dsh-logicprobe 0.9.0 → 1.1.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 (63) hide show
  1. package/README.en-US.md +128 -66
  2. package/README.md +128 -66
  3. package/lib/baseline.js +142 -0
  4. package/lib/client.js +56 -1
  5. package/lib/compose-tool.js +1 -1
  6. package/lib/concurrency.js +14 -0
  7. package/lib/data-engine.js +42 -8
  8. package/lib/engine.js +3151 -2801
  9. package/lib/export-tool.js +27 -2
  10. package/lib/granularity.js +237 -0
  11. package/lib/index.js +63 -41
  12. package/lib/report-diff-tool.js +39 -0
  13. package/lib/structure-tool.js +64 -0
  14. package/lib/structure.js +648 -0
  15. package/lib/tool.js +3 -3
  16. package/lib/types/baseline.d.ts +69 -0
  17. package/lib/types/concurrency.d.ts +10 -0
  18. package/lib/types/data-engine.d.ts +13 -1
  19. package/lib/types/engine.d.ts +419 -277
  20. package/lib/types/granularity.d.ts +106 -0
  21. package/lib/types/index.d.ts +9 -8
  22. package/lib/types/report-diff-tool.d.ts +8 -0
  23. package/lib/types/structure-tool.d.ts +10 -0
  24. package/lib/types/structure.d.ts +156 -0
  25. package/lib/types/tool.d.ts +2 -2
  26. package/lib/types/uml.d.ts +89 -0
  27. package/lib/uml-tool.js +146 -104
  28. package/lib/uml.js +1748 -1544
  29. package/locale/en.json +6 -0
  30. package/locale/zh.json +6 -0
  31. package/package.json +16 -14
  32. package/skills/logicprobe/SKILL.md +84 -58
  33. package/skills/logicprobe/references/dsh-model-schema.md +102 -10
  34. package/skills/logicprobe/references/gap-routing-guide.md +37 -36
  35. package/skills/logicprobe/references/hash-spec.md +153 -0
  36. package/skills/logicprobe/references/logic-verification-guide.md +27 -250
  37. package/skills/logicprobe-concurrency/SKILL.md +43 -0
  38. package/skills/{logicprobe → logicprobe-concurrency}/references/concurrency-risk-guide.md +1 -1
  39. package/skills/logicprobe-datamodel/SKILL.md +5 -4
  40. package/skills/logicprobe-datamodel/references/data-model-guide.md +1 -1
  41. package/skills/logicprobe-datamodel/references/data-model-schema.md +1 -1
  42. package/skills/logicprobe-structure/SKILL.md +95 -0
  43. package/skills/logicprobe-structure/references/structure-review-guide.md +177 -0
  44. package/skills/logicprobe-uml/SKILL.md +57 -0
  45. package/skills/{logicprobe → logicprobe-uml}/references/uml-modeling-guide.md +121 -8
  46. package/src/baseline.ts +180 -0
  47. package/src/client.js +56 -1
  48. package/src/compose-tool.ts +47 -47
  49. package/src/concurrency.ts +23 -0
  50. package/src/data-engine.ts +51 -9
  51. package/src/engine.ts +503 -72
  52. package/src/export-tool.ts +73 -48
  53. package/src/granularity.ts +312 -0
  54. package/src/index.ts +63 -41
  55. package/src/report-diff-tool.ts +43 -0
  56. package/src/structure-tool.ts +68 -0
  57. package/src/structure.ts +724 -0
  58. package/src/tool.ts +3 -3
  59. package/src/uml-tool.ts +53 -10
  60. package/src/uml.ts +288 -24
  61. package/skills/logicprobe/references/logicprobe-engine.py +0 -4943
  62. package/skills/logicprobe/references/verification-harness.py +0 -959
  63. package/skills/logicprobe-datamodel/references/data-model-harness.py +0 -528
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Multi-granularity structure review: one architecture, several levels of detail.
3
+ *
4
+ * A module diagram and the repository-wide diagram it belongs to are two views of one
5
+ * fact, and nothing keeps them in step — the child grows a dependency the parent never
6
+ * had, or the parent keeps an arrow the child quietly stopped drawing. This module
7
+ * checks that a child diagram is a **refinement** of its declared parent:
8
+ *
9
+ * - every dependency the child draws between two nodes the parent also has must exist in
10
+ * the parent (nothing appears out of nowhere);
11
+ * - an edge the parent draws and the child does not must be *expanded* in the child, i.e.
12
+ * a child path must connect the same two ends;
13
+ * - the declared parent relation must be a forest, not a cycle.
14
+ *
15
+ * Every per-diagram structural check still runs, and its findings are tagged with the
16
+ * diagram they came from (`file`), so one report can carry several diagrams without the
17
+ * findings becoming anonymous.
18
+ *
19
+ * @module logicprobe-granularity
20
+ */
21
+ import { type Finding, type ReportSchema, type Verdict, type VerdictSummary } from './engine.js';
22
+ import { type StructureNotation } from './structure.js';
23
+ export interface GranularityDiagram {
24
+ /** Name of this level, e.g. `L2/motion` or `repo`. Referenced by a child's `parent`. */
25
+ name: string;
26
+ /** Diagram source text. */
27
+ diagram: string;
28
+ /** Name of the diagram this one refines; absent for a root. */
29
+ parent?: string;
30
+ }
31
+ export interface GranularityOptions {
32
+ diagrams: GranularityDiagram[];
33
+ notation?: 'auto' | StructureNotation;
34
+ /** Optional dependency matrix, applied to every diagram. */
35
+ matrix?: unknown;
36
+ }
37
+ export interface GranularityEdgeRef {
38
+ from: string;
39
+ to: string;
40
+ line?: number;
41
+ }
42
+ export interface GranularityPairSummary {
43
+ parent: string;
44
+ child: string;
45
+ parentNodes: number;
46
+ childNodes: number;
47
+ parentEdges: number;
48
+ childEdges: number;
49
+ /** Child edges whose endpoints both exist in the parent and which the parent also draws. */
50
+ inheritedEdges: number;
51
+ /** Child edges with at least one endpoint the parent does not have (the refinement's own detail). */
52
+ newEdges: number;
53
+ /** Parent edges with no direct child counterpart, but a child path connects the same ends. */
54
+ expandedEdges: GranularityEdgeRef[];
55
+ /** Parent edges with no direct counterpart and no connecting path — the refinement lost them. */
56
+ missingEdges: GranularityEdgeRef[];
57
+ /** Child edges between two parent nodes that the parent does not draw — invented dependencies. */
58
+ inventedEdges: GranularityEdgeRef[];
59
+ }
60
+ export interface GranularityDiagramSummary {
61
+ name: string;
62
+ parent?: string;
63
+ notation: StructureNotation;
64
+ nodes: number;
65
+ edges: number;
66
+ verdict: Verdict;
67
+ findings: number;
68
+ }
69
+ export interface GranularityReport {
70
+ ok: boolean;
71
+ ran: boolean;
72
+ verdict: Verdict;
73
+ verdictReason: string;
74
+ schema: ReportSchema;
75
+ diagrams: GranularityDiagramSummary[];
76
+ pairs: GranularityPairSummary[];
77
+ findings: Finding[];
78
+ summary: {
79
+ diagrams: number;
80
+ roots: number;
81
+ pairs: number;
82
+ nodes: number;
83
+ edges: number;
84
+ inventedEdges: number;
85
+ missingEdges: number;
86
+ expandedEdges: number;
87
+ errors: number;
88
+ warnings: number;
89
+ };
90
+ hashes: {
91
+ diagrams: Array<{
92
+ name: string;
93
+ hash: string;
94
+ }>;
95
+ };
96
+ warnings: string[];
97
+ nextSteps: string[];
98
+ }
99
+ /**
100
+ * Review a set of structure diagrams with declared parent relations. Per-diagram
101
+ * structural checks run first; the cross-diagram refinement checks follow.
102
+ */
103
+ export declare function reviewGranularity(options: GranularityOptions): GranularityReport;
104
+ /** Deterministic JSON of a granularity report's pair table, for a stable summary line. */
105
+ export declare function granularityDigest(pairs: GranularityPairSummary[]): string;
106
+ export type { VerdictSummary };
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * logicprobe — DeepSeek Harness native plugin for the Logic Probe toolbox.
3
- * Injects the session-start gate text (claim-verification doctrine, 1% Rule,
4
- * Red Flags, proactive suggestion) into the first model step of every agent
5
- * session, mirroring the SessionStart hook the Claude Code plugin installs.
3
+ * Injects the session-start gate text (what this plugin checks, the 1% Rule,
4
+ * the Red Flags, the routing to the skills, the tool list, how to read a report)
5
+ * into the first model step of every agent session, mirroring the SessionStart
6
+ * hook the Claude Code plugin installs.
6
7
  * The skill ships in this package's `skills/` directory and is registered at
