@formicoidea/labre-framework-ddd-core-domain 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.
@@ -7,5 +7,10 @@ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
7
7
  export declare class CoreDomainView extends GfxElementModelView<CoreDomainChartElementModel> {
8
8
  static type: string;
9
9
  }
10
- /** Resize gating: handles hidden unless `model.resizeEnabled` (toolbar toggle). */
10
+ /**
11
+ * Resize gating, driven by the declaration: the handles are offered while
12
+ * `model.resizeEnabled` says so (the toolbar toggle), and an element carrying no
13
+ * such prop falls back to `geometry.resizable` — the same behaviour the
14
+ * hand-written extension had, minus the hand.
15
+ */
11
16
  export declare const CoreDomainInteraction: import("@formicoidea/labre-core/store").ExtensionType;
@@ -1,4 +1,6 @@
1
- import { GfxElementModelView, GfxViewInteractionExtension, } from '@formicoidea/labre-core/std/gfx';
1
+ import { FrameworkBackgroundInteractionExtension } from '@formicoidea/labre-core/blocks/surface';
2
+ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
3
+ import { CORE_DOMAIN_BACKGROUND } from './background.js';
2
4
  /**
3
5
  * View for the Core Domain Chart background. Registering it ensures
4
6
  * `gfx.view.get(model)` returns a view (required so move / select work).
@@ -6,15 +8,10 @@ import { GfxElementModelView, GfxViewInteractionExtension, } from '@formicoidea/
6
8
  export class CoreDomainView extends GfxElementModelView {
7
9
  static { this.type = 'coreDomain'; }
8
10
  }
9
- /** Resize gating: handles hidden unless `model.resizeEnabled` (toolbar toggle). */
10
- export const CoreDomainInteraction = GfxViewInteractionExtension(CoreDomainView.type, {
11
- handleResize({ model }) {
12
- return {
13
- beforeResize({ set }) {
14
- if (!model.resizeEnabled) {
15
- set({ allowedHandlers: [] });
16
- }
17
- },
18
- };
19
- },
20
- });
11
+ /**
12
+ * Resize gating, driven by the declaration: the handles are offered while
13
+ * `model.resizeEnabled` says so (the toolbar toggle), and an element carrying no
14
+ * such prop falls back to `geometry.resizable` — the same behaviour the
15
+ * hand-written extension had, minus the hand.
16
+ */
17
+ export const CoreDomainInteraction = FrameworkBackgroundInteractionExtension(CORE_DOMAIN_BACKGROUND);
@@ -1,18 +1,29 @@
1
- import { type LegendSection } from '@formicoidea/labre-ddd-shared';
2
- import { type CoreDomainChartElementModel } from '@formicoidea/labre-core/model';
3
- import type { BlockStdScope } from '@formicoidea/labre-core/std';
1
+ import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
4
2
  /**
5
- * Build the Notation legend sections. When `present` is given (a content-aware
6
- * scan of the background), only the sub-domain types / team-topology modes /
7
- * movement actually used are listed; otherwise the full notation is shown.
3
+ * What the Core Domain Chart'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 draws its dots with
7
+ * ({@link CD_SUBDOMAINS}) and from the role vocabulary's own labels, never
8
+ * restated — which also keeps this table and `core-domain.off-legend-colour`
9
+ * naming the same five colours by construction.
10
+ *
11
+ * ## What changed
12
+ *
13
+ * The chart's legend button predates roles: until now it scanned the perimeter
14
+ * for FILL COLOURS, which is why it fell back to the full notation when it
15
+ * recognised nothing. Detection is now by role, like every other reader of the
16
+ * board, with one consequence worth stating: a chart on which nothing is
17
+ * recognised yields a legend box with a title and no rows, rather than the whole
18
+ * notation. That is Wardley's behaviour and the honest one — a legend lists what
19
+ * is drawn, not what could have been.
20
+ *
21
+ * The **Team Topologies markers** were the casualty of that change for one
22
+ * release: `addMarker` stamped no role, so a chart covered in them produced a
23
+ * legend that mentioned none (PO recette, 26/08/2026). They now carry
24
+ * `core-domain:marker-*` and their section is here, derived from
25
+ * `TEAM_TOPOLOGIES` like everything else — swatch, letter and colour from the
26
+ * preset the palette draws with, wording from the vocabulary that names the
27
+ * role.
8
28
  */
