dsh-model-everything 0.0.0-stage → 0.2.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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.en-US.md +332 -0
  3. package/README.md +332 -3
  4. package/cordis.patch.yml +20 -0
  5. package/examples/README.md +48 -0
  6. package/examples/control-dispatcher.json +113 -0
  7. package/examples/control-dispatcher.overbudget.json +113 -0
  8. package/examples/ecommerce-data-model.json +185 -0
  9. package/examples/order-state-machine.after.json +116 -0
  10. package/examples/order-state-machine.before.json +101 -0
  11. package/examples/user-migration.after.json +29 -0
  12. package/examples/user-migration.before.json +29 -0
  13. package/gate/locale/en.json +6 -0
  14. package/gate/locale/zh.json +6 -0
  15. package/gate/package.json +5 -0
  16. package/lib/baseline.js +249 -0
  17. package/lib/compose-tool.js +80 -0
  18. package/lib/concurrency-tool.js +40 -0
  19. package/lib/concurrency.js +206 -0
  20. package/lib/data-engine.js +1141 -0
  21. package/lib/data-tool.js +87 -0
  22. package/lib/design-engine.js +1149 -0
  23. package/lib/design-tool.js +63 -0
  24. package/lib/engine.js +4343 -0
  25. package/lib/export-tool.js +78 -0
  26. package/lib/exporters.js +434 -0
  27. package/lib/gate.js +274 -0
  28. package/lib/granularity.js +237 -0
  29. package/lib/index.js +237 -0
  30. package/lib/json-value.js +18 -0
  31. package/lib/model-file.js +48 -0
  32. package/lib/option-shape.js +62 -0
  33. package/lib/report-diff-tool.js +63 -0
  34. package/lib/report-view.js +433 -0
  35. package/lib/structure-tool.js +91 -0
  36. package/lib/structure.js +711 -0
  37. package/lib/tool.js +94 -0
  38. package/lib/types/baseline.d.ts +65 -0
  39. package/lib/types/compose-tool.d.ts +7 -0
  40. package/lib/types/concurrency-tool.d.ts +8 -0
  41. package/lib/types/concurrency.d.ts +37 -0
  42. package/lib/types/data-engine.d.ts +211 -0
  43. package/lib/types/data-tool.d.ts +10 -0
  44. package/lib/types/design-engine.d.ts +215 -0
  45. package/lib/types/design-tool.d.ts +11 -0
  46. package/lib/types/engine.d.ts +494 -0
  47. package/lib/types/export-tool.d.ts +7 -0
  48. package/lib/types/exporters.d.ts +37 -0
  49. package/lib/types/gate.d.ts +91 -0
  50. package/lib/types/granularity.d.ts +106 -0
  51. package/lib/types/index.d.ts +45 -0
  52. package/lib/types/json-value.d.ts +21 -0
  53. package/lib/types/model-file.d.ts +7 -0
  54. package/lib/types/option-shape.d.ts +22 -0
  55. package/lib/types/report-diff-tool.d.ts +8 -0
  56. package/lib/types/report-view.d.ts +50 -0
  57. package/lib/types/structure-tool.d.ts +10 -0
  58. package/lib/types/structure.d.ts +152 -0
  59. package/lib/types/tool.d.ts +11 -0
  60. package/lib/types/uml-communication.d.ts +109 -0
  61. package/lib/types/uml-composite.d.ts +107 -0
  62. package/lib/types/uml-interaction-overview.d.ts +91 -0
  63. package/lib/types/uml-profile.d.ts +112 -0
  64. package/lib/types/uml-structure.d.ts +53 -0
  65. package/lib/types/uml-syntax.d.ts +296 -0
  66. package/lib/types/uml-timing.d.ts +152 -0
  67. package/lib/types/uml-tool.d.ts +12 -0
  68. package/lib/types/uml-usecase.d.ts +58 -0
  69. package/lib/types/uml.d.ts +303 -0
  70. package/lib/uml-communication.js +353 -0
  71. package/lib/uml-composite.js +442 -0
  72. package/lib/uml-interaction-overview.js +277 -0
  73. package/lib/uml-profile.js +373 -0
  74. package/lib/uml-structure.js +306 -0
  75. package/lib/uml-syntax.js +545 -0
  76. package/lib/uml-timing.js +974 -0
  77. package/lib/uml-tool.js +213 -0
  78. package/lib/uml-usecase.js +532 -0
  79. package/lib/uml.js +2110 -0
  80. package/locale/en.json +6 -0
  81. package/locale/zh.json +6 -0
  82. package/package.json +128 -6
  83. package/skills/model-everything/SKILL.md +450 -0
  84. package/skills/model-everything/references/dsh-model-schema.md +437 -0
  85. package/skills/model-everything/references/gap-routing-guide.md +42 -0
  86. package/skills/model-everything/references/hash-spec.md +152 -0
  87. package/skills/model-everything/references/logic-verification-guide.md +422 -0
  88. package/skills/model-everything-datamodel/SKILL.md +130 -0
  89. package/skills/model-everything-datamodel/references/data-model-guide.md +84 -0
  90. package/skills/model-everything-datamodel/references/data-model-schema.md +128 -0
  91. package/skills/model-everything-design/SKILL.md +115 -0
  92. package/skills/model-everything-interleaving/SKILL.md +63 -0
  93. package/skills/model-everything-interleaving/SKILL.zh-CN.md +60 -0
  94. package/skills/model-everything-interleaving/references/concurrency-risk-guide.md +63 -0
  95. package/skills/model-everything-report-reading/SKILL.md +137 -0
  96. package/skills/model-everything-report-reading/references/reading-a-report.md +166 -0
  97. package/skills/model-everything-report-reading/references/reading-a-report.mmd +59 -0
  98. package/skills/model-everything-structure/SKILL.md +96 -0
  99. package/skills/model-everything-structure/references/structure-review-guide.md +201 -0
  100. package/skills/model-everything-uml/SKILL.md +60 -0
  101. package/skills/model-everything-uml/references/uml-modeling-guide.md +551 -0
  102. package/src/baseline.ts +288 -0
  103. package/src/compose-tool.ts +82 -0
  104. package/src/concurrency-tool.ts +44 -0
  105. package/src/concurrency.ts +254 -0
  106. package/src/data-engine.ts +1208 -0
  107. package/src/data-tool.ts +91 -0
  108. package/src/design-engine.ts +1263 -0
  109. package/src/design-tool.ts +68 -0
  110. package/src/engine.ts +4564 -0
  111. package/src/export-tool.ts +81 -0
  112. package/src/exporters.ts +399 -0
  113. package/src/gate.ts +330 -0
  114. package/src/granularity.ts +312 -0
  115. package/src/index.ts +289 -0
  116. package/src/json-value.ts +20 -0
  117. package/src/model-file.ts +49 -0
  118. package/src/option-shape.ts +64 -0
  119. package/src/report-diff-tool.ts +67 -0
  120. package/src/report-view.ts +483 -0
  121. package/src/structure-tool.ts +93 -0
  122. package/src/structure.ts +786 -0
  123. package/src/tool.ts +103 -0
  124. package/src/uml-communication.ts +428 -0
  125. package/src/uml-composite.ts +520 -0
  126. package/src/uml-interaction-overview.ts +321 -0
  127. package/src/uml-profile.ts +439 -0
  128. package/src/uml-structure.ts +317 -0
  129. package/src/uml-syntax.ts +764 -0
  130. package/src/uml-timing.ts +1106 -0
  131. package/src/uml-tool.ts +230 -0
  132. package/src/uml-usecase.ts +566 -0
  133. package/src/uml.ts +2139 -0