7
8
  * apply time into dsh's `ctx.skills` registry through the standard filesystem
8
9
  * provider, so it appears in every session catalog without a manual copy step.
@@ -16,11 +17,11 @@
16
17
  * reminders (skill catalog, AGENTS.md, gate plugins) simply defer this message
17
18
  * to the first step after their promotion, and the history guard re-injects it
18
19
  * there. The default gate text is the dsh-native adaptation of
19
- * `hooks/session-start-content.md`: behavior rules
20
- * (1% Rule / Red Flags / proactive suggestion) stay in sync, while
21
- * presentation is adapted to dsh's native skill catalog — the trigger list
22
- * lives in the skill description, not duplicated in the gate. Deployments
23
- * override via Config.
20
+ * `hooks/session-start-content.md`. Both are a guide to calling the tools: what
21
+ * this plugin checks, the 1% Rule and the Red Flags that raise the chance of a
22
+ * call, the routing to the five skills, the tool list, and how to read a report.
23
+ * They stay in sync. Method, doctrine and per-domain detail live in the skills
24
+ * and their references, not here. Deployments override via Config.
24
25
  *
25
26
  * @module logicprobe-dsh
26
27
  */
@@ -0,0 +1,8 @@
1
+ export declare const LOGICPROBE_REPORT_DIFF_TOOL_NAME = "logicprobe_report_diff";
2
+ /**
3
+ * Model-visible DSH tool that compares two reports of the same family — the accepted
4
+ * "violations must not increase" acceptance criterion, computed instead of eyeballed.
5
+ * A finding's identity is its check + code + machine-readable locator, so a reworded
6
+ * message reads as `changed`, and two runs over the same input add nothing.
7
+ */
8
+ export declare const logicProbeReportDiffTool: import("@deepseek-ai/dsh-tools").ToolDefinition;
@@ -0,0 +1,10 @@
1
+ export declare const LOGICPROBE_STRUCTURE_TOOL_NAME = "logicprobe_structure_verify";
2
+ /**
3
+ * Model-visible DSH tool that audits a *structure* diagram — components, packages,
4
+ * classes, deployment nodes and the dependency arrows between them — against an
5
+ * optional dependency matrix. A structure diagram is not a state machine: this tool
6
+ * reads the graph the diagram actually draws, instead of refusing it (which is what
7
+ * `logicprobe_uml action=parse` does) or pretending the arrows are state transitions
8
+ * (which is what a false `ok` used to hide).
9
+ */
10
+ export declare const logicProbeStructureTool: import("@deepseek-ai/dsh-tools").ToolDefinition;
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Structure-diagram review: a dependency graph is not a state machine.
3
+ *
4
+ * The state-machine front end (`uml.ts`) reads a component, package, class or
5
+ * deployment diagram as a *by-product* and says so (`UML_NOT_A_STATE_DIAGRAM`).
6
+ * This module reads the same text as what it actually is — a directed graph of
7
+ * nodes and dependency edges — and audits it against a declared dependency matrix.
8
+ *
9
+ * The checks are the structural ones a reader performs by eye and gets wrong:
10
+ * an isolated node nobody notices, an arrow whose endpoint was never declared, a
11
+ * dependency cycle, an edge that violates the allowed-dependency matrix, a child
12
+ * depending on its parent, and an edge the matrix says must exist but the diagram
13
+ * does not draw. Every finding names the rule id it hit, so the diagram and the
14
+ * source-side checker can be reconciled rule by rule.
15
+ *
16
+ * @module logicprobe-structure
17
+ */
18
+ import { type Finding, type ReportSchema, type Verdict, type VerdictSummary } from './engine.js';
19
+ export type StructureNotation = 'plantuml' | 'mermaid';
20
+ /** What a node declares itself to be. Containers hold other nodes; they are not dependencies. */
21
+ export type StructureNodeKind = 'component' | 'class' | 'interface' | 'actor' | 'database' | 'node' | 'package' | 'rectangle' | 'cloud' | 'queue' | 'unknown';
22
+ export interface StructureNode {
23
+ id: string;
24
+ /** Display label when the declaration carried one (`component "Order Service" as SVC`). */
25
+ label?: string;
26
+ kind: StructureNodeKind;
27
+ /** True when the node is a container (package/rectangle/frame): it owns members and carries no dependency of its own. */
28
+ container: boolean;
29
+ /** 1-based line of the declaration. Absent when the node was only ever named by an edge. */
30
+ line?: number;
31
+ declared: boolean;
32
+ /** Container id this node was declared inside, if any. */
33
+ parent?: string;
34
+ }
35
+ export interface StructureEdge {
36
+ from: string;
37
+ to: string;
38
+ /** Arrow label, e.g. `read` in `PAY --> DRV : read`. */
39
+ label?: string;
40
+ line: number;
41
+ }
42
+ export interface StructureGraph {
43
+ notation: StructureNotation;
44
+ nodes: StructureNode[];
45
+ edges: StructureEdge[];
46
+ warnings: string[];
47
+ }
48
+ /** One dependency rule from the matrix document. */
49
+ export interface StructureRule {
50
+ id: string;
51
+ /** Node id or glob the rule applies to; absent = applies to every source. */
52
+ source?: string;
53
+ /** Permitted targets (glob or node id). Winning an allow match permits the edge. */
54
+ allow?: string[];
55
+ /** Forbidden targets. Deny always wins over allow. */
56
+ deny?: string[];
57
+ /** When true, at least one edge matching source→targets must exist (UML025). */
58
+ require?: boolean;
59
+ }
60
+ export interface StructureLayer {
61
+ name: string;
62
+ /** Node ids or globs that belong to this layer. */
63
+ members: string[];
64
+ }
65
+ /**
66
+ * The dependency matrix: the single source of truth a diagram is checked against.
67
+ * `default` decides the fate of an edge no rule mentions (`allow` = only explicit
68
+ * rules judge, `deny` = anything unlisted is a violation).
69
+ */
70
+ export interface DependencyMatrix {
71
+ rules?: StructureRule[];
72
+ layers?: StructureLayer[];
73
+ default?: 'allow' | 'deny';
74
+ }
75
+ export interface StructureEdgeVerdict {
76
+ from: string;
77
+ to: string;
78
+ line: number;
79
+ /** Rule ids whose `source` matched this edge, whether they allowed or denied it. */
80
+ matchedRules: string[];
81
+ allowed: boolean;
82
+ /** `allow` (a rule permitted it), `default` (nothing judged it), `deny` (a rule forbade it), `unlisted` (default=deny and no rule matched). */
83
+ basis: 'allow' | 'default' | 'deny' | 'unlisted';
84
+ }
85
+ export interface StructureSummary {
86
+ nodes: number;
87
+ edges: number;
88
+ containers: number;
89
+ isolated: number;
90
+ dangling: number;
91
+ cycles: number;
92
+ disallowedEdges: number;
93
+ layerViolations: number;
94
+ missingExpectedEdges: number;
95
+ errors: number;
96
+ warnings: number;
97
+ rules: number;
98
+ }
99
+ export interface StructureReport {
100
+ /** The tool ran and produced this report; read `verdict` for the outcome. */
101
+ ok: boolean;
102
+ ran: boolean;
103
+ verdict: Verdict;
104
+ verdictReason: string;
105
+ /** The versioned report contract this result follows. */
106
+ schema: ReportSchema;
107
+ notation: StructureNotation;
108
+ graph: StructureGraph;
109
+ /** Per-edge matrix verdict, present only when a matrix was supplied. */
110
+ edgeVerdicts?: StructureEdgeVerdict[];
111
+ findings: Finding[];
112
+ summary: StructureSummary;
113
+ /** Hashes of the inputs this report is about: the diagram text, and the matrix when one was supplied. */
114
+ hashes: {
115
+ diagram: string;
116
+ matrix?: string;
117
+ };
118
+ warnings: string[];
119
+ nextSteps: string[];
120
+ }
121
+ /** A finding code in the structure family; the numbers continue the UML0xx series after UML019. */
122
+ export type StructureFindingCode = 'UML020_ISOLATED_NODE' | 'UML021_DANGLING_REFERENCE' | 'UML022_CYCLE' | 'UML023_DISALLOWED_EDGE' | 'UML024_LAYER_VIOLATION' | 'UML025_MISSING_EXPECTED_EDGE' | 'UML026_NO_NODES';
123
+ /**
124
+ * Parse a structure diagram (PlantUML component/package/class/deployment, Mermaid
125
+ * class diagram) into nodes and dependency edges.
126
+ *
127
+ * A structure diagram is *not* refused here: refusing is the state-machine front
128
+ * end's job (`parseUml`). This parser is the honest reading of the same text.
129
+ */
130
+ export declare function parseStructure(text: string, notation?: 'auto' | StructureNotation): StructureGraph;
131
+ /** `*` matches any run of characters, `?` exactly one. Ids keep their own punctuation. */
132
+ export declare function globMatches(pattern: string, value: string): boolean;
133
+ export declare function validateMatrix(input: unknown): {
134
+ ok: true;
135
+ matrix: DependencyMatrix;
136
+ } | {
137
+ ok: false;
138
+ errors: string[];
139
+ };
140
+ /** Shortest directed cycle through the graph, as a node path with the start repeated. */
141
+ export declare function shortestCycle(nodes: string[], edges: StructureEdge[]): string[] | undefined;
142
+ export interface StructureReviewOptions {
143
+ /** Diagram text to review. */
144
+ diagram: string;
145
+ notation?: 'auto' | StructureNotation;
146
+ /** Dependency matrix: allowed/denied edges, layers, required edges. */
147
+ matrix?: unknown;
148
+ }
149
+ /**
150
+ * Audit a structure diagram. Every check is structural: it reads the drawn graph and
151
+ * the declared matrix, and never claims anything about the code behind them.
152
+ */
153
+ export declare function reviewStructure(options: StructureReviewOptions): StructureReport;
154
+ /** The finding codes this module can emit, for documentation and tests. */
155
+ export declare const STRUCTURE_FINDING_CODES: readonly StructureFindingCode[];
156
+ export type { VerdictSummary };
@@ -5,7 +5,7 @@ export declare const LOGICPROBE_VERIFY_TOOL_NAME = "logicprobe_verify";
5
5
  * the 22-check report (S1-S8 structural, A1-A14), or a 26-check