9
- export declare function coreDomainLegendSections(present?: {
10
- fills: Set<string>;
11
- movement: boolean;
12
- }): LegendSection[];
13
- /**
14
- * Insert a content-aware legend next to a Core Domain background: scans the
15
- * shapes/connectors inside the background's perimeter and lists only the
16
- * notation actually present. Triggered from the element's contextual toolbar.
17
- */
18
- export declare function createCoreDomainLegend(std: BlockStdScope, bg: CoreDomainChartElementModel): void;
29
+ export declare const CORE_DOMAIN_AUTO_LEGEND: AutoLegendSpec;
@@ -1,68 +1,78 @@
1
- import { addLegend, CD_SUBDOMAINS, MOVEMENT_COLOR, TEAM_TOPOLOGIES, } from '@formicoidea/labre-ddd-shared';
2
- import { ConnectorElementModel, ShapeElementModel, StrokeStyle, } from '@formicoidea/labre-core/model';
3
- import { Bound } from '@formicoidea/labre-core/global/gfx';
4
- import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
1
+ import { CD_SUBDOMAINS, MOVEMENT_COLOR, roleLabel, TEAM_TOPOLOGIES, } from '@formicoidea/labre-ddd-shared';
2
+ import { CORE_DOMAIN_ROLE, CORE_DOMAIN_ROLES } from '../roles.js';
5
3
  /**
6
- * Build the Notation legend sections. When `present` is given (a content-aware
7
- * scan of the background), only the sub-domain types / team-topology modes /
8
- * movement actually used are listed; otherwise the full notation is shown.
4
+ * What the Core Domain Chart'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 draws its dots with
8
+ * ({@link CD_SUBDOMAINS}) and from the role vocabulary's own labels, never
9
+ * restated — which also keeps this table and `core-domain.off-legend-colour`
10
+ * naming the same five colours by construction.
11
+ *
12
+ * ## What changed
13
+ *
14
+ * The chart's legend button predates roles: until now it scanned the perimeter
15
+ * for FILL COLOURS, which is why it fell back to the full notation when it
16
+ * recognised nothing. Detection is now by role, like every other reader of the
17
+ * board, with one consequence worth stating: a chart on which nothing is
18
+ * recognised yields a legend box with a title and no rows, rather than the whole
19
+ * notation. That is Wardley's behaviour and the honest one — a legend lists what
20
+ * is drawn, not what could have been.
21
+ *
22
+ * The **Team Topologies markers** were the casualty of that change for one
23
+ * release: `addMarker` stamped no role, so a chart covered in them produced a
24
+ * legend that mentioned none (PO recette, 26/08/2026). They now carry
25
+ * `core-domain:marker-*` and their section is here, derived from
26
+ * `TEAM_TOPOLOGIES` like everything else — swatch, letter and colour from the
27
+ * preset the palette draws with, wording from the vocabulary that names the
28
+ * role.
9
29
  */
