dsh-model-everything 0.1.0 → 0.3.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.
- package/README.en-US.md +102 -81
- package/README.md +88 -76
- package/lib/automaton-tool.js +69 -0
- package/lib/automaton.js +327 -0
- package/lib/compose-tool.js +11 -2
- package/lib/concurrency-tool.js +6 -1
- package/lib/data-engine.js +1 -1
- package/lib/data-tool.js +18 -5
- package/lib/design-tool.js +21 -8
- package/lib/edit-tool.js +111 -0
- package/lib/editor.js +293 -0
- package/lib/engine.js +8 -1
- package/lib/export-tool.js +6 -1
- package/lib/index.js +4 -0
- package/lib/model-file.js +48 -0
- package/lib/presentation.js +81 -0
- package/lib/report-diff-tool.js +6 -1
- package/lib/report-view.js +92 -15
- package/lib/routing.js +85 -0
- package/lib/scan.js +547 -0
- package/lib/structure-tool.js +34 -1
- package/lib/structure.js +28 -3
- package/lib/tool.js +19 -4
- package/lib/types/automaton-tool.d.ts +2 -0
- package/lib/types/automaton.d.ts +57 -0
- package/lib/types/edit-tool.d.ts +2 -0
- package/lib/types/editor.d.ts +46 -0
- package/lib/types/engine.d.ts +1 -0
- package/lib/types/model-file.d.ts +7 -0
- package/lib/types/presentation.d.ts +59 -0
- package/lib/types/report-view.d.ts +8 -1
- package/lib/types/routing.d.ts +31 -0
- package/lib/types/scan.d.ts +37 -0
- package/lib/types/structure.d.ts +16 -0
- package/lib/uml-tool.js +16 -6
- package/package.json +8 -3
- package/skills/model-everything/SKILL.md +51 -79
- package/skills/model-everything/references/automata.md +102 -0
- package/skills/model-everything-interleaving/SKILL.zh-CN.md +60 -60
- package/skills/model-everything-report-reading/SKILL.md +137 -137
- package/src/automaton-tool.ts +73 -0
- package/src/automaton.ts +375 -0
- package/src/compose-tool.ts +13 -3
- package/src/concurrency-tool.ts +7 -1
- package/src/data-engine.ts +1 -1
- package/src/data-tool.ts +19 -5
- package/src/design-tool.ts +74 -60
- package/src/edit-tool.ts +119 -0
- package/src/editor.ts +297 -0
- package/src/engine.ts +8 -1
- package/src/export-tool.ts +87 -81
- package/src/index.ts +4 -0
- package/src/model-file.ts +49 -0
- package/src/presentation.ts +125 -0
- package/src/report-diff-tool.ts +7 -1
- package/src/report-view.ts +534 -451
- package/src/routing.ts +96 -0
- package/src/scan.ts +564 -0
- package/src/structure-tool.ts +33 -1
- package/src/structure.ts +37 -3
- package/src/tool.ts +19 -4
- package/src/uml-tool.ts +240 -230
package/README.en-US.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center"><strong>English</strong> · <a href="README.md">中文</a></p>
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/AmethystLuna/dsh-model-everything/actions/workflows/dsh-bundle.yml"><img src="https://github.com/AmethystLuna/dsh-model-everything/actions/workflows/dsh-bundle.yml/badge.svg" alt="CI"></a>
|
|
7
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
|
|
8
|
+
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20-blue.svg" alt="Node 20+"></a>
|
|
9
|
+
<a href="https://afdian.com/a/amethystluna"><img src="https://img.shields.io/badge/%E7%88%B1%E5%8F%91%E7%94%B5-Afdian-946CE6" alt="Sponsor on Afdian"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
5
12
|
Abstract what a design or a piece of code claims into a model and let an engine run it: findings carry citations and hashes, so they can be recomputed and compared. The conclusion comes from a run rather than from reasoning it out: thinking it through becomes running it.
|
|
6
13
|
|
|
7
14
|
A native DeepSeek Harness plugin. It turns the assertions a design makes **about behaviour** into models that can be run, reviewed and exported:
|
|
@@ -12,117 +19,123 @@ A native DeepSeek Harness plugin. It turns the assertions a design makes **about
|
|
|
12
19
|
- **Compare a refactor**: a model before and after, with the two reports side by side.
|
|
13
20
|
- **Leave a record**: conclusions fixed into a report with hashes, recomputable and comparable and exportable.
|
|
14
21
|
|
|
22
|
+
## It costs more; what it returns is a verdict
|
|
23
|
+
|
|
24
|
+
This is a capability tool, not a token-saving one.
|
|
25
|
+
|
|
26
|
+
**How much it costs depends on the size of the task, and the direction is the opposite of intuition.** On a
|
|
27
|
+
fixture of a few hundred lines it costs several times the baseline, because the fixed cost - skill body,
|
|
28
|
+
tool definitions - has nothing to amortise against. On an object of tens of thousands of lines across
|
|
29
|
+
hundreds of files the ratio falls back toward parity: we measured 0.93x to 1.11x. **The larger the task,
|
|
30
|
+
the better the trade**: one decision replaces dozens of `read` calls rather than a few lines of code.
|
|
31
|
+
|
|
32
|
+
What the extra buys:
|
|
33
|
+
|
|
34
|
+
- a conclusion that can be **recomputed**: hashes, `verdict`, citations, not a paragraph that reads like one;
|
|
35
|
+
- a **counterexample path**: the steps or the event sequence that breaks the claim;
|
|
36
|
+
- a **portable model**: the same conclusion can be handed to UPPAAL, TLA+, PRISM or SPIN for a second opinion.
|
|
37
|
+
|
|
38
|
+
When it is not worth it: when one reading of the code settles the claim, or three lines of script count
|
|
39
|
+
it out. **It does not buy speed over reading.** It buys the claims that reading cannot decide.
|
|
40
|
+
|
|
41
|
+
**It decides small models, not programs.** The engine enumerates states, so a model that explodes is
|
|
42
|
+
reported `truncated` with the undecided check named. That is not a bug to retry with a larger `maxStates`:
|
|
43
|
+
reduce the model first, and if it still explodes the property needs a tool that does not enumerate - SPIN
|
|
44
|
+
for partial-order reduction, NuSMV for symbolic search, CBMC for bounded SAT. This plugin builds no
|
|
45
|
+
abstraction and reads no program source.
|
|
46
|
+
|
|
15
47
|
## What it covers
|
|
16
48
|
|
|
17
49
|
| Domain | What it does |
|
|
18
50
|
|---|---|
|
|
19
51
|
| Claim checking | Enumerates the verifiable claims in a design, spec or review comment. Checks each against the code with a citation, and says plainly which ones it could not settle |
|
|
20
|
-
| Behaviour | State machines and protocols: structural checks, adversarial probes, budgets and deadlines, before/after regression. Composition checks catch deadlock and a rendezvous that never fires |
|
|
52
|
+
| Behaviour | State machines and protocols: structural checks, adversarial probes, budgets and deadlines, before/after regression. Composition checks catch deadlock and a rendezvous that never fires. Finite-word automata decide language relations - equivalence, inclusion - and return the shortest witness word |
|
|
21
53
|
| Diagrams | UML 2.5 diagram families: render, parse and modelling review (including the render→parse fidelity check), in Mermaid and PlantUML |
|
|
22
54
|
| Structure | Component, package, class and deployment diagrams audited as dependency graphs: isolated nodes, dangling endpoints, cycles, matrix and layer violations, missing required edges |
|
|
23
55
|
| Data | Data models and migrations: structure, migration coverage, copy consistency, rollback symmetry, before/after data regression |
|
|
24
56
|
| Concurrency / synchrony / async | Mines claims about how work is executed (thread-safe, locks, interrupts, async/await, the event loop) and routes each to a tool that can decide it. It proves nothing itself |
|
|
25
57
|
| Export | Exports a verified model as input for UPPAAL, TLA+, PRISM or SPIN |
|
|
26
|
-
| Reports | Report body rendering, baseline comparison (`report_diff`), hash specification |
|
|
58
|
+
| Reports | Report body rendering, baseline comparison (`report_diff`), hash specification. Every report also carries a summary for a UI - verdict, the first finding, the next step - while the model still gets the full text |
|
|
27
59
|
|
|
28
60
|
## Typical uses
|
|
29
61
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
A refactor may change the implementation. It may not change the behaviour. Let an engine settle that, instead of reading the diff:
|
|
33
|
-
|
|
34
|
-
1. **Before**: extract a BEFORE model from the code as it stands (`uml_parse` reads an existing diagram, or write the model against the schema).
|
|
35
|
-
2. **Refactor**.
|
|
36
|
-
3. **After**: extract an AFTER model.
|
|
37
|
-
4. **Regression**: `model_verify` with `beforeModel` and `stateMapping` runs the before/after regression: behaviour preserved, invariants continuous, the state mapping consistent. On the data side, `model_datamodel_verify` runs the same comparison over data, from its `beforeModel`, `fieldMapping` and `migrationMappings`.
|
|
38
|
-
5. **Verdict and record**: `report_diff` compares against the baseline report. An added error finding is the reason not to accept the refactor. The hashes in the report let the conclusion be recomputed.
|
|
39
|
-
|
|
40
|
-
It compares the **two models you give it**, not two versions of the code. Whether each model is faithful to its own source is what steps 1 and 3 are for, and it does not do that part for you. It does not read the diff, edit code or run your tests either. It answers "is the behaviour still the same", not "was this a good refactor".
|
|
41
|
-
|
|
42
|
-
### Reviewing a code flow
|
|
62
|
+
Each one says what to hand over, which field to read, and what the tool does not do.
|
|
43
63
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
1. **Extract the flow**: write the branches of a function or a service as a `LogicModelV1`, or draw a `stateDiagram-v2` / PlantUML diagram by hand.
|
|
47
|
-
2. **Read it back**: give the hand-drawn diagram to `uml_parse`. A line it cannot read becomes a warning rather than disappearing.
|
|
48
|
-
3. **Review it**: `uml_review` reports the structural defects - unreachable states, dead ends, a branch that is ambiguous or not exhaustive, a self-loop with no exit, isolated nodes, cycles - and the documentation gaps.
|
|
49
|
-
4. **Reconcile with the source**: take every finding back to the code. A correct diagram does not make the code correct.
|
|
50
|
-
|
|
51
|
-
It reviews the diagram and the model you give it. Whether they match the code is what step 1 is for.
|
|
52
|
-
|
|
53
|
-
### Reviewing a state machine
|
|
54
|
-
|
|
55
|
-
Build the machine as an executable model and let an engine run it, instead of reading the code and concluding that it cannot get stuck:
|
|
56
|
-
|
|
57
|
-
1. **Build the model**: `uml_parse` reads a hand-drawn `stateDiagram-v2` or PlantUML state diagram; a `LogicModelV1` can also be written directly against the schema.
|
|
58
|
-
2. **Run the checks**: `model_verify` looks for unreachable states, absorbing cycles, events silently ignored, an allocation with no recovery path, a budget overrun, and a deadline that cannot be met. It reports each as a code whose prefix says which family it belongs to.
|
|
59
|
-
3. **State the always/never claims**: put them in `invariants`. The engine searches every reachable state for a counterexample and returns the shortest one it finds.
|
|
60
|
-
4. **Reconcile with the source**: every error finding goes back to the code.
|
|
61
|
-
|
|
62
|
-
Concurrency claims split in two: the ones about **two models touching one shared location** are decided here, by `model_compose_verify` (declare `shared` and `accesses`; C3/C4/C5 decide the declaration, the unordered write and the lost update). Source-level data races, interrupt latency, a blocking call and a missing `await` are still routed to TSan/Helgrind/CBMC/TLA+. Hard real-time semantics - deadlines and periods - are outside its scope.
|
|
64
|
+
### A refactoring harness
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
1. Extract the **BEFORE** model; keep the old schema for the data side.
|
|
67
|
+
2. Refactor.
|
|
68
|
+
3. Extract the **AFTER** model.
|
|
69
|
+
4. `model_verify` with `beforeModel` and `stateMapping`; `model_datamodel_verify` with `fieldMapping` for data.
|
|
70
|
+
5. `report_diff` against the baseline report: **a newly added error is the reason to reject the refactor**.
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
It compares two models, not two codebases. It reads no diff, changes no code, runs no test.
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
2. **Say what is allowed**, if you have a rule: a matrix of `layers` and `rules`, each rule naming a `source` with `allow` / `deny` / `require` and a `default` for everything else. Without a matrix it reports only structural defects.
|
|
70
|
-
3. **Read the findings**: an isolated node, an endpoint never declared, a cycle with its shortest path, an edge that crosses a layer, a required edge that is missing, and - when no node is declared at all - that the input said nothing to audit.
|
|
71
|
-
4. **Ask the same question about a code flow**, if the drawing is a state or activity diagram: that is `uml_review`, not this.
|
|
74
|
+
### A state machine or a flow
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
1. Hand the diagram to `uml_parse`, or write the model against the schema.
|
|
77
|
+
2. `model_verify` runs the structural checks and the adversarial probes: unreachable states, absorbing cycles, silently ignored events, budgets, deadlines.
|
|
78
|
+
3. Put the always/never claims into `invariants` and get the shortest counterexample path back.
|
|
79
|
+
4. For the drawing alone, `uml_review`: are the branches exhaustive, is there a dead end.
|
|
80
|
+
5. Every error finding goes back to the code; fixing the model is `model_edit`, which returns the structural diff and the change in findings in one call.
|
|
74
81
|
|
|
75
|
-
|
|
82
|
+
**A correct drawing is not correct code** - that step belongs to the extraction.
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
### Auditing a dependency graph
|
|
78
85
|
|
|
79
|
-
1.
|
|
80
|
-
2.
|
|
81
|
-
3.
|
|
86
|
+
1. Hand over a diagram, or a `repoPath` and let `uml_structure_verify` build the graph from the source.
|
|
87
|
+
2. Optional matrix: `layers` plus `rules`.
|
|
88
|
+
3. Read the findings: cycle, isolated node, dangling endpoint, layer violation, missing required edge. When the parser reports **label drift**, `uml_explain_labels` prints the spellings that notation accepts.
|
|
82
89
|
|
|
83
|
-
|
|
90
|
+
**Facts belong here, rules do not**: whether an edge exists is this tool's question; whether it was allowed is `model_design_review`.
|
|
84
91
|
|
|
85
|
-
###
|
|
92
|
+
### A design held to its own declarations
|
|
86
93
|
|
|
87
|
-
|
|
94
|
+
1. Write the design and the rules it declares as a `DesignModelV1`.
|
|
95
|
+
2. `model_design_review` reports three lists: `violations` decide the verdict, `signals` are signals, `facts` are measurements.
|
|
96
|
+
3. A check with nothing to hold the design to is `skip`, not `pass`.
|
|
88
97
|
|
|
89
|
-
|
|
90
|
-
2. **Name the shared events** in `rendezvous` if a handshake is only legal when both sides are ready. An event not named there advances one machine, so a machine waiting on a handshake can take any number of its own steps first.
|
|
91
|
-
3. **Read C1 and C2**: a reachable node where no machine can advance and one of them is not terminal, and a rendezvous that can never fire. Both name the reason per machine, and C1 gives the shortest counterexample.
|
|
98
|
+
It judges no design **by an external standard**. It asks whether the design holds to what it says about itself.
|
|
92
99
|
|
|
93
|
-
|
|
100
|
+
### Two machines that must cooperate
|
|
94
101
|
|
|
95
|
-
|
|
102
|
+
1. Model each one, hand the array to `model_compose_verify`.
|
|
103
|
+
2. Put the handshakes that need both sides ready into `rendezvous`.
|
|
104
|
+
3. Read C1 (a node no machine can advance from) and C2 (a rendezvous that never fires), each with a per-machine reason and, for C1, the shortest counterexample.
|
|
96
105
|
|
|
97
|
-
|
|
106
|
+
A question about one machine alone goes back to `model_verify`. There is no rate ratio and no fairness in a composition.
|
|
98
107
|
|
|
99
|
-
|
|
100
|
-
2. **Read what each absolute claim owes**: a claim like "no data race is possible" is reported as an error requiring dedicated verification, and each finding names the analysis that could settle it - TSan or Helgrind for a race, CBMC for a bounded proof, TLA+ for a protocol, RTOS-aware interrupt analysis for an ISR.
|
|
101
|
-
3. **Run that analysis**: this plugin does not run it and proves nothing about concurrency itself.
|
|
108
|
+
### Concurrency claims: mine, then route
|
|
102
109
|
|
|
103
|
-
|
|
110
|
+
1. `model_interleaving_scan` reads a document and reports absolute claims by `family` (thread-safe, lock-free, ISR-safe ...).
|
|
111
|
+
2. Each one names the analysis that decides it: TSan or Helgrind, CBMC, TLA+, RTOS-aware analysis.
|
|
112
|
+
3. This plugin **runs none of them** and proves nothing about concurrency.
|
|
104
113
|
|
|
105
|
-
|
|
114
|
+
A clean scan is not a clean bill of health: it says no claim was found.
|
|
106
115
|
|
|
107
|
-
A migration
|
|
116
|
+
### A migration: two models, one assertion
|
|
108
117
|
|
|
109
|
-
1.
|
|
110
|
-
2.
|
|
111
|
-
3.
|
|
112
|
-
4.
|
|
118
|
+
1. A data model before and after.
|
|
119
|
+
2. `fieldMapping`; `migrationMappings` for a field whose source is not its own old name.
|
|
120
|
+
3. `model_datamodel_verify` checks migration coverage, copy consistency, rollback symmetry, and the before/after data regression.
|
|
121
|
+
4. `DS2_REQUIRED_FIELD_UNSOURCED` is a **warning**: it is a decision for you, not a failure the engine can announce.
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
### Language inclusion: two automata
|
|
115
124
|
|
|
116
|
-
|
|
125
|
+
1. Write the specification and the implementation as automata: `states`, `alphabet`, `transitions`, `accepting`.
|
|
126
|
+
2. `model_automaton_verify` with `other` and `relation` (`equivalent`, `subset` or `superset`).
|
|
127
|
+
3. When the relation fails you get the **shortest witness word** - accepted by one, rejected by the other, replayable through both.
|
|
117
128
|
|
|
118
|
-
|
|
129
|
+
Finite words only. Liveness, fairness and timing need a Büchi or timed automaton, which this family does not build.
|
|
119
130
|
|
|
120
|
-
|
|
121
|
-
- **A reference for the long run**: on the next change, extract the model again, run the verification again, and compare with the frozen report through `report_diff`. An added error is what this change introduced; a finding that disappeared is an old problem solved. The hashes decide whether this is still the same model, instead of an eyeball comparison of two pictures.
|
|
131
|
+
### Diagrams as source: freeze and iterate
|
|
122
132
|
|
|
123
|
-
|
|
133
|
+
1. `uml_render` writes Mermaid or PlantUML source; `uml_parse` reads it back into a model.
|
|
134
|
+
2. Commit the source, the model and the report of that run together, as the design record at a point in time.
|
|
135
|
+
3. On the next change, re-extract, re-run, and compare with `report_diff`.
|
|
136
|
+
4. For a second opinion, `model_export` writes UPPAAL, TLA+, PRISM or SPIN input.
|
|
124
137
|
|
|
125
|
-
|
|
138
|
+
What is kept is the **source file**; a rendered image is a by-product.
|
|
126
139
|
|
|
127
140
|
## Tools
|
|
128
141
|
|
|
@@ -137,10 +150,14 @@ The limit: it stores and compares **model and diagram source**; a rendered pictu
|
|
|
137
150
|
| `model_datamodel_verify` | Data models and migrations |
|
|
138
151
|
| `model_interleaving_scan` | Mines and routes concurrency, synchrony and async claims |
|
|
139
152
|
| `model_export` | Exports to an external checker (UPPAAL, TLA+, PRISM, SPIN) |
|
|
140
|
-
| `uml_structure_verify` | Dependency-graph audit, including a dependency matrix and multi-level refinement |
|
|
153
|
+
| `uml_structure_verify` | Dependency-graph audit, including a dependency matrix and multi-level refinement; give it `repoPath` and it builds the graph from each language's own import construct (C/C++, Python, TypeScript/JavaScript, Go, Rust, Java/Kotlin/Scala, C#, PHP, Ruby, Lua, Zig, Dart, Elixir) |
|
|
141
154
|
| `model_design_review` | Design review: the dependency graph's shape, plus the contracts the design declares about itself - layering, responsibility boundaries, substitutability, interface width |
|
|
155
|
+
| `model_automaton_verify` | Finite-word automata: empty language, trap states, reachability, and the equivalence or inclusion relation against another automaton, with the **shortest witness word** when it fails |
|
|
156
|
+
| `model_edit` | Changes a model file by naming one change (add/remove a state, add/remove/update a transition, pointer set/remove): returns the structural diff and the difference in findings, so edit-verify-compare takes one call |
|
|
142
157
|
| `report_diff` | Compares two reports: what a change added, removed or changed |
|
|
143
158
|
|
|
159
|
+
`model_verify`, `model_datamodel_verify` and `model_design_review` also take `modelPath`: a JSON file in the workspace, in any formatting (indentation, a BOM and a trailing newline all parse). It is the alternative to an inline `model`; passing both is refused.
|
|
160
|
+
|
|
144
161
|
## Reading a report
|
|
145
162
|
|
|
146
163
|
What a tool returns is a report, and the outcome is in `verdict`: read `verdict`, never `ok`. `ok` carries a different historical meaning in each family — most set it to `true` for a failing review, and a composition sets it to `false` when any error-severity finding exists — so it cannot be read as a verdict, and reading it as one is how a reader concludes the opposite of what the report says.
|
|
@@ -154,7 +171,7 @@ What a tool returns is a report, and the outcome is in `verdict`: read `verdict`
|
|
|
154
171
|
| `schema` | The versioned report contract, for example `model-everything/verify/v1`. Branch on this field rather than on the shape of the payload |
|
|
155
172
|
| `truncated` | The search hit its ceiling and stopped. **A truncated search is not a pass**, it is no conclusion; a property that could not be decided appears as `_UNDECIDED` |
|
|
156
173
|
|
|
157
|
-
The body is what comes back by default. For the whole structured result, pass `reportView: "full"
|
|
174
|
+
The body is what comes back by default. A truncated check can be expanded on its own: pass `check: "<id>"` and every finding of that check prints. For the whole structured result, pass `reportView: "full"` — compact JSON, no field lost.
|
|
158
175
|
|
|
159
176
|
When `ok` is `false` the verdict is `fail` as well, but it means something else: the tool did not run. The reason is in `errorCode` - invalid input, an unsupported diagram family, or a declared `intent` this view cannot serve. Such a refusal starts its `verdictReason` with `the tool did not run:`.
|
|
160
177
|
|
|
@@ -234,8 +251,6 @@ How it works, in four sentences:
|
|
|
234
251
|
|
|
235
252
|
**Default and switch**: on by default. That default was measured: it reaches the one request class the plugin otherwise never sees, and a control task was not over-triggered. The price is about 3.2k characters per session; turn it off in `cordis.patch.yml` (below) or with the Plugins-page switch, which is also how to run a comparison - the same request with the gate off and on.
|
|
236
253
|
|
|
237
|
-
`gateContent` can be replaced wholesale to try different wording; `tests/gate` still requires it to name every shipped skill.
|
|
238
|
-
|
|
239
254
|
## Configuration
|
|
240
255
|
|
|
241
256
|
The routing component (on by default) has three keys:
|
|
@@ -251,11 +266,11 @@ The main row has one key, `interaction` (what happens when a tool call is offere
|
|
|
251
266
|
Write it into the profile's `cordis.patch.yml` by row id:
|
|
252
267
|
|
|
253
268
|
```yaml
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
269
|
+
# Override that row's config by id: the whole config is replaced, not merged.
|
|
270
|
+
# Do not add `name` here - a row with a name inserts a new row instead of changing this one.
|
|
271
|
+
- id: dsh-model-everything-gate
|
|
272
|
+
config:
|
|
273
|
+
enabled: false # turn the injection off
|
|
259
274
|
```
|
|
260
275
|
|
|
261
276
|
## Boundaries
|
|
@@ -317,3 +332,9 @@ The published work behind the checks — and which checks have none — is in [d
|
|
|
317
332
|
## License and security
|
|
318
333
|
|
|
319
334
|
MIT, see [LICENSE](LICENSE). Security policy in [SECURITY.md](SECURITY.md).
|
|
335
|
+
|
|
336
|
+
## Sponsor
|
|
337
|
+
|
|
338
|
+
This plugin is open source under the MIT license. If it saves you time, you can support development on [Afdian](https://afdian.com/a/amethystluna).
|
|
339
|
+
|
|
340
|
+
Sponsorship is voluntary and changes neither the license nor the features.
|
package/README.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
<p align="center"><a href="README.en-US.md">English</a> · <strong>中文</strong></p>
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://github.com/AmethystLuna/dsh-model-everything/actions/workflows/dsh-bundle.yml"><img src="https://github.com/AmethystLuna/dsh-model-everything/actions/workflows/dsh-bundle.yml/badge.svg" alt="CI"></a>
|
|
7
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
|
|
8
|
+
<a href="https://nodejs.org/"><img src="https://img.shields.io/badge/node-%3E%3D20-blue.svg" alt="Node 20+"></a>
|
|
9
|
+
<a href="https://afdian.com/a/amethystluna"><img src="https://img.shields.io/badge/%E7%88%B1%E5%8F%91%E7%94%B5-Afdian-946CE6" alt="在爱发电上赞助"></a>
|
|
10
|
+
</p>
|
|
11
|
+
|
|
5
12
|
把设计与代码里的断言抽象成模型,交给引擎跑一遍:结论带出处与哈希,能复算、能比对。让结论来自一次运行,而不是一次通盘推理:把「想清楚」变成「跑一遍」。
|
|
6
13
|
|
|
7
14
|
DeepSeek Harness 原生插件。把设计与代码里**关于行为的断言**变成可运行、可审查、可导出的模型:
|
|
@@ -12,117 +19,114 @@ DeepSeek Harness 原生插件。把设计与代码里**关于行为的断言**
|
|
|
12
19
|
- **对照重构**:重构前后各建一份模型,两份报告摆一起比。
|
|
13
20
|
- **留痕**:结论固化成带哈希的报告,可复算、可比对、可导出。
|
|
14
21
|
|
|
22
|
+
## 它更贵,但它给的是判定
|
|
23
|
+
|
|
24
|
+
这是一个**能力型工具,不是省钱工具**。
|
|
25
|
+
|
|
26
|
+
**贵多少取决于任务大小,而且是反过来的**:几百行的夹具上它贵出数倍——固定成本(技能正文、工具定义)摊不开;对象涨到几万行、上百文件,比例回落到持平附近,我们测到 0.93×–1.11×。**任务越大,这笔钱越值**:一次判定替代的是几十次 `read`,而不是几行代码。
|
|
27
|
+
|
|
28
|
+
换来的是别的东西:
|
|
29
|
+
|
|
30
|
+
- 一条**可复算**的结论:哈希、`verdict`、出处,而不是一段读起来像结论的散文;
|
|
31
|
+
- 一条**反例路径**:哪几步、哪个事件序列让断言不成立;
|
|
32
|
+
- 一份**可导出的模型**:同一条结论能交给 UPPAAL、TLA+、PRISM、SPIN 复核。
|
|
33
|
+
|
|
34
|
+
什么时候不值得:断言能靠通读一次代码、或者写三行脚本数出来的时候。**它买不到比读一遍更快**;它买到的是「读一遍给不出判定」的那类断言。
|
|
35
|
+
|
|
36
|
+
**它判定的是小模型,不是程序。** 引擎显式枚举状态,模型炸开时会报 `truncated` 并点名未决的检查。那不是重试一个更大的 `maxStates` 就能解决的:先减模型(去掉性质不读的变量、合并对称状态),仍然炸开就换不靠枚举的工具——SPIN 的偏序归约、NuSMV 的符号化、CBMC 的有界 SAT。本插件不建立抽象,也不读程序源码。
|
|
37
|
+
|
|
15
38
|
## 能力范围
|
|
16
39
|
|
|
17
40
|
| 域 | 做什么 |
|
|
18
41
|
|---|---|
|
|
19
42
|
| 事实核验 | 把一份设计/规格/评审意见里的可验证断言列出来,逐条对着代码核验并给出出处。核不了的直接说明 |
|
|
20
|
-
| 行为验证 | 状态机与协议:结构检查、对抗性探测、预算与时限、before/after
|
|
43
|
+
| 行为验证 | 状态机与协议:结构检查、对抗性探测、预算与时限、before/after 回归。多机组合查死锁,以及永不发生的会合(握手事件)。有限词自动机判语言关系(等价、包含)并给出最短反例词 |
|
|
21
44
|
| 图 | UML 2.5 各图族的渲染、解析与建模审查(含 render→parse 往返一致性对照),覆盖 Mermaid 与 PlantUML 两种记号 |
|
|
22
45
|
| 结构 | 组件/包/类/部署图按依赖图审计:孤立节点、悬空引用、环、矩阵与分层违规、缺失的必需边 |
|
|
23
46
|
| 数据 | 数据模型与迁移:结构、迁移覆盖、拷贝一致性、回滚对称、前后数据回归 |
|
|
24
47
|
| 并发 / 同步 / 异步 | 挖掘"工作怎么被执行"的断言(线程安全、锁、中断、async/await、事件循环…)并路由到能判定它的工具;它自己不证明 |
|
|
25
48
|
| 导出 | 已验证模型导出为 UPPAAL / TLA+ / PRISM / SPIN 的输入 |
|
|
26
|
-
| 报告 | 报告正文渲染、基线比对(`report_diff
|
|
49
|
+
| 报告 | 报告正文渲染、基线比对(`report_diff`)、哈希规范。每份报告另带一份给界面用的摘要:verdict、首条问题、下一步,正文照旧给模型 |
|
|
27
50
|
|
|
28
51
|
## 典型用法
|
|
29
52
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
重构可以改实现,不能改行为。这个判断交给引擎,不必通读 diff:
|
|
33
|
-
|
|
34
|
-
1. **重构前**:从当前代码抽出 BEFORE 模型(`uml_parse` 读已有的图,或按 schema 手写)。
|
|
35
|
-
2. **重构**。
|
|
36
|
-
3. **重构后**:抽出 AFTER 模型。
|
|
37
|
-
4. **回归**:`model_verify` 带 `beforeModel` 与 `stateMapping` 跑前后回归:行为是否保持、不变式是否连续、状态映射是否自洽。数据侧用 `model_datamodel_verify` 的 `beforeModel` / `fieldMapping` / `migrationMappings` 做同一件事的**数据版**。
|
|
38
|
-
5. **判定与留痕**:`report_diff` 拿基线报告比对。新增的 error 发现,就是这次重构不接受的理由。报告里的哈希让结论可复算。
|
|
39
|
-
|
|
40
|
-
它比较的是**你给的两份模型**,不是两份代码。每份模型是否忠实于对应代码,由第 1、3 步负责,它不代替你做。它也不读 diff、不改代码、不跑你的测试。它回答的是"行为还一样吗",不是"重构得好不好"。
|
|
41
|
-
|
|
42
|
-
### 代码流程审查
|
|
53
|
+
每个场景都只讲「给什么、看哪个字段、它不管什么」。
|
|
43
54
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
1. **抽流程**:把函数或服务里的分支写成 `LogicModelV1`,或者手画一张 `stateDiagram-v2` / PlantUML 图。
|
|
47
|
-
2. **读回模型**:手画的图交给 `uml_parse` 转成模型。读不动的行会变成警告,不会悄悄跳过。
|
|
48
|
-
3. **审查**:`uml_review` 报结构缺陷——不可达状态、死端、分支有歧义或没穷尽、自环没有出口、孤立节点、环——以及文档缺口。
|
|
49
|
-
4. **落回源码**:每条发现都回到代码核验。图画对了,不等于代码写对了。
|
|
55
|
+
### 重构 harness
|
|
50
56
|
|
|
51
|
-
|
|
57
|
+
1. 重构前抽 **BEFORE** 模型;数据侧留一份旧 schema。
|
|
58
|
+
2. 重构。
|
|
59
|
+
3. 抽 **AFTER** 模型。
|
|
60
|
+
4. `model_verify` 带 `beforeModel` 与 `stateMapping`;数据侧用 `model_datamodel_verify` 的 `fieldMapping`。
|
|
61
|
+
5. `report_diff` 拿基线报告比对:**新增的 error 就是拒绝这次重构的理由**。
|
|
52
62
|
|
|
53
|
-
|
|
63
|
+
它比的是两份模型,不是两份代码;也不读 diff、不改代码、不跑测试。
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
### 状态机与流程图
|
|
56
66
|
|
|
57
|
-
1.
|
|
58
|
-
2.
|
|
59
|
-
3.
|
|
60
|
-
4.
|
|
67
|
+
1. 图交给 `uml_parse`,或直接按 schema 写模型。
|
|
68
|
+
2. `model_verify` 跑结构检查与对抗探测:不可达、吸收环、被静默忽略的事件、预算、时限。
|
|
69
|
+
3. 把「永远 / 绝不」写进 `invariants`,拿回最短反例路径。
|
|
70
|
+
4. 只看图本身用 `uml_review`:分支是否穷尽、有没有死端。
|
|
71
|
+
5. 每条 error 回到代码核验;改模型用 `model_edit`,一次调用拿回结构 diff 与发现 diff。
|
|
61
72
|
|
|
62
|
-
|
|
73
|
+
**图画对了不等于代码写对了**——那一步由抽取负责。
|
|
63
74
|
|
|
64
75
|
### 审计一张依赖图
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
2. **说清什么被允许**(如果有规则):一个含 `layers` 与 `rules` 的矩阵,每条规则点名一个 `source` 并给 `allow` / `deny` / `require`,再用 `default` 管其余。没有矩阵时,它只报结构缺陷。
|
|
70
|
-
3. **读发现**:孤立节点、从未声明过的端点、带最短路径的环、越过层的边、缺失的必需边,以及——一个节点都没声明时——**这份输入没有任何可审的东西**。
|
|
71
|
-
4. **换一种图就换个工具**:如果这张图是状态图或活动图,那是 `uml_review`,不是它。
|
|
77
|
+
1. 给图,或给 `repoPath` 让 `uml_structure_verify` 直接从源码建图。
|
|
78
|
+
2. 有规则就给矩阵:`layers` 加 `rules`。
|
|
79
|
+
3. 读发现:环、孤立节点、悬空端点、越层边、缺失的必需边。解析器报**标签漂移**时,`uml_explain_labels` 打印该记号接受的写法。
|
|
72
80
|
|
|
73
|
-
|
|
81
|
+
**事实归它,规则不归它**:某条边到底存不存在,问这个工具;该不该允许,是 `model_design_review`。
|
|
74
82
|
|
|
75
83
|
### 让设计对自己作出的声明负责
|
|
76
84
|
|
|
77
|
-
|
|
85
|
+
1. 把设计与它声明的规则写成 `DesignModelV1`。
|
|
86
|
+
2. `model_design_review` 报三类:`violations` 决定判定,`signals` 只是信号,`facts` 是测量。
|
|
87
|
+
3. 没声明任何可对照的东西时,对应检查是 `skip`,不是 pass。
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
2. **跑它**:`model_design_review` 报出设计与自相矛盾的地方,并**另外**报出它图的形状——环与打断环所需的最少边、承重元素、层级、扇入扇出。
|
|
81
|
-
3. **读那三个列表**:`violations` 决定判定;`signals` 值得一看但不使任何东西失败;`facts` 是**测量**,不是发现。`checksSkipped` 说明哪些原则因为**没声明任何可对照的东西**而没有检查。
|
|
82
|
-
|
|
83
|
-
**它从不按外部标准评判设计。** 它报的是:设计**与它自己声明的某件事**矛盾,或关于它的图的一个结构事实。问「这个设计好不好」是评审者的问题;这个工具回答的是另一个:**它就自己的说法而言,站得住吗**。
|
|
89
|
+
它**不按外部标准**评判设计,只问:它就自己的说法而言站得住吗。
|
|
84
90
|
|
|
85
91
|
### 两台必须互相配合的机器
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
2. **点名共享事件**:如果一个握手只有在双方都就绪时才合法,把它写进 `rendezvous`。没写进去的事件只推进一台机器,所以等握手的机器可以先走任意多步自己的路。
|
|
91
|
-
3. **读 C1 与 C2**:一个可达节点上没有任何机器能前进、且有机器不是终止态(C1),以及一个**永远不会触发**的会合(C2)。两者都逐机给出理由,C1 还给最短反例。
|
|
93
|
+
1. 各自建模,一起给 `model_compose_verify`。
|
|
94
|
+
2. 需要双方同时就绪的会合写进 `rendezvous`。
|
|
95
|
+
3. 读 C1 死锁与 C2 永不触发的会合,各自带逐机理由与最短反例。
|
|
92
96
|
|
|
93
|
-
|
|
97
|
+
单台机器自己的问题回 `model_verify`;组合里没有速率比,也没有公平性。
|
|
94
98
|
|
|
95
99
|
### 并发声明:挖掘并路由
|
|
96
100
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
2. **看每条绝对声明欠着什么**:「不可能有数据竞争」这类声明会被报为 error,要求**专门的**验证,且每条发现都点名能判定它的分析——竞争用 TSan 或 Helgrind,有界证明用 CBMC,协议用 TLA+,中断用 RTOS 感知的分析。
|
|
101
|
-
3. **去做那个分析**:本插件不运行它,也不对并发安全作任何证明。
|
|
101
|
+
1. `model_interleaving_scan` 扫文本,按 `family` 报出绝对断言(线程安全、lock-free、ISR 安全…)。
|
|
102
|
+
2. 每条点名能判定它的分析:TSan / Helgrind、CBMC、TLA+、RTOS 感知分析。
|
|
103
|
+
3. 本插件**不运行**那个分析,也不对并发安全作任何证明。
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
一次干净的扫描不是健康证明——它的含义只是没找到声明。
|
|
104
106
|
|
|
105
107
|
### 一次迁移:前后两份模型
|
|
106
108
|
|
|
107
|
-
|
|
109
|
+
1. 前后各一份数据模型。
|
|
110
|
+
2. 给 `fieldMapping`;来源不是自己旧名字的字段用 `migrationMappings`。
|
|
111
|
+
3. `model_datamodel_verify` 查迁移覆盖、拷贝一致性、回滚对称、前后数据回归。
|
|
112
|
+
4. `DS2_REQUIRED_FIELD_UNSOURCED` 是 **warning**:它是要你做的决定,不是引擎能替你宣布的失败。
|
|
108
113
|
|
|
109
|
-
|
|
110
|
-
2. **说清字段怎么走**:`fieldMapping` 从旧路径到新路径,加上 `migrationMappings`——用于来源不是它自己旧名字的字段。
|
|
111
|
-
3. **跑比对**:`model_datamodel_verify` 带 `beforeModel`,检查迁移覆盖、拷贝一致性、回滚对称,以及前后数据回归。
|
|
112
|
-
4. **读那条警告**:新 schema 里声明为 `required`、却没有任何东西供给它的字段,会报 `DS2_REQUIRED_FIELD_UNSOURCED`。它是 **warning**,所以判定停在 `pass_with_findings`——**这是一个要做的决定,不是引擎可以替你宣布的失败**。
|
|
114
|
+
### 语言包含:两台自动机
|
|
113
115
|
|
|
114
|
-
|
|
116
|
+
1. 把规范与实现各自写成自动机:`states`、`alphabet`、`transitions`、`accepting`。
|
|
117
|
+
2. `model_automaton_verify` 带 `other` 与 `relation`(`equivalent` / `subset` / `superset`)。
|
|
118
|
+
3. 关系不成立时拿走**最短反例词**——一个实现接受、规范拒绝的词,可以直接在两台机器上重放。
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
只判有限词。liveness、公平性与时序需要 Büchi 或时间自动机,这个族不做。
|
|
117
121
|
|
|
118
|
-
|
|
122
|
+
### 图的导入与导出:冻结与迭代
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
1. `uml_render` 写出 Mermaid / PlantUML 源,`uml_parse` 读回模型。
|
|
125
|
+
2. 图源、模型与那次验证的报告一起提交,作为某个时间点的设计记录。
|
|
126
|
+
3. 下次改动重抽、重跑,用 `report_diff` 与冻结的那份比对。
|
|
127
|
+
4. 要交给外部检查器,用 `model_export` 出 UPPAAL / TLA+ / PRISM / SPIN。
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
界线:它保存并比对的是**模型与图的源文件**,渲染出来的图片只是副产品。图变了模型没变、或模型变了图没变,都会在下一次解析或比对时暴露。
|
|
129
|
+
它保留的是**源文件**,渲染出的图片只是副产品。
|
|
126
130
|
|
|
127
131
|
## 工具
|
|
128
132
|
|
|
@@ -137,10 +141,14 @@ DeepSeek Harness 原生插件。把设计与代码里**关于行为的断言**
|
|
|
137
141
|
| `model_datamodel_verify` | 数据模型与迁移验证 |
|
|
138
142
|
| `model_interleaving_scan` | 并发 / 同步 / 异步声明的挖掘与路由 |
|
|
139
143
|
| `model_export` | 导出到外部检查器(UPPAAL / TLA+ / PRISM / SPIN) |
|
|
140
|
-
| `uml_structure_verify` |
|
|
144
|
+
| `uml_structure_verify` | 依赖图审计(含依赖矩阵与多层级细化);也可以直接给 `repoPath`,由工具按语言的 import 构造建图(C/C++、Python、TypeScript/JavaScript、Go、Rust、Java/Kotlin/Scala、C#、PHP、Ruby、Lua、Zig、Dart、Elixir) |
|
|
141
145
|
| `model_design_review` | 设计审阅:依赖图形状 + 设计自身声明的契约(分层、职责边界、可替换性、接口宽度) |
|
|
146
|
+
| `model_automaton_verify` | 有限词自动机:空语言、陷阱状态、可达性,以及与另一台自动机的等价/包含关系;关系不成立时给出**最短反例词** |
|
|
147
|
+
| `model_edit` | 按条改动模型文件(加/删状态、加/删/改迁移、指针 set/remove):返回结构 diff 与发现 diff,一次调用完成「改—验—比」 |
|
|
142
148
|
| `report_diff` | 两份报告比对:新增/消失/变化的发现 |
|
|
143
149
|
|
|
150
|
+
`model_verify`、`model_datamodel_verify`、`model_design_review` 另收 `modelPath`:从工作区里的 JSON 文件读模型,缩进、BOM、尾随换行都不影响。它与内联的 `model` 二选一,两个都给会被拒绝。
|
|
151
|
+
|
|
144
152
|
## 怎么读报告
|
|
145
153
|
|
|
146
154
|
工具的产出是一份报告,结论只在 `verdict` 里:**看 `verdict`,不看 `ok`**。`ok` 在各族的含义不同——多数族在评审失败时仍是 `true`,组合族在出现 error 级发现时是 `false`——所以它不能当判定读;把它当判定读,会得出与报告相反的结论。
|
|
@@ -154,7 +162,7 @@ DeepSeek Harness 原生插件。把设计与代码里**关于行为的断言**
|
|
|
154
162
|
| `schema` | 报告的版本化契约,例如 `model-everything/verify/v1`。要按字段分支,就分支在它上面 |
|
|
155
163
|
| `truncated` | 搜索撞到上限就停了。**截断不等于通过**,是没结论;某个性质没判定出来时,报告里会出现 `_UNDECIDED` |
|
|
156
164
|
|
|
157
|
-
|
|
165
|
+
默认返回正文。被截断的检查可以单独展开:传 `check: "<id>"`,该检查的全部条目都会打印。要完整结果,传 `reportView: "full"`——紧凑 JSON,对象不丢字段。
|
|
158
166
|
|
|
159
167
|
`ok` 为 `false` 时判定也是 `fail`,但含义不同:工具根本没跑。原因写在 `errorCode` 里——输入不合法、图族不支持,或声明的 `intent` 服务不了。这类拒绝的 `verdictReason` 以 `the tool did not run:` 开头。
|
|
160
168
|
|
|
@@ -234,8 +242,6 @@ npx -p @deepseek-ai/dsh dsh plugin --profile <profile> add dsh-model-everything
|
|
|
234
242
|
|
|
235
243
|
**开关与默认**:默认开。这个默认值是量出来的——它补上的是插件唯一接不住的那类请求,而对照任务没有被过度触发。代价是每个会话约 3.2k 字符;要关掉就改 `cordis.patch.yml`(见下)或翻插件页的开关。想做对照(同一个请求,关一次开一次)也用它。
|
|
236
244
|
|
|
237
|
-
`gateContent` 可以整段替换,用来试别的措辞;`tests/gate` 仍要求它点名每个已发布的技能。
|
|
238
|
-
|
|
239
245
|
## 配置
|
|
240
246
|
|
|
241
247
|
注入组件(默认开)有三个键:
|
|
@@ -251,11 +257,11 @@ npx -p @deepseek-ai/dsh dsh plugin --profile <profile> add dsh-model-everything
|
|
|
251
257
|
按 row id 写进 profile 的 `cordis.patch.yml`:
|
|
252
258
|
|
|
253
259
|
```yaml
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
# 按 id 覆盖那一行的 config:整段替换,不做深合并。
|
|
261
|
+
# 这里不要写 name——写了 name 是「插入一行」,不是「改这一行」。
|
|
262
|
+
- id: dsh-model-everything-gate
|
|
263
|
+
config:
|
|
264
|
+
enabled: false # 关掉注入
|
|
259
265
|
```
|
|
260
266
|
|
|
261
267
|
## 边界
|
|
@@ -317,3 +323,9 @@ MODEL_EVERYTHING_SPIN=/path/to/spin MODEL_EVERYTHING_GCC=/path/to/gcc npm run te
|
|
|
317
323
|
## 许可证与安全
|
|
318
324
|
|
|
319
325
|
MIT,见 [LICENSE](LICENSE)。安全策略见 [SECURITY.md](SECURITY.md)。
|
|
326
|
+
|
|
327
|
+
## 赞助
|
|
328
|
+
|
|
329
|
+
本插件以 MIT 许可证开源。如果它节省了你的时间,可以在[爱发电](https://afdian.com/a/amethystluna)赞助开发。
|
|
330
|
+
|
|
331
|
+
赞助完全自愿,不影响许可证,也不改变任何功能。
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `model_automaton_verify`: what language does this machine accept, and is it the one it claims.
|
|
3
|
+
*
|
|
4
|
+
* The description is written for the decision. A conformance claim - "the implementation allows every run
|
|
5
|
+
* the specification allows" - is a language inclusion, and the two machines can be small while the
|
|
6
|
+
* question is still beyond a reading: the witness is a word nobody thought to try.
|
|
7
|
+
*/
|
|
8
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
9
|
+
import { verifyAutomaton } from './automaton.js';
|
|
10
|
+
import { optionRefusal } from './option-shape.js';
|
|
11
|
+
import { renderReportText } from './report-view.js';
|
|
12
|
+
import { reportCard, reportResultView } from './presentation.js';
|
|
13
|
+
export const MODEL_AUTOMATON_TOOL_NAME = 'model_automaton_verify';
|
|
14
|
+
export const modelAutomatonTool = defineTool({
|
|
15
|
+
name: MODEL_AUTOMATON_TOOL_NAME,
|
|
16
|
+
description: 'Decide a finite-word automaton: what it accepts, whether it is empty, whether a state is a trap, and whether its language equals, contains or is contained in another automaton. Use it for a conformance claim - the protocol the code implements against the one the specification draws - where the answer is a word that one machine accepts and the other rejects, not an opinion. ' +
|
|
17
|
+
'Give `other` to compare two automata; `relation` picks equivalent (default), subset (the first is contained in the second) or superset. A failed relation returns the shortest witness word. ' +
|
|
18
|
+
'Determinism, reachability and trap states are reported whether or not `other` is given. ' +
|
|
19
|
+
'It decides finite words over an explicit alphabet. Liveness, fairness, timing and infinite words are out of scope: a Büchi or timed model is a different family, and this tool does not build one. For reachability or deadlock in a single state machine use `model_verify`; for machines that must handshake use `model_compose_verify`.',
|
|
20
|
+
parameters: {
|
|
21
|
+
automaton: {
|
|
22
|
+
type: 'json',
|
|
23
|
+
required: true,
|
|
24
|
+
description: 'The automaton: {states: [ids], alphabet: [symbols], transitions: [{from, symbol, to}], init, accepting: [ids]}. An NFA is accepted and determinised; nondeterminism is reported.',
|
|
25
|
+
},
|
|
26
|
+
other: {
|
|
27
|
+
type: 'json',
|
|
28
|
+
description: 'The automaton to compare against, in the same shape. Omit to check this one on its own.',
|
|
29
|
+
},
|
|
30
|
+
relation: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
enum: ['equivalent', 'subset', 'superset'],
|
|
33
|
+
description: 'Which language relation `other` must stand in. Default equivalent. subset: the first is contained in the second; superset: the second is contained in the first.',
|
|
34
|
+
},
|
|
35
|
+
reportView: {
|
|
36
|
+
type: 'string',
|
|
37
|
+
enum: ['digest', 'full'],
|
|
38
|
+
description: 'digest (default) prints the readable body; full prints the structured result.',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
output: {
|
|
42
|
+
schema: {
|
|
43
|
+
type: 'json',
|
|
44
|
+
description: 'the automaton report: verdict, findings, the witness word when a relation fails, and hashes of the inputs.',
|
|
45
|
+
},
|
|
46
|
+
render(args, value) {
|
|
47
|
+
return [{ type: 'text', text: renderReportText(value, { full: args.reportView === 'full' }) }];
|
|
48
|
+
},
|
|
49
|
+
// The card a UI shows, separated from the text the model reads: a verdict and the first thing wrong,
|
|
50
|
+
// never the whole report.
|
|
51
|
+
presentationMeta(_args, value) {
|
|
52
|
+
return reportCard(value, MODEL_AUTOMATON_TOOL_NAME);
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
presentResult: reportResultView(MODEL_AUTOMATON_TOOL_NAME),
|
|
56
|
+
timeoutMs: 10_000,
|
|
57
|
+
isConcurrencySafe: () => true,
|
|
58
|
+
async execute(args) {
|
|
59
|
+
try {
|
|
60
|
+
return verifyAutomaton(args.automaton, {
|
|
61
|
+
...(args.other === undefined ? {} : { other: args.other }),
|
|
62
|
+
...(args.relation === undefined ? {} : { relation: args.relation }),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return optionRefusal(error, 'AUTOMATON_OPTION_INVALID');
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
});
|