6
6
  * report when beforeModel is supplied (D1 behavioral preservation, D2
7
7
  * invariant continuity, D3 regression delta, D4 deadlock/liveness regression).
8
- * This is the dsh-native replacement for hand-filling the Python template
9
- * shipped in the skill references.
8
+ * This is the dsh-native path: the model is built and run here, with no
9
+ * template to fill in by hand.
10
10
  */
11
11
  export declare const logicProbeVerifyTool: import("@deepseek-ai/dsh-tools").ToolDefinition;
@@ -30,6 +30,7 @@
30
30
  *
31
31
  * @module logicprobe-uml
32
32
  */
33
+ import { type HashSpec, type NarrativeCoverage, type ReportSchema, type Verdict } from './engine.js';
33
34
  import type { GuardNode, LogicModelV1, UpdateSpec } from './engine.js';
34
35
  export type UmlNotation = 'mermaid' | 'plantuml';
35
36
  export type UmlDiagram = 'state' | 'activity' | 'sequence';
@@ -52,8 +53,29 @@ export interface UmlParseResult {
52
53
  * symbol, which the review reports.
53
54
  */
54
55
  labels: Record<string, string>;
56
+ /**
57
+ * Declarations found in the text that LogicModelV1 cannot represent. A non-empty
58
+ * list means the parsed model is NOT this diagram: the text belongs to another
59
+ * diagram family (component, package, class, deployment, …), so whatever came
60
+ * out is a by-product of reading keywords the parser does not own.
61
+ */
62
+ discardedConstructs: DiscardedConstruct[];
63
+ /**
64
+ * Arrows whose endpoints were declared by a discarded construct. They survive
65
+ * parsing as state transitions, which is exactly why they are counted out loud.
66
+ */
67
+ discardedEdges: number;
55
68
  warnings: string[];
56
69
  }