10
- export function coreDomainLegendSections(present) {
11
- const has = (c) => !present || present.fills.has(c.toLowerCase());
12
- const subRows = CD_SUBDOMAINS.filter(s => has(s.fill)).map(s => ({
13
- swatch: 'dot',
14
- color: s.fill,
15
- label: s.label,
16
- }));
17
- const ttRows = TEAM_TOPOLOGIES.filter(t => has(t.fill)).map(t => ({
18
- swatch: 'square',
19
- color: t.fill,
20
- letter: t.letter,
21
- label: t.label,
22
- }));
23
- const sections = [];
24
- if (subRows.length)
25
- sections.push({ title: 'Sub-domains', rows: subRows });
26
- if (ttRows.length)
27
- sections.push({ title: 'Team topologies', rows: ttRows });
28
- if (!present || present.movement) {
29
- sections.push({
30
+ export const CORE_DOMAIN_AUTO_LEGEND = {
31
+ title: 'Legend',
32
+ roles: CORE_DOMAIN_ROLES,
33
+ sections: [
34
+ {
35
+ title: 'Sub-domains',
36
+ entries: CD_SUBDOMAINS.map(preset => ({
37
+ role: CORE_DOMAIN_ROLE[preset.kind],
38
+ row: {
39
+ swatch: 'dot',
40
+ color: preset.fill,
41
+ label: preset.label,
42
+ },
43
+ })),
44
+ },
45
+ {
46
+ // The letter is what identifies a marker on the chart — the squares are
47
+ // three colours a reader has no key to — so the legend shows the same
48
+ // square with the same letter in it, which is what `LegendRow.letter`
49
+ // exists for.
50
+ title: 'Team interaction modes',
51
+ entries: TEAM_TOPOLOGIES.map(preset => ({
52
+ role: CORE_DOMAIN_ROLE[preset.kind],
53
+ row: {
54
+ swatch: 'square',
55
+ color: preset.fill,
56
+ letter: preset.letter,
57
+ label: roleLabel(CORE_DOMAIN_ROLES, CORE_DOMAIN_ROLE[preset.kind]),
58
+ },
59
+ })),
60
+ },
61
+ {
30
62
  title: 'Movement',
31
- rows: [{ swatch: 'line', color: MOVEMENT_COLOR, label: 'Movement over time' }],
32
- });
33
- }
34
- // Content-aware scan found nothing recognizable → fall back to the full legend.
35
- if (present && sections.length === 0)
36
- return coreDomainLegendSections();
37
- return sections;
38
- }
39
- /**
40
- * Insert a content-aware legend next to a Core Domain background: scans the
41
- * shapes/connectors inside the background's perimeter and lists only the
42
- * notation actually present. Triggered from the element's contextual toolbar.
43
- */
44
- export function createCoreDomainLegend(std, bg) {
45
- const gfx = std.get(GfxControllerIdentifier);
46
- const surface = gfx.surface;
47
- if (!surface)
48
- return;
49
- const fills = new Set();
50
- let movement = false;
51
- for (const el of gfx.getElementsByBound(Bound.deserialize(bg.xywh), {
52
- type: 'canvas',
53
- })) {
54
- if (el instanceof ConnectorElementModel) {
55
- if (el.strokeStyle === StrokeStyle.Dash)
56
- movement = true;
57
- }
58
- else if (el instanceof ShapeElementModel) {
59
- if (typeof el.fillColor === 'string')
60
- fills.add(el.fillColor.toLowerCase());
61
- }
62
- }
63
- const [bx, by, bw] = bg.deserializedXYWH;
64
- addLegend(surface, std, bx + bw + 30, by, {
65
- title: 'Légende',
66
- sections: coreDomainLegendSections({ fills, movement }),
67
- });
68
- }
63
+ entries: [
64
+ {
65
+ role: CORE_DOMAIN_ROLE.movement,
66
+ row: {
67
+ swatch: 'line',
68
+ // The style `activateMovement` arms the connector tool with: a red
69
+ // dashed line.
70
+ color: MOVEMENT_COLOR,
71
+ dashed: true,
72
+ label: roleLabel(CORE_DOMAIN_ROLES, CORE_DOMAIN_ROLE.movement),
73
+ },
74
+ },
75
+ ],
76
+ },
77
+ ],
78
+ };
@@ -1,33 +1,27 @@
1
+ import { createAutoLegend, dddLegendIcon } from '@formicoidea/labre-ddd-shared';
1
2
  import { CoreDomainChartElementModel } from '@formicoidea/labre-core/model';
2
3
  import { TelemetryProvider, ToolbarModuleExtension, } from '@formicoidea/labre-core/shared/services';