@@ -0,0 +1,494 @@
1
+ export declare const ENGINE_SCHEMA_VERSION = 1;
2
+ export type VarValue = number | boolean;
3
+ export type GuardOp = '==' | '!=' | '<' | '<=' | '>' | '>=';
4
+ export interface LeafGuard {
5
+ variable: string;
6
+ op: GuardOp;
7
+ value: VarValue;
8
+ }
9
+ export interface AllGuard {
10
+ all: GuardNode[];
11
+ }
12
+ export interface AnyGuard {
13
+ any: GuardNode[];
14
+ }
15
+ export interface NotGuard {
16
+ not: GuardNode;
17
+ }
18
+ export type GuardNode = LeafGuard | AllGuard | AnyGuard | NotGuard;
19
+ export interface StateSpec {
20
+ id: string;
21
+ terminal?: boolean;
22
+ /** Actions fired automatically when the state is entered. They do not change state or variables; checks such as A4 Pair Symmetry treat them as implicit acquire/release events so lock/unlock hidden inside entry actions is verified. */
23
+ onEntry?: string[];
24
+ /** Actions fired automatically when the state is left. Same semantics as onEntry. */
25
+ onExit?: string[];
26
+ /** Deadline (A14): the state must be left within this many declared tick events of entering it. */
27
+ maxTicks?: number;
28
+ }
29
+ export interface UpdateSpec {
30
+ variable: string;
31
+ op: 'set' | 'inc' | 'dec';
32
+ value?: number;
33
+ }
34
+ export interface TransitionSpec {
35
+ from: string;
36
+ event: string;
37
+ to: string;
38
+ /** Absent guard is the else/default branch for the same (from, event) group. */
39
+ guard?: GuardNode;
40
+ updates?: UpdateSpec[];
41
+ /** Execution cost of firing this transition (e.g. cycles, microseconds). Absent cost defaults to 1, so an unannotated machine keeps step-count semantics. Checked by A12 against budget invariants. */
42
+ cost?: number;
43
+ /** Relative probability weight when a probability invariant is declared (DTMC interpretation). Absent weight = 1; weight 0 means the branch never fires probabilistically. */
44
+ weight?: number;
45
+ }
46
+ export interface TransitionScenarioSpec {
47
+ from: string;
48
+ event: string;
49
+ /** Natural language: what this (state, event) combination represents in the real scenario. */
50
+ scenario: string;
51
+ }
52
+ export interface ModelNarrative {
53
+ /** Natural-language meaning of each state id. */
54
+ states?: Record<string, string>;
55
+ /** Natural-language meaning of each event id. */
56
+ events?: Record<string, string>;
57
+ /** Natural-language scenario for each distinct (from, event) combination. */
58
+ scenarios?: TransitionScenarioSpec[];
59
+ }
60
+ export interface VariableSpec {
61
+ name: string;
62
+ kind: 'integer' | 'boolean';
63
+ init: number | boolean;
64
+ min?: number;
65
+ max?: number;
66
+ monotonic?: 'inc' | 'dec';
67
+ }
68
+ /**
69
+ * Scope filter for a state-predicate invariant (see `InvariantSpec`): the range is
70
+ * only required to hold in runtime states that satisfy the filter. Exactly one of
71
+ * `state` / guard-node form must be present.
72
+ */
73
+ export interface StateGuard {
74
+ /** Only runtime states whose id is this state are checked. */
75
+ state: string;
76
+ }
77
+ /** A `when` filter: either a single-state scope or the ordinary guard language. */
78
+ export type InvariantWhen = StateGuard | GuardNode;
79
+ export declare function isStateGuard(when: InvariantWhen): when is StateGuard;
80
+ export type InvariantSpec = {
81
+ id: string;
82
+ description: string;
83
+ kind: 'never-states';
84
+ states: string[];
85
+ } | {
86
+ id: string;
87
+ description: string;
88
+ kind: 'var-in-range';
89
+ variable: string;
90
+ min?: number;
91
+ max?: number;
92
+ /**
93
+ * Optional scope. `when` is evaluated against the POST-state of every transition
94
+ * (and, for the `{ state }` form, against the initial state regardless), so a
95
+ * `{ state }` scope is sound: for every reachable runtime state inside the scope
96
+ * the variable is in range. A guard-node scope that references the constrained
97
+ * variable can mask its own violation — prefer `{ state }` or an independent
98
+ * control variable. Not offered on trace-property kinds (leads-to, sequence, ...),
99
+ * whose scope over a path would be ambiguous.
100
+ */
101
+ when?: InvariantWhen;
102
+ } | {
103
+ id: string;
104
+ description: string;
105
+ kind: 'event-before-state';
106
+ event: string;
107
+ state: string;
108
+ } | {
109
+ id: string;
110
+ description: string;
111
+ kind: 'leads-to';
112
+ from: string;
113
+ to: string | string[];
114
+ } | {
115
+ id: string;
116
+ description: string;
117
+ kind: 'sequence';
118
+ events: string[];
119
+ } | {
120
+ id: string;
121
+ description: string;
122
+ kind: 'atomicity';
123
+ events: string[];
124
+ commit: string;
125
+ rollback?: string;
126
+ } | {
127
+ id: string;
128
+ description: string;
129
+ kind: 'budget';
130
+ budget: number;
131
+ } | {
132
+ id: string;
133
+ description: string;
134
+ kind: 'probability';
135
+ target: string;
136
+ op: '>=' | '<=' | '>' | '<';
137
+ p: number;
138
+ };
139
+ export interface ResourcePairSpec {
140
+ resource: string;
141
+ acquireEvent: string;
142
+ releaseEvent: string;
143
+ failEvent?: string;
144
+ }
145
+ export interface BoundaryCheckSpec {
146
+ variable: string;
147
+ values: number[];
148
+ }
149
+ export interface LogicModelV1 {
150
+ schemaVersion: 1;
151
+ init: string;
152
+ states: StateSpec[];
153
+ transitions: TransitionSpec[];
154
+ variables?: VariableSpec[];
155
+ invariants?: InvariantSpec[];
156
+ concurrentPairs?: [string, string][];
157
+ boundaryChecks?: BoundaryCheckSpec[];
158
+ resourcePairs?: ResourcePairSpec[];
159
+ idempotentEvents?: string[];
160
+ /** Events that advance the discrete clock by one tick; used by A14 deadline checks. */
161
+ tickEvents?: string[];
162
+ /** Natural-language descriptions of states, events, and (state, event) scenarios. */
163
+ narrative?: ModelNarrative;
164
+ }
165
+ export interface VerificationOptions {
166
+ maxStates?: number;
167
+ maxPermutationEvents?: number;
168
+ beforeModel?: unknown;
169
+ stateMapping?: Record<string, string>;
170
+ /** Hash specification used for modelHash. Defaults to the current published spec (`v1`). */
171
+ hashSpec?: HashSpec;
172
+ }
173
+ export interface PathStep {
174
+ from: string;
175
+ event: string;
176
+ to: string;
177
+ }
178
+ export interface Finding {
179
+ code: string;
180
+ /**
181
+ * `info` is a note, not a defect: it is reported so a machine-readable reader can see it,
182
+ * and it never contributes to `verdict`, `summary.errors` or `summary.warnings`.
183
+ */
184
+ severity: 'error' | 'warning' | 'info';
185
+ message: string;
186
+ /** Longer explanation: the shortest-path note, the per-machine reasons, the quoted source lines. */
187
+ detail?: string;
188
+ /** The artefact the finding is about (a diagram name, a file path) — set when one report covers several. */
189
+ file?: string;
190
+ /** 1-based line in that artefact, when the check knows it. */
191
+ line?: number;
192
+ path?: PathStep[];
193
+ evidence?: Record<string, unknown>;
194
+ }
195
+ export interface CheckResult {
196
+ id: string;
197
+ name: string;
198
+ status: 'pass' | 'fail' | 'skip';
199
+ detail: string;
200
+ findings: Finding[];
201
+ }
202
+ export interface VerificationReport {
203
+ /**
204
+ * The engine ran and the input was well-formed enough to produce this report.
205
+ * It does NOT mean the review passed — read `verdict` for that.
206
+ */
207
+ ok: boolean;
208
+ /** The tool executed and produced a report. False only when a tool refused the request before the engine ran. */
209
+ ran: boolean;
210
+ /** The review outcome. `ok: true` with `verdict: "fail"` is a failing review, not a passing one. */
211
+ verdict: Verdict;
212
+ /** Why the verdict came out that way, e.g. `2 error finding(s) (first error: S2_NO_TRANSITIONS)`. */
213
+ verdictReason: string;
214
+ /** The versioned report contract this result follows. */
215
+ schema: ReportSchema;
216
+ schemaVersion: 1;
217
+ /** Which published specification `modelHash` follows (see references/hash-spec.md). */
218
+ hashSpec: HashSpec;
219
+ modelHash: string;
220
+ /** Every hash this report carries, in one place, for a baseline diff or an archive record. */
221
+ hashes: {
222
+ hashSpec: HashSpec;
223
+ modelHash: string;
224
+ beforeModelHash?: string;
225
+ afterModelHash?: string;
226
+ };
227
+ /** Paths of the `_`-prefixed metadata keys found in the input and ignored by the schema. */
228
+ metadataKeys?: string[];
229
+ /** How much of the model the narrative documents; absent when there is no narrative. */
230
+ narrativeCoverage?: NarrativeCoverage;
231
+ /** Echo of the model's natural-language narrative, when present. */
232
+ narrative?: ModelNarrative;
233
+ summary: {
234
+ states: number;
235
+ transitions: number;
236
+ errors: number;
237
+ warnings: number;
238
+ checksRun: number;
239
+ truncated?: boolean;
240
+ /** Bounds that were replaced or clamped because they could not bound the search. */
241
+ boundNotes?: string[];
242
+ };
243
+ checks: CheckResult[];
244
+ comparison?: ComparisonSummary;
245
+ /** What to do next, derived from the findings — never empty. */
246
+ nextSteps: string[];
247
+ /** Informational notes about semantic dimensions this model references (timing, preemption)
248
+ * that this engine does not verify. Heuristic, vocabulary-based — never a substitute for the checks. */
249
+ coverageNotes?: string[];
250
+ }
251
+ export interface ComparisonSummary {
252
+ beforeModelHash: string;
253
+ afterModelHash: string;
254
+ stateMapping: Record<string, string>;
255
+ beforeStates: number;
256
+ beforeTransitions: number;
257
+ afterStates: number;
258
+ afterTransitions: number;
259
+ addedStates: string[];
260
+ removedStates: string[];
261
+ addedEvents: string[];
262
+ removedEvents: string[];
263
+ addedTransitions: TransitionSpec[];
264
+ removedTransitions: TransitionSpec[];
265
+ }
266
+ export interface RuntimeState {
267
+ state: string;
268
+ vars: Record<string, VarValue>;
269
+ }
270
+ /**
271
+ * The hash of any model this plugin carries: the same normalization as `modelHash`,
272
+ * over whatever object the family defines. A use case diagram and a state machine are
273
+ * hashed by one rule, so a report can name either.
274
+ */
275
+ export declare function valueHash(value: unknown, spec?: HashSpec): string;
276
+ export declare function modelHash(model: LogicModelV1, spec?: HashSpec): string;
277
+ /**
278
+ * Deterministic JSON (sorted keys, no insignificant whitespace) — the serialization the
279
+ * hash specification is defined over. Exported so every report hashes inputs the same way.
280
+ */
281
+ export declare function canonicalJson(value: unknown): string;
282
+ /**
283
+ * Published model-hash specifications. The full normalization rules, the list of
284
+ * excluded keys and a one-line recompute command are in `references/hash-spec.md`.
285
+ *
286
+ * - `v1` (1.0.0) drops every `_`-prefixed metadata key at every level before hashing,
287
+ * so archiving `_source` / `_verified` next to a model cannot change its hash.
288
+ * - `v0` is the pre-1.0.0 behaviour (no metadata filtering), kept so an archived hash
289
+ * can still be checked against the old engine.
290
+ *
291
+ * For a model that carries no `_` keys the two specs are byte-identical.
292
+ */
293
+ export type HashSpec = 'v0' | 'v1';
294
+ export declare const PUBLISHED_HASH_SPECS: readonly HashSpec[];
295
+ export declare const DEFAULT_HASH_SPEC: HashSpec;
296
+ /**
297
+ * Versioned report contracts. Every tool result carries `schema`, so a consumer can
298
+ * branch on the contract instead of sniffing fields, and a change to a report's shape
299
+ * is a version bump here rather than a silent break. `findings[]` keeps the same
300
+ * stable core in every family: `{code, severity, message, detail?, evidence?, path?}`.
301
+ */
302
+ export declare const REPORT_SCHEMAS: {
303
+ readonly verify: 'model-everything/verify/v1';
304
+ readonly compose: 'model-everything/compose/v1';
305
+ readonly datamodel: 'model-everything/datamodel/v1';
306
+ readonly concurrency: 'model-everything/concurrency/v1';
307
+ readonly export: 'model-everything/export/v1';
308
+ readonly umlRender: 'model-everything/uml/render/v1';
309
+ readonly umlParse: 'model-everything/uml/parse/v1';
310
+ readonly umlReview: 'model-everything/uml/review/v1';
311
+ readonly umlExplainLabels: 'model-everything/uml/explain-labels/v1';
312
+ readonly umlRefusal: 'model-everything/uml/refusal/v1';
313
+ readonly structure: 'model-everything/structure/v1';
314
+ readonly granularity: 'model-everything/granularity/v1';
315
+ readonly design: 'model-everything/design/v1';
316
+ readonly baseline: 'model-everything/baseline/v1';
317
+ };
318
+ export type ReportSchema = typeof REPORT_SCHEMAS[keyof typeof REPORT_SCHEMAS];
319
+ /**
320
+ * How much of the model the `narrative` block actually documents, as `covered/total`
321
+ * per dimension. A partial narrative is valid — writing the states first and the
322
+ * events later is the natural order — so this is a coverage report, not a gate.
323
+ * `scenarios` counts distinct modelled (from, event) groups: one scenario per group.
324
+ */
325
+ export interface NarrativeCoverage {
326
+ states: string;
327
+ events: string;
328
+ scenarios: string;
329
+ }
330
+ export declare function narrativeCoverageOf(model: LogicModelV1): NarrativeCoverage | undefined;
331
+ /** True when every dimension of the coverage is fully described. */
332
+ export declare function narrativeComplete(coverage: NarrativeCoverage | undefined): boolean;
333
+ /**
334
+ * The review outcome, kept separate from `ok` (= "the tool ran"). Collapsing the two
335
+ * is how a failed review gets read as a passing one.
336
+ */
337
+ export type Verdict = 'pass' | 'pass_with_findings' | 'fail';
338
+ export interface VerdictSummary {
339
+ verdict: Verdict;
340
+ verdictReason: string;
341
+ }
342
+ /** A tool that refused the request before running anything: it neither passed nor failed a review. */
343
+ export declare function refusalVerdict(reason: string): VerdictSummary;
344
+ /**
345
+ * Decide the verdict from finding counts. Any error-severity finding fails the review
346
+ * even though the tool ran successfully — that gap is exactly what `verdict` closes.
347
+ */
348
+ export declare function verdictOf(errors: number, warnings: number, firstCode?: string): VerdictSummary;
349
+ export declare function verdictOfFindings(findings: Array<{
350
+ code: string;
351
+ severity: string;
352
+ }>): VerdictSummary;
353
+ /**
354
+ * Paths of every `_`-prefixed key in the input, sorted (`_source`, `_verified`,
355
+ * `states[0]._note`; a metadata key's own children are not listed, since the subtree is
356
+ * metadata as a whole). The schema ignores these keys as annotation metadata; echoing
357
+ * them in the report makes the ignored metadata auditable instead of invisible.
358
+ *
359
+ * Iterative, with an explicit stack: this runs before validation on whatever the caller passed, so
360
+ * a recursive walk overflowed the stack on a deeply nested model and the `RangeError` arrived
361
+ * instead of any report at all. A guard nested ten thousand deep is nonsense, and it has to be
362
+ * refused rather than crash the walk that was going to refuse it.
363
+ */
364
+ export declare function metadataKeysOf(input: unknown): string[];
365
+ /**
366
+ * The exact payload a hash spec hashes. Exported so the specification has one
367
+ * implementation and the documentation can be checked against it.
368
+ */
369
+ export declare function hashPayload(model: unknown, spec?: HashSpec): unknown;
370
+ export declare function validateModel(input: unknown): {
371
+ ok: true;
372
+ model: LogicModelV1;
373
+ } | {
374
+ ok: false;
375
+ errors: string[];
376
+ };
377
+ /**
378
+ * Event names in the adversarial declarations that no transition and no entry/exit action
379
+ * declares.
380
+ *
381
+ * The robustness audit called this the dominant defect class: a misspelled name made a check
382
+ * skip and then report its all-clear - "All pairs balanced", "No race conditions detected", "All
383
+ * deadlines respected" - for a model it never ran on. A reader cannot tell an empty check from a
384
+ * passing one, which is what a verifier must never do.
385
+ *
386
+ * A name that resolves to nothing is reported by the check that would have used it, not refused
387
+ * by validation, because for some fields the absence IS the defect: a
388
+ * `resourcePairs[].releaseEvent` naming a step nobody built is what `A4_NO_RELEASE_EVENT` says,
389
+ * and refusing it would replace a finding that names the missing step with a generic one.
390
+ */
391
+ export declare function unresolvedEventNames(root: Record<string, unknown>): Array<{
392
+ path: string;
393
+ value: string;
394
+ check: string;
395
+ }>;
396
+ /**
397
+ * Every variable a guard names, total and iterative for the same reasons as
398
+ * `walkGuardReferences`.
399
+ */
400
+ export declare function guardVariables(guard: GuardNode | undefined): string[];
401
+ export declare function runVerification(input: unknown, options?: VerificationOptions): VerificationReport;
402
+ export interface CompositionStep {
403
+ event: string;
404
+ /** Indices of the machines that advanced together on this step. */
405
+ machines: number[];
406
+ }
407
+ /** A location two machines can both touch. Without one, a composition shares nothing. */
408
+ export interface SharedLocation {
409
+ id: string;
410
+ /** Initial value, for the reader only: the checks below decide on declarations, not on values. */
411
+ initial?: string | number | boolean;
412
+ }
413
+ /** How one machine event touches a shared location. */
414
+ export interface SharedAccess {
415
+ /** Machine index, as given in the composition's `machines` array. */
416
+ machine: number;
417
+ event: string;
418
+ location: string;
419
+ /**
420
+ * `read-write` is a read-modify-write: the value read is written back, so two of them that
421
+ * are not mutually exclusive lose an update.
422
+ */
423
+ kind: 'read' | 'write' | 'read-write';
424
+ /**
425
+ * The lock both sides name when the operation is guarded. Two accesses that name the SAME
426
+ * lock are treated as mutually exclusive. This checks that the two sides agree on the lock,
427
+ * not that the lock is held across the whole operation - that is a single-machine question,
428
+ * and `model_verify` is the tool that can answer it.
429
+ */
430
+ protectedBy?: string;
431
+ }
432
+ export interface CompositionOptions {
433
+ /** Events that require a synchronized multi-machine step (handshake). */
434
+ rendezvous?: string[];
435
+ /** Locations both machines can touch. Declaring none means the composition shares nothing. */
436
+ shared?: SharedLocation[];
437
+ /** Which machine events touch which shared locations, and how. */
438
+ accesses?: SharedAccess[];
439
+ maxStates?: number;
440
+ /** Hash specification used for the per-machine modelHash. Defaults to the current published spec (`v1`). */
441
+ hashSpec?: HashSpec;
442
+ }
443
+ export interface CompositionSummary {
444
+ machineCount: number;
445
+ machines: Array<{
446
+ modelHash: string;
447
+ states: number;
448
+ transitions: number;
449
+ }>;
450
+ compositeStates: number;
451
+ errors: number;
452
+ warnings: number;
453
+ truncated: boolean;
454
+ }
455
+ export interface CompositionReport {
456
+ /**
457
+ * Historical meaning: the composition has no error-severity finding. Read `verdict` for the review
458
+ * outcome.
459
+ *
460
+ * This field does NOT mean the same thing across the report families, which is why nothing should
461
+ * route on it: a failing verification report carries `ok: true`, and a failing composition carries
462
+ * `ok: false`, for the same verdict. The robustness review of the report-reading guide measured
463
+ * both. `docs/report-reading/guide.md` says so, and `tests/report-reading` holds it.
464
+ */
465
+ ok: boolean;
466
+ ran: boolean;
467
+ verdict: Verdict;
468
+ verdictReason: string;
469
+ /** The versioned report contract this result follows. */
470
+ schema: ReportSchema;
471
+ /** Which published specification the per-machine `modelHash` values follow. */
472
+ hashSpec: HashSpec;
473
+ /** Every hash this report carries, in one place. */
474
+ hashes: {
475
+ hashSpec: HashSpec;
476
+ machines: string[];
477
+ };
478
+ summary: CompositionSummary;
479
+ checks: CheckResult[];
480
+ /** What to do next, derived from the findings — never empty. */
481
+ nextSteps: string[];
482
+ }
483
+ /**
484
+ * N-machine composition semantics (documented in dsh-model-schema.md):
485
+ * - a non-rendezvous event advances exactly ONE non-terminal machine that fires it;
486
+ * - a rendezvous event (handshake) fires only when AT LEAST TWO machines declare it in
487
+ * their alphabet and EVERY such non-terminal machine has it enabled (guards held);
488
+ * all participants then advance simultaneously. A machine that is terminal, or whose
489
+ * alphabet does not include the event, does not participate;
490
+ * - a terminal machine is stopped and takes no further part.
491
+ * Checks: C1 composition deadlock (reachable node where no machine can advance while at
492
+ * least one is not terminal) and C2 rendezvous that can never fire.
493
+ */
494
+ export declare function runCompositionVerification(machinesInput: unknown[], options?: CompositionOptions): CompositionReport;
@@ -0,0 +1,7 @@
1
+ export declare const EXPORT_TOOL_NAME = "model_export";
2
+ /**
3
+ * DSH tool wrapping the external-tool exporters: turn a LogicModelV1 machine into
4
+ * native input for the tool this plugin routes to (UPPAAL / TLA+ / PRISM / SPIN).
5
+ * v1 translates the core machine; unrepresentable invariants become warnings.
6
+ */
7
+ export declare const modelExportTool: import("@deepseek-ai/dsh-tools").ToolDefinition;
@@ -0,0 +1,37 @@
1
+ import { type LogicModelV1 } from './engine.js';
2
+ export type ExportFormat = 'uppaal' | 'tla' | 'prism' | 'spin';
3
+ export interface ExportResult {
4
+ format: ExportFormat;
5
+ primary: string;
6
+ extras?: Record<string, string>;
7
+ warnings: string[];
8
+ }
9
+ export interface ExportedModel {
10
+ model: LogicModelV1;
11
+ stateIds: string[];
12
+ indexOf: Map<string, number>;
13
+ initId: string;
14
+ stateIdOf: Map<string, string>;
15
+ }
16
+ export declare function prepareModel(input: unknown): ExportedModel;
17
+ /**
18
+ * Every format this exporter can produce, in one place.
19
+ *
20
+ * The absence of this list is what made an unknown format dangerous: the function ended with
21
+ * `return exportSpin(ex)`, so `'mermaid'`, `42`, `''` and `undefined` all produced Promela and
22
+ * reported `format: 'spin'`. A caller who named a notation this exporter cannot write received a
23
+ * different notation's output and a report naming a format they had not asked for.
24
+ */
25
+ export declare const EXPORT_FORMATS: readonly ExportFormat[];
26
+ export declare function isExportFormat(value: unknown): value is ExportFormat;
27
+ /**
28
+ * A refusal an exporter knows by name.
29
+ *
30
+ * The tool mapped every throw onto `MODEL_INVALID`, so "this valid model is too large for the PRISM encoding" came
31
+ * back as "your model is invalid" - a claim about the caller's work made by a limit of the exporter.
32
+ */
33
+ export declare class ExportError extends Error {
34
+ readonly code: string;
35
+ constructor(code: string, message: string);
36
+ }
37
+ export declare function exportModel(input: unknown, format: unknown): ExportResult;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The gate: one optional routing message, injected once per session.
3
+ *
4
+ * Why it exists. Routing works through text: the measured result is that a session asked
5
+ * to check something loads the skill whose catalog line matches. What that measurement
6
+ * also showed is the limit - a session that never decides to load anything is never routed,
7
+ * and the catalog line is cut at 500 characters, so the tail of a long line is invisible at
8
+ * the moment of choosing. This component carries the routing in a message instead of in the
9
+ * line, for a deployment that wants the decision made for it.
10
+ *
11
+ * Why it is a separate row. The plugin's doctrine is that a capability is discoverable
12
+ * through its own tool description or skill text. Injection departs from that, so it is
13
+ * opt-in and mounted as its own component: install it, disable it, or never enable it,
14
+ * without touching the tools or the skills. `enabled` is a live switch, so the Web Plugins
15
+ * page flips it inside a running host.
16
+ *
17
+ * Why it is off by default. It costs tokens in every session that turns it on, to fix a
18
+ * problem text-only routing was measured not to have once the session engages. A deployment
19
+ * that wants it says so; the default pays nothing.
20
+ *
21
+ * What it does not do. It routes; it checks nothing. It cannot make a skill load, and it
22
+ * does not restate the doctrine - the skill bodies carry that, and duplicating them here
23
+ * would spend the session's context on a second copy.
24
+ *
25
+ * @module dsh-model-everything-gate
26
+ */
27
+ import type { Context, Volatile } from '@deepseek-ai/cordis';
28
+ import z from '@deepseek-ai/schemastery';
29
+ import type { ContextFormed } from '@deepseek-ai/dsh-llm';
30
+ declare module '@deepseek-ai/dsh-llm' {
31
+ interface MessageSourceMap {
32
+ 'plugin:dsh-model-everything-gate': {
33
+ kind: 'plugin:dsh-model-everything-gate';
34
+ } & ContextFormed;
35
+ }
36
+ }
37
+ export declare const name = "dsh-model-everything-gate";
38
+ /**
39
+ * The skills this package actually ships, read from disk when the module loads.
40
+ *
41
+ * The table below advertises only these. A row for a skill that is not in the package sends the
42
+ * model to a name that resolves to nothing, which is the one failure a routing message must not
43
+ * have; a skill added without a row still gets an entry, reading "see its catalog line", so the
44
+ * table can be incomplete but never wrong.
45
+ */
46
+ export declare function shippedSkills(): string[];
47
+ /**
48
+ * The text, rendered from the skills that ship.
49
+ *
50
+ * The rule is stated at both ends, in different words. That is a measured change, not a stylistic
51
+ * one: with a single statement, the one case that needed the plugin - a migration question the
52
+ * session believed it could answer from memory - loaded no skill and ran no tool. Stated at the
53
+ * start and restated at the end, it did both, and a control task was not over-triggered.
54
+ *
55
+ * The shape follows a neighbouring plugin's injected section: a table that chooses between near-equals,
56
+ * rows only for what is installed, and a rule against degrading silently when a tool refuses.
57
+ *
58
+ * @param skills - the skills to advertise; defaults to the ones on disk.
59
+ * @param extraGuidance - a deployment's own sentence, appended last.
60
+ */
61
+ export declare function renderGateText(skills?: string[], extraGuidance?: string): string;
62
+ /** The shipped default: every row the package can advertise, no deployment guidance. */
63
+ export declare const DEFAULT_GATE_TEXT: string;
64
+ export interface Config {
65
+ /** Whether the gate is injected. Read through {@link injectionEnabled}. On unless a deployment says otherwise. */
66
+ enabled: Volatile<boolean> | boolean;
67
+ /** The text to inject. Override in the profile's `cordis.patch.yml` row, not in a GUI form. */
68
+ gateContent: string;
69
+ /** A deployment's own sentence, appended to whatever text is injected. */
70
+ extraGuidance: string;
71
+ }
72
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
73
+ enabled: z<boolean, boolean, "defined">;
74
+ gateContent: z<string, string, "defined">;
75
+ extraGuidance: z<string, string, "defined">;
76
+ }>>, Schemastery.ObjectT<NoInfer<{
77
+ enabled: z<boolean, boolean, "defined">;
78
+ gateContent: z<string, string, "defined">;
79
+ extraGuidance: z<string, string, "defined">;
80
+ }>>, "plain">;
81
+ /**
82
+ * Mount the gate.
83
+ *
84
+ * The listener is registered whether or not the switch is on: the switch is volatile, so
85
+ * `apply` runs once and the value behind it can turn on later from the Plugins page.
86
+ * Returning early here would freeze the decision for the lifetime of the mount.
87
+ *
88
+ * @param ctx - the plugin context.
89
+ * @param config - the resolved plugin configuration.
90
+ */
91
+ export declare function apply(ctx: Context, config: Config): void;