70
+ /** One declaration the parser could not represent, with the source line that carried it. */
71
+ export interface DiscardedConstruct {
72
+ /** The construct keyword, lower-cased (`component`, `package`, `classDiagram`). */
73
+ construct: string;
74
+ /** 1-based line number in the diagram source. */
75
+ line: number;
76
+ /** The source line, trimmed. */
77
+ text: string;
78
+ }
57
79
  export interface UmlFinding {
58
80
  code: string;
59
81
  severity: 'error' | 'warning' | 'info';
@@ -66,18 +88,28 @@ export interface UmlFinding {
66
88
  to: string;
67
89
  }>;
68
90
  detail?: string;
91
+ /** Machine-readable context for the finding (ids, coverage, rule matches), same shape as the engine's findings. */
92
+ evidence?: Record<string, unknown>;
69
93
  }
70
94
  export interface UmlRoundTripReport {
71
95
  notation: UmlNotation;
72
96
  diagram: UmlDiagram;
73
97
  ok: boolean;
98
+ /** Which published hash specification the two hashes follow (see references/hash-spec.md). */
99
+ hashSpec: HashSpec;
74
100
  modelHash: string;
75
101
  parsedHash: string;
76
102
  diffs: string[];
77
103
  warnings: string[];
78
104
  }