3
4
  import { BlockFlavourIdentifier } from '@formicoidea/labre-core/std';
4
- import { html } from 'lit';
5
- import { createCoreDomainLegend } from './legend.js';
6
- const legendIcon = html `<svg
7
- width="24"
8
- height="24"
9
- viewBox="0 0 24 24"
10
- fill="none"
11
- xmlns="http://www.w3.org/2000/svg"
12
- >
13
- <rect x="3" y="4" width="18" height="16" rx="2" stroke="currentColor" stroke-width="1.6" />
14
- <circle cx="7" cy="9" r="1.6" fill="currentColor" />
15
- <circle cx="7" cy="14" r="1.6" fill="currentColor" />
16
- <path d="M11 9 H18 M11 14 H18" stroke="currentColor" stroke-width="1.4" />
17
- </svg>`;
5
+ import { CORE_DOMAIN_AUTO_LEGEND } from './legend.js';
18
6
  /** Contextual toolbar for a selected Core Domain background: insert its legend. */
19
7
  const coreDomainToolbarConfig = {
20
8
  actions: [
21
9
  {
22
10
  id: 'a.legend',
23
- tooltip: 'Insert legend (notation present in the chart)',
24
- icon: legendIcon,
11
+ tooltip: 'Generate the legend (notation present)',
12
+ icon: dddLegendIcon,
25
13
  run(ctx) {
26
14
  const bg = ctx.getSurfaceModelsByType(CoreDomainChartElementModel)[0];
27
15
  if (!bg)
28
16
  return;
29
- createCoreDomainLegend(ctx.std, bg);
30
- ctx.std.getOptional(TelemetryProvider)?.track('FrameworkLegendCreated', {
17
+ createAutoLegend(ctx.std, bg, CORE_DOMAIN_AUTO_LEGEND);
18
+ ctx.std
19
+ .getOptional(TelemetryProvider)
20
+ ?.track('FrameworkLegendCreated', {
21
+ // The WIRE value, which is not the module id: the framework is
22
+ // `ddd-core-domain` in code and `core-domain` in PostHog
23
+ // (`frameworks.ts` `telemetryKey`). Unchanged by this rework — the
24
+ // button is the same gesture, it just detects by role now.
31
25
  framework: 'core-domain',
32
26
  element: 'legend',
33
27
  page: 'whiteboard editor',
@@ -1,7 +1,8 @@
1
1
  import { DddCoreDomainRenderViewExtension, DddCoreDomainViewExtension } from './view.js';
2
2
  /** Host wiring for the ddd-core-domain framework. */
3
3
  export declare const dddCoreDomainFramework: {
4
- readonly telemetry: "ddd-core-domain";
4
+ readonly flag: "ddd-core-domain";
5
+ readonly telemetryKey: "core-domain";
5
6
  readonly extensions: readonly [{
6
7
  readonly viewExtension: typeof DddCoreDomainRenderViewExtension;
7
8
  }, {
@@ -1,7 +1,8 @@
1
1
  import { DddCoreDomainRenderViewExtension, DddCoreDomainViewExtension } from './view.js';
2
2
  /** Host wiring for the ddd-core-domain framework. */
3
3
  export const dddCoreDomainFramework = {
4
- telemetry: 'ddd-core-domain',
4
+ flag: 'ddd-core-domain',
5
+ telemetryKey: 'core-domain',
5
6
  extensions: [
6
7
  { viewExtension: DddCoreDomainRenderViewExtension },
7
8
  { flag: 'ddd-core-domain', viewExtension: DddCoreDomainViewExtension },
package/dist/index.d.ts CHANGED
@@ -1,4 +1,12 @@
1
+ export { activateMovement, createCoreDomainChart } from './actions.js';
2
+ export { coreDomainCommandIcons, coreDomainCommands } from './commands.js';
3
+ export { coreDomainTranslationEntries } from './translations.js';
4
+ export { CORE_DOMAIN_BACKGROUND, CORE_DOMAIN_LEGEND_TONES, } from './core-domain/background.js';
1
5
  export { coreDomain } from './core-domain/element-renderer.js';
6
+ export { CORE_DOMAIN_NUDGES } from './nudges.js';
7
+ export { CORE_DOMAIN_PROFILES } from './profiles.js';
8
+ export { CORE_DOMAIN_ROLE, CORE_DOMAIN_ROLES, type CoreDomainRole, type CoreDomainRoleId, subdomainRole, } from './roles.js';
9
+ export { CORE_DOMAIN_RULES } from './rules.js';
2
10
  export { coreDomainTemplateCategory } from './templates.js';
3
11
  export { coreDomainSeniorTool } from './toolbar/senior-tool.js';
4
12
  export { EdgelessDddCoreDomainSeniorButton } from './toolbar/senior-button.js';
package/dist/index.js CHANGED
@@ -1,4 +1,12 @@
1
+ export { activateMovement, createCoreDomainChart } from './actions.js';
2
+ export { coreDomainCommandIcons, coreDomainCommands } from './commands.js';
3
+ export { coreDomainTranslationEntries } from './translations.js';
4
+ export { CORE_DOMAIN_BACKGROUND, CORE_DOMAIN_LEGEND_TONES, } from './core-domain/background.js';
1
5
  export { coreDomain } from './core-domain/element-renderer.js';
6
+ export { CORE_DOMAIN_NUDGES } from './nudges.js';
7
+ export { CORE_DOMAIN_PROFILES } from './profiles.js';
8
+ export { CORE_DOMAIN_ROLE, CORE_DOMAIN_ROLES, subdomainRole, } from './roles.js';
9
+ export { CORE_DOMAIN_RULES } from './rules.js';
2
10
  export { coreDomainTemplateCategory } from './templates.js';
3
11
  export { coreDomainSeniorTool } from './toolbar/senior-tool.js';
4
12
  export { EdgelessDddCoreDomainSeniorButton } from './toolbar/senior-button.js';
@@ -0,0 +1,21 @@
1
+ import type { QualityNudge } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * Core Domain Chart **work quality** — the checklist.
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
+ * All three below are about whether the chart can be DISCUSSED, and no
12
+ * algorithm can check a single one of them. Whether a movement is justified is
13
+ * a statement about an argument; whether the core was agreed is a statement
14
+ * about a room. A rule claiming to have verified either would be lying.
15
+ *
16
+ * Registered from the flag-gated `DddCoreDomainViewExtension`, beside the rules
17
+ * and the profiles: a checklist is tooling. Switching the flag off takes it away
18
+ * and leaves the ticks written on the chart, unread, until it comes back
19
+ * (PF7.10).
20
+ */
21
+ export declare const CORE_DOMAIN_NUDGES: readonly QualityNudge[];
package/dist/nudges.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Core Domain Chart **work quality** — the checklist.
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
+ * All three below are about whether the chart can be DISCUSSED, and no
11
+ * algorithm can check a single one of them. Whether a movement is justified is
12
+ * a statement about an argument; whether the core was agreed is a statement
13
+ * about a room. A rule claiming to have verified either would be lying.
14
+ *
15
+ * Registered from the flag-gated `DddCoreDomainViewExtension`, beside the rules
16
+ * and the profiles: a checklist is tooling. Switching the flag off takes it away
17
+ * and leaves the ticks written on the chart, unread, until it comes back
18
+ * (PF7.10).
19
+ */
20
+ export const CORE_DOMAIN_NUDGES = [
21
+ {
22
+ id: 'core-domain.q1-legend',
23
+ framework: 'core-domain',
24
+ labelKey: 'com.labre.core-domain.quality.legend',
25
+ fallback: 'The chart has a legend.',
26
+ order: 1,
27
+ },
28
+ {
29
+ id: 'core-domain.q2-movements',
30
+ framework: 'core-domain',
31
+ labelKey: 'com.labre.core-domain.quality.movements',
32
+ fallback: 'Movements are dated and justified.',
33
+ order: 2,
34
+ },
35
+ {
36
+ id: 'core-domain.q3-core-agreed',
37
+ framework: 'core-domain',
38
+ labelKey: 'com.labre.core-domain.quality.core-agreed',
39
+ fallback: 'The core has been agreed by the team.',
40
+ order: 3,
41
+ },
42
+ ];
@@ -0,0 +1,2 @@
1
+ import type { ValidationProfile } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare const CORE_DOMAIN_PROFILES: readonly ValidationProfile[];
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Core Domain Chart 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 this framework has.
6
+ *
7
+ * A profile is chosen per CHART, not per document (PF9.1) — a rough sketch and
8
+ * a chart that goes in front of a steering committee coexist on the same canvas
9
+ * with different requirements, and the choice rides on the background element
10
+ * itself.
11
+ *
12
+ * Registered from the flag-gated `DddCoreDomainViewExtension`, beside the
13
+ * rules: switching the flag off takes the choice away with the rest of the
14
+ * tooling, and a chart already set to `strict` simply stops being checked until
15
+ * it comes back — the id stays written, untouched.
16
+ */
17
+ /**
18
+ * Sketch: every rule demoted to `audit`, so findings still reach `violations$`
19
+ * — a host panel and a conformance report see them — and the canvas says
20
+ * nothing at all.
21
+ *
22
+ * The DEFAULT, and deliberately so: the sketch wins (PRD principle 3). A Core
23
+ * Domain Chart is drawn in a workshop, in front of people, by dragging dots
24
+ * around until the room agrees; a tool badging a dot that has been in the core
25
+ * for eleven seconds is a tool the room switches off. Being the default also
26
+ * means it is the one profile that WRITES NOTHING: a chart on `sketch` carries
27
+ * no profile key, so every chart ever drawn is on it, with no migration and no
28
+ * backfill.
29
+ */
30
+ const sketch = {
31
+ id: 'core-domain.sketch',
32
+ framework: 'core-domain',
33
+ labelKey: 'com.labre.core-domain.profile.sketch',
34
+ fallback: 'Sketch',
35
+ isDefault: true,
36
+ rules: {
37
+ 'core-domain.outsourced-core': 'audit',
38
+ 'core-domain.malformed-movement': 'audit',
39
+ 'core-domain.overlapping-artefacts': 'audit',
40
+ 'core-domain.off-legend-colour': 'audit',
41
+ },
42
+ };
43
+ /**
44
+ * Strict: the deliverable level. Every severity a user gets is spelled out here
45
+ * rather than left absent — PF9.4 wants the answer readable in one place.
46
+ *
47
+ * C4 stays `audit` even here, and that is the one deliberate asymmetry: the
48
+ * colour of a dot is a NOTATION question, answered when the chart is read back
49
+ * rather than while it is drawn, and the honest place for it is the conformance
50
+ * report the audit level already feeds. Promoting it would put a badge on a dot
51
+ * whose only sin is a shade.
52
+ */
53
+ const strict = {
54
+ id: 'core-domain.strict',
55
+ framework: 'core-domain',
56
+ labelKey: 'com.labre.core-domain.profile.strict',
57
+ fallback: 'Strict',
58
+ rules: {
59
+ 'core-domain.outsourced-core': 'warning',
60
+ 'core-domain.malformed-movement': 'warning',
61
+ 'core-domain.overlapping-artefacts': 'warning',
62
+ 'core-domain.off-legend-colour': 'audit',
63
+ },
64
+ };
65
+ export const CORE_DOMAIN_PROFILES = [
66
+ sketch,
67
+ strict,
68
+ ];
@@ -0,0 +1,66 @@
1
+ import { CD_SUBDOMAINS, TEAM_TOPOLOGIES } from '@formicoidea/labre-ddd-shared';
2
+ import type { RoleDefs, RoleId } from '@formicoidea/labre-core/std/gfx';
3
+ /**
4
+ * The five dot presets' own `kind`, read off the shared table rather than
5
+ * restated: a preset added there without a role here is a compile error.
6
+ */
7
+ export type CdSubdomainKind = (typeof CD_SUBDOMAINS)[number]['kind'];
8
+ /** The three Team Topologies marker kinds, read off their table the same way. */
9
+ export type CdMarkerKind = (typeof TEAM_TOPOLOGIES)[number]['kind'];
10
+ /**
11
+ * Core Domain Chart role vocabulary.
12
+ *
13
+ * Roles are the semantic identity of a chart artefact — no rule will ever look
14
+ * at a shape type. They mirror the presets the user already picks in the
15
+ * sub-menu — the five dots ({@link CD_SUBDOMAINS}) and the three Team
16
+ * Topologies markers ({@link TEAM_TOPOLOGIES}) — plus the chart itself and the
17
+ * typed MOVEMENT edge.
18
+ *
19
+ * Hierarchy is DATA (`parent`), never TS inheritance: the five dots specialise
20
+ * `core-domain:subdomain`, so a rule written on the parent covers all five for
21
+ * free (see `roleIsA`), and a rule written on `-outsourced` touches that one
22
+ * alone. The three markers form a SECOND family under `core-domain:marker`,
23
+ * deliberately disjoint from the first: they annotate the chart, they are not
24
+ * plotted on it, and no rule written on sub-domains must ever fall on one.
25
+ *
26
+ * ## No backfill, ever
27
+ *
28
+ * These values are written by the creation sites from today on. A chart drawn
29
+ * before they existed carries dots with no role at all, and an element with no
30
+ * role is never evaluated (proportionality, PRD principle 8) — so an old
31
+ * document opens exactly as it always did and raises nothing. Same promise every
32
+ * other framework's vocabulary made (#71).
33
+ *
34
+ * The vocabulary is registered from the ALWAYS-ON render extension
35
+ * (`docs/adr/0009`): a role is written in the document, not in the tooling, and
36
+ * what reads it back — the direction reveal of a typed edge, the inversion
37
+ * command — has to keep working on a chart drawn while the flag was on and
38
+ * opened while it is off.
39
+ */
40
+ /** Every role this framework declares. */
41
+ export type CoreDomainRole = 'chart' | 'subdomain' | 'subdomain-big-bet' | 'subdomain-platform' | 'subdomain-outsourced' | 'bc-current' | 'bc-future' | 'marker' | 'marker-collaboration' | 'marker-xaas' | 'marker-facilitating' | 'movement';
42
+ export type CoreDomainRoleId = `core-domain:${CoreDomainRole}`;
43
+ /**
44
+ * Role ids, keyed by the `kind` the creation sites use — camelCased, exactly
45
+ * like `CD_SUBDOMAINS[].kind`, so `commands.ts` can hand a preset's own kind
46
+ * straight to this table.
47
+ */
48
+ export declare const CORE_DOMAIN_ROLE: {
49
+ readonly chart: "core-domain:chart";
50
+ readonly subdomain: "core-domain:subdomain";
51
+ readonly bigBet: "core-domain:subdomain-big-bet";
52
+ readonly platform: "core-domain:subdomain-platform";
53
+ readonly outsourced: "core-domain:subdomain-outsourced";
54
+ readonly bcCurrent: "core-domain:bc-current";
55
+ readonly bcFuture: "core-domain:bc-future";
56
+ readonly marker: "core-domain:marker";
57
+ readonly collaboration: "core-domain:marker-collaboration";
58
+ readonly xaas: "core-domain:marker-xaas";
59
+ readonly facilitating: "core-domain:marker-facilitating";
60
+ readonly movement: "core-domain:movement";
61
+ };
62
+ /** The role of one of the five dot presets. */
63
+ export declare function subdomainRole(kind: CdSubdomainKind): RoleId;
64
+ /** The role of one of the three Team Topologies markers. */
65
+ export declare function markerRole(kind: CdMarkerKind): RoleId;
66
+ export declare const CORE_DOMAIN_ROLES: RoleDefs;