79
105
  export interface UmlReviewReport {
106
+ /** The review ran and produced this report. It does NOT mean the modelling passed — read `verdict`. */
80
107
  ok: boolean;
108
+ ran: boolean;
109
+ verdict: Verdict;
110
+ verdictReason: string;
111
+ /** The versioned report contract this result follows. */
112
+ schema: ReportSchema;
81
113
  source: 'model' | 'diagram' | 'model+diagram';
82
114
  summary: {
83
115
  errors: number;
@@ -98,10 +130,30 @@ export interface UmlReviewReport {
98
130
  model?: LogicModelV1;
99
131
  /** Diagram rendered from the model, when only a model was given. */
100
132
  primary?: string;
133
+ /** Paths of the `_`-prefixed metadata keys found in the supplied model, when it carried any. */
134
+ metadataKeys?: string[];
135
+ /** How much of the model the narrative documents; absent when there is no narrative. */
136
+ narrativeCoverage?: NarrativeCoverage;
137
+ /** Hashes of what was reviewed, in one place. */
138
+ hashes: {
139
+ hashSpec: HashSpec;
140
+ modelHash?: string;
141
+ parsedHash?: string;
142
+ };
143
+ /** Declarations the parser could not represent; a non-empty list fails the review. */
144
+ discardedConstructs?: DiscardedConstruct[];
145
+ /** Arrows whose endpoints came from a discarded construct. */
146
+ discardedEdges?: number;
101
147
  warnings: string[];
102
148
  nextSteps: string[];
103
149
  }
150
+ /**
151
+ * A UML front-end refusal. `code` lets the tool report *why* it refused instead of
152
+ * collapsing every refusal into a generic input error.
153
+ */
104
154
  export declare class UmlError extends Error {
155
+ readonly code: string;
156
+ constructor(message: string, code?: string);
105
157
  }
106
158
  /** Canonical guard text. Rendering wraps every composite node in parentheses, and the parser flattens same-operator chains, so render∘parse is the identity. */
107
159
  export declare function guardText(node: GuardNode): string;
@@ -124,6 +176,43 @@ export declare function renderUml(input: unknown, notation?: UmlNotation, diagra
124
176
  export declare function parseGuardText(text: string): GuardNode;
125
177
  /** Parse a UML action clause such as `retry := retry + 1, armed := true`. */
126
178
  export declare function parseUpdatesText(text: string, warnings: string[]): UpdateSpec[];
179
+ /**
180
+ * Findings a parse result carries on its own. A diagram from another family parses
181
+ * into something; without this finding that something is presented as a model of the
182
+ * file, which is a false guarantee of exactly the kind this plugin exists to prevent.
183
+ */
184
+ export declare function parseFindings(parsed: UmlParseResult): UmlFinding[];
185
+ /** One accepted way of writing a state's meaning into a diagram label. */
186
+ export interface LabelForm {
187
+ form: string;
188
+ example: string;
189
+ note: string;
190
+ }
191
+ export interface LabelExplanation {
192
+ notation: UmlNotation;
193
+ /** The comment prefix a `logicprobe:` directive uses in this notation. */
194
+ directivePrefix: string;
195
+ directiveLines: Array<{
196
+ example: string;
197
+ meaning: string;
198
+ }>;
199
+ /** Accepted label spellings, in the order `documentedMeaning` accepts them. */
200
+ acceptedLabelForms: LabelForm[];
201
+ /** What the renderer itself writes, so a hand-edited diagram can match it. */
202
+ renderedForm: string;
203
+ ignoredLines: Array<{
204
+ pattern: string;
205
+ behaviour: string;
206
+ }>;
207
+ rules: string[];
208
+ }
209
+ /**
210
+ * What the front end expects of labels and comments, so "why does my hand-drawn diagram
211
+ * report label drift or ignored lines?" has a printed answer instead of a guess.
212
+ * `tests/uml/run.mjs` feeds every claim here back through the parser, so this text cannot
213
+ * drift away from the behaviour it describes.
214
+ */
215
+ export declare function explainLabels(notation?: UmlNotation): LabelExplanation;
127
216
  /**
128
217
  * Parse a Mermaid or PlantUML diagram back into a LogicModelV1.
129
218
  *