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
|
@@ -9,22 +9,24 @@ For an unverified design, failure is only a matter of time. Complex code becomes
|
|
|
9
9
|
|
|
10
10
|
## When This Skill Applies
|
|
11
11
|
|
|
12
|
-
**This is the entry point.**
|
|
12
|
+
**This is the entry point.** Load this skill when a claim about the code has to be settled and a reading will not settle it. It owns the doctrine: enumerate the claims, verify each against the code, cite `file:line`, read `verdict`. It also owns the executable verification for behaviour. A neighbouring domain goes to its own skill through the routing table below.
|
|
13
|
+
|
|
14
|
+
**It decides small models, not programs.** The engine enumerates states, so a model that explodes is reported `truncated` with the undecided check named. That is not a bug to retry with a larger `maxStates`: reduce the model first (drop variables the property does not read, collapse symmetric states), and if it still explodes the property needs a tool that does not enumerate - SPIN for partial-order reduction, NuSMV for symbolic search, CBMC for bounded SAT. This plugin builds no abstraction and reads no program source.
|
|
15
|
+
|
|
16
|
+
**This costs more than reading, and less the larger the task.** On a fixture of a few hundred lines it costs several times a plain reading, because the fixed cost has nothing to amortise against. On a tree of tens of thousands of lines the ratio falls to roughly parity. Spend it where the object is large enough for one decision to replace many reads. Reach for it when the claim is about all paths rather than one, when nothing in the repository will go red if it is false, or when the verdict has to be reproducible later. A claim one reading settles belongs in a sentence, not in a model.
|
|
13
17
|
|
|
14
18
|
| The task involves… | What it does |
|
|
15
19
|
|---|---|
|
|
16
|
-
| Any claim about code
|
|
17
|
-
| A state machine or protocol
|
|
18
|
-
| A quantitative or temporal guarantee
|
|
19
|
-
| A handshake or power-up
|
|
20
|
-
| A refactoring that changes state topology or
|
|
21
|
-
|
|
|
22
|
-
| An architecture or dependency question about a component
|
|
23
|
-
| Whether a design keeps its own declarations
|
|
24
|
-
|
|
25
|
-
**Catalog budget**: DSH renders only the frontmatter `description`, and truncates it at 500 characters (`dsh-tool-skill`, `DEFAULT_CATALOG_DESCRIPTION_MAX_LENGTH`). Every description in this plugin is written to fit that budget, and the triggers that do not fit live in this table. `tests/skills/run.mjs` fails when any skill's catalog line would be cut, or would lose one of its use-case triggers.
|
|
20
|
+
| Any claim about code: design doc, spec, plan, review comment, README, commit message, refactor proposal, "this is safe", "this always holds", "this can't deadlock" | Enumerate the verifiable claims (Phase 1), verify each with `file:line` evidence (Phase 2), classify the gaps (Phase 3) |
|
|
21
|
+
| A state machine or protocol with three or more states, guards, ACK/NACK/retry, lock/unlock, or start/stop ordering | Build an executable model. Run the S1-S8 structural checks and the A1-A14 adversarial probes |
|
|
22
|
+
| A quantitative or temporal guarantee: worst-case cost within a budget, "90% of runs reach SAFE", "must leave within 2 ticks" | A12 budget, A13 probabilistic reachability, A14 deadlines. Each returns a counterexample path |
|
|
23
|
+
| A handshake or power-up sequence across two or more components | `model_compose_verify`: C1 composition deadlock, C2 rendezvous that never fires |
|
|
24
|
+
| A refactoring that changes state topology or guards | Compare BEFORE and AFTER models for behaviour preservation, invariant continuity and deadlock regression (D1-D4) |
|
|
25
|
+
| An explicit request to prove code correct, verify a module, or check a migration for breakage | Route by domain through [Routing to the Sibling Skills](#routing-to-the-sibling-skills). Keep the doctrine |
|
|
26
|
+
| An architecture or dependency question about a component, package or class diagram | `model-everything-structure`: parse it into a dependency graph, judge every edge against the dependency matrix |
|
|
27
|
+
| Whether a design keeps its own declarations: layering, a responsibility boundary, an interface wider than its callers, a subtype that cannot replace its base | `model-everything-design`: `model_design_review` decides the declared contracts (`DES1`-`DES11`) and reports the graph's shape |
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
**Catalog budget**: DSH renders only the frontmatter `description` and truncates it at 500 characters. Every description here fits. Triggers that do not fit live in this table.
|
|
28
30
|
|
|
29
31
|
## Verification Depth (Plan-Mode Gate)
|
|
30
32
|
|
|
@@ -182,53 +184,23 @@ not a bound on the search.
|
|
|
182
184
|
|
|
183
185
|
### Native dsh Tools
|
|
184
186
|
|
|
185
|
-
|
|
186
|
-
|------|--------|
|
|
187
|
-
| `model_verify` | S1-S8 structural + A1-A14 adversarial, including A12 budget / worst-case path cost, A13 probabilistic reachability over a DTMC, and A14 discrete-tick deadlines. `beforeModel` + `stateMapping` add the D1-D4 before/after regression. |
|
|
188
|
-
| `model_datamodel_verify` | Data models and schema migrations: DS/DA checks plus the DD1-DD4 data regression. See the `model-everything-datamodel` skill. |
|
|
189
|
-
| `model_compose_verify` | Two or more machines checked together (rendezvous handshake semantics): C1 composition deadlock, C2 rendezvous never fires. When `shared` and `accesses` declare a location both machines touch, it also decides the sharing: C3 a declaration that names nothing, C4 an unordered write, C5 a read-modify-write pair the model does not make atomic (the lost update). |
|
|
190
|
-
| `model_interleaving_scan` | Mines claims about how work is executed: threads, synchronization, async, interrupts, shared state. Every finding carries a `family`; async terms (async, await, promise, event loop, callback, and their Chinese counterparts) are in the vocabulary, and an absolute async claim such as "non-blocking" is an error like "thread-safe" is. It routes each claim to the tool that decides it - and for a shared location two machines both update, that tool is `model_compose_verify` (C5), not an external analyzer. It proves nothing itself, and it refuses text it can mine nothing from (`CONCURRENCY_NO_CLAIM`) rather than calling it clean. |
|
|
191
|
-
| `model_export` | Emits external-checker input from a verified model: UPPAAL, TLA+, PRISM, SPIN. |
|
|
192
|
-
| `uml_render` | model → Mermaid/PlantUML source, for any family the notation can draw; a view it cannot draw is refused with the reason. |
|
|
193
|
-
| `uml_parse` | diagram text → the model of the family it declares, so a hand-drawn diagram can be checked. |
|
|
194
|
-
| `uml_review` | audit the modelling: structural defects, documentation gaps and the render-and-read-back fidelity check. |
|
|
195
|
-
| `uml_explain_labels` | print the label and comment contract the parser accepts, for one notation. |
|
|
196
|
-
| `uml_structure_verify` | Reviews a structure diagram as a dependency graph. It reports isolated nodes, dangling endpoints, cycles, disallowed edges, layer violations and missing required edges, and it checks refinement across declared levels. The diagram domain belongs to the `model-everything-structure` skill. |
|
|
197
|
-
| `model_design_review` | Reviews a design: the shape of its dependency graph, and the contracts the design declares about itself. Violations of a declaration decide the verdict; structural facts are reported as signals and never do. A check with nothing to hold the design to is `skip`, not `pass`. The design domain belongs to the `model-everything-design` skill. |
|
|
198
|
-
| `report_diff` | Compares two reports of the same family. A finding's identity is its check, its code and its machine-readable locator, so reworded prose reads as changed rather than new. This is slice acceptance computed instead of eyeballed. |
|
|
199
|
-
|
|
200
|
-
These tools are the engine: every capability this plugin claims is one of the tools above. What is not on that list is out of scope, and the skills name where it is answered instead.
|
|
187
|
+
The tools are `model_verify`, `model_edit`, `model_compose_verify`, `model_datamodel_verify`, `model_design_review`, `model_interleaving_scan`, `model_export`, `report_diff`, `uml_render`, `uml_parse`, `uml_review`, `uml_explain_labels`, `uml_structure_verify` and `model_automaton_verify`. `model_automaton_verify` decides a finite-word language and its relation to another automaton, returning the shortest word that separates them; `references/automata.md` states what each of its checks decides, on what authority, and where it stops. `model_edit` changes a model file by naming the change and returns the structural diff plus the difference in findings, so a fix round costs one call instead of three. `uml_structure_verify` builds its graph from a source tree when given `repoPath`, reading each language's own import construct, so a dependency question about code does not start with drawing. Each tool's description states what it decides and what it does not. Read the description before calling it, and read the report's `verdict` afterwards.
|
|
201
188
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
Every tool report carries the same outcome contract. **`ok` says a report was produced; `verdict` says how the review went.** A report may be `ok: true` and still be a failed review — gating on `ok` is how a failing verification gets read as a passing one.
|
|
189
|
+
A model is the largest argument these tools take. When it is long, or you have edited it more than once, write it to a file and pass `modelPath` instead of inlining it: a streamed argument that long is where invalid JSON comes from, and the file accepts any formatting.
|
|
205
190
|
|
|
206
|
-
|
|
207
|
-
|-------|---------|
|
|
208
|
-
| `schema` | The versioned report contract (`model-everything/verify/v1`, `model-everything/uml/review/v1`, …). Branch on this instead of sniffing fields. |
|
|
209
|
-
| `ran` | The tool executed and produced this report. `false` only when the tool refused the request before running (see `errorCode`/`error`). |
|
|
210
|
-
| `verdict` | `pass` \| `pass_with_findings` \| `fail`. **This is the outcome you act on.** |
|
|
211
|
-
| `verdictReason` | Why, e.g. `2 error finding(s) (first: S2_NO_TRANSITIONS)` or `no error findings; 3 warning finding(s)`. |
|
|
212
|
-
| `findings[]` | `{code, severity, message, detail?, evidence?, path?}`. Any `severity: "error"` forces `verdict: "fail"`. |
|
|
213
|
-
| `hashSpec` | Which published model-hash specification `modelHash` follows — see `references/hash-spec.md`. |
|
|
214
|
-
| `hashes` | Every hash the report carries, in one place (a model hash, a diagram hash, before/after hashes). |
|
|
215
|
-
| `nextSteps[]` | What to do next, derived from the findings; never empty, and identical for two runs over the same input. |
|
|
216
|
-
| `metadataKeys[]` | Paths of the `_`-prefixed annotation keys the schema ignored, e.g. `["_source", "_verified", "states[0]._note"]` (present only when the input carried any). |
|
|
217
|
-
| `narrativeCoverage` | `{states: "5/5", events: "3/9", scenarios: "0/12"}` when the model carries a narrative — a partial narrative is valid, and this is how much is still undocumented. The gap is also a `NARRATIVE_PARTIAL` (info) finding, so a gate can read it without parsing `nextSteps` text. |
|
|
191
|
+
These tools carry every capability this plugin claims. Anything outside them is out of scope, and the skills name where that claim is answered instead.
|
|
218
192
|
|
|
219
|
-
|
|
193
|
+
### Reading a Report: `ok` Is Not a Verdict
|
|
220
194
|
|
|
221
|
-
|
|
195
|
+
**`ok` records that a report was produced. `verdict` records how the review went.** A report can carry `ok: true` and still be a failed review. Gate on `verdict`.
|
|
222
196
|
|
|
223
|
-
- `
|
|
224
|
-
- `
|
|
225
|
-
- `
|
|
197
|
+
- `pass`: no error and no warning. Report the result as verified, together with the scope the model covered.
|
|
198
|
+
- `pass_with_findings`: verification ran clean and warnings exist. Report the pass and the warnings. Do not restate it as "no issues".
|
|
199
|
+
- `fail`: an error finding exists, or the engine rejected the input (`MODEL_INVALID`). State that the claim is not verified, quote the counterexample path, then propose a correction. Do not describe a `fail` as a successful run.
|
|
226
200
|
|
|
227
|
-
|
|
201
|
+
`summary.truncated: true` and any code ending in `_UNDECIDED` both mean the search stopped before deciding. Name the invariant that went undecided and report the property as undecided.
|
|
228
202
|
|
|
229
|
-
`
|
|
230
|
-
stopped before deciding. That is **not** a pass: name the invariant that went undecided,
|
|
231
|
-
and say the property is undecided rather than reading the silence as success.
|
|
203
|
+
A tool prints a readable body. Passing checks stay in the `CHECKS` inventory line, and a fact that several checks report appears once. Only error findings inline their evidence. When the body truncates a check, pass `check: "<id>"` to print that check in full. `reportView: "full"` returns the whole report as compact JSON. Use it only to hand the report to `report_diff`; it costs the most tokens of any request you can make.
|
|
232
204
|
|
|
233
205
|
### Writing the Answer: Name the Finding, Not Its Code
|
|
234
206
|
|
|
@@ -315,24 +287,24 @@ Run these FIRST. They establish basic well-formedness before adversarial probing
|
|
|
315
287
|
|
|
316
288
|
### Phase 2b: Adversarial Probes
|
|
317
289
|
|
|
318
|
-
Run these
|
|
290
|
+
Run these second. Each probe tries to break the model, and a probe that finds a violation proves a behaviour gap.
|
|
319
291
|
|
|
320
|
-
| # | Attack | Method |
|
|
292
|
+
| # | Attack | Method | Claim it refutes |
|
|
321
293
|
|:--:|--------|--------|-------------|
|
|
322
|
-
| A1 | **Unexpected event** |
|
|
323
|
-
| A2 | **Race interleaving** |
|
|
324
|
-
| A3 | **Order permutation** |
|
|
325
|
-
| A4 | **Pair symmetry** | Match every `start/stop`, `lock/unlock`, `alloc/free` pair.
|
|
326
|
-
| A5 | **Boundary blast** | Probe counters at 0, 1, max-1, max
|
|
327
|
-
| A6 | **Resource injection** | Simulate `malloc
|
|
328
|
-
| A7 | **Counter-example witness** | For
|
|
329
|
-
| A8 | **Idempotent replay** |
|
|
330
|
-
| A9 | **Leads-to** | From a declared source state, every path must
|
|
331
|
-
| A10 | **Sequence order** |
|
|
332
|
-
| A11 | **Atomicity** |
|
|
333
|
-
| A12 | **Budget
|
|
334
|
-
| A13 | **Probability reachability
|
|
335
|
-
| A14 | **Deadline
|
|
294
|
+
| A1 | **Unexpected event** | Inject every event E into every state S that has no transition for (S, E). Record whether the model ignores it or crashes. | "All events are handled in all states" |
|
|
295
|
+
| A2 | **Race interleaving** | Deliver every pair of concurrent events in both orders. Report a differing terminal state. | "Behaviour is independent of ordering" |
|
|
296
|
+
| A3 | **Order permutation** | Permute N independent events. Report differing final states or broken invariants. | "Outcome is order-independent" |
|
|
297
|
+
| A4 | **Pair symmetry** | Match every `start/stop`, `lock/unlock`, `alloc/free` pair. Report a path where a pair is unbalanced. `onEntry` and `onExit` count as acquire and release. | "Resources are always released" |
|
|
298
|
+
| A5 | **Boundary blast** | Probe counters at 0, 1, max-1, max and max+1, and timestamps at 0 and wraparound. Report overflow, underflow or undefined behaviour. | "Handles all counter and timer values" |
|
|
299
|
+
| A6 | **Resource injection** | Simulate `malloc` returning NULL, a full queue and a semaphore timeout at each state that calls them. Report a state with no recovery path. | "Degrades gracefully under resource pressure" |
|
|
300
|
+
| A7 | **Counter-example witness** | For a failing invariant, emit the exact violating sequence. The breadth-first searches (state, sequence, atomicity, budget) return the shortest witness. Leads-to and probability return the witness they found without claiming minimality. | "This invariant holds" |
|
|
301
|
+
| A8 | **Idempotent replay** | Apply each `idempotentEvents` entry twice from every reachable state. Report a second application that changes state. | "This event is safe to replay" |
|
|
302
|
+
| A9 | **Leads-to** | From a declared source state, every path must reach the target state or a member of the declared target set. | "Always progresses to completion" |
|
|
303
|
+
| A10 | **Sequence order** | Declared events must occur in the declared order. | "backup before modify before commit" |
|
|
304
|
+
| A11 | **Atomicity** | An atomic event must commit or roll back before the scope is left or the machine terminates. | "all-or-nothing" |
|
|
305
|
+
| A12 | **Budget** | With `cost` per transition (absent means 1) and a `budget` invariant, every reachable path must stay within budget. The probe returns the shortest over-budget path and reports reachable positive-cost cycles as unbounded. | "Worst case fits the budget" |
|
|
306
|
+
| A13 | **Probability reachability** | With `weight` per transition (absent means 1) and a `probability` invariant, P(ever hitting the target) must meet the bound, by value iteration over the absorbing chain. | "90% of runs reach SAFE" |
|
|
307
|
+
| A14 | **Deadline** | State `maxTicks` plus top-level `tickEvents`. A tick step must not keep a state resident past its deadline. The probe returns the over-residency path. | "Must leave within 2 ticks" |
|
|
336
308
|
|
|
337
309
|
### Integration Back to Phase 3
|
|
338
310
|
|
|
@@ -469,14 +441,14 @@ If you catch yourself thinking any of these, stop:
|
|
|
469
441
|
|
|
470
442
|
## Rules
|
|
471
443
|
|
|
472
|
-
1.
|
|
473
|
-
2.
|
|
474
|
-
3. Cite evidence
|
|
475
|
-
4.
|
|
476
|
-
5.
|
|
477
|
-
6.
|
|
478
|
-
7.
|
|
479
|
-
8.
|
|
480
|
-
9.
|
|
481
|
-
10.
|
|
482
|
-
11.
|
|
444
|
+
1. Verify a document's claim against the code before you trust it.
|
|
445
|
+
2. State mechanism boundaries plainly. When the language standard cannot do the thing, say so.
|
|
446
|
+
3. Cite evidence as `file:line`.
|
|
447
|
+
4. Point the way during review. Implementation happens after approval.
|
|
448
|
+
5. Verify behavioural claims by running code. A plan that says "always", "never" or "guaranteed" gets a model, and one counterexample refutes a universal claim.
|
|
449
|
+
6. Confirm the model before you run it, unless this session already told you to proceed. Extraction errors are the dominant failure mode of formal verification. In auto mode, extract with cited evidence, validate the round trip, and mark the report `UNCONFIRMED`.
|
|
450
|
+
7. Cite the existing check instead of re-verifying it. Compile-time assertions, static analysis and runtime checks already settle that property.
|
|
451
|
+
8. Hand a neighbouring domain to its own skill. A diagram is a model, and auditing one belongs to `model-everything-uml`. A concurrency claim is mined and routed by `model-everything-interleaving`. Schema, data invariants and migrations belong to `model-everything-datamodel`. This skill keeps the doctrine and the behavioural checks.
|
|
452
|
+
9. Say what this does not prove. Hard real time, preemptive concurrency, hybrid-control stability, probabilistic reliability and execution-cost budgets go to the tool named in `references/gap-routing-guide.md`. `model_verify` reports carry the same routing as `coverageNotes`.
|
|
453
|
+
10. A declared range is a property, not a bound. `inc` and `dec` are never clamped; only a guard pins the value. A `truncated` report or an `_UNDECIDED` check means the property is undecided. Report it that way.
|
|
454
|
+
11. Write-site analysis is out of scope. "Only the ISR writes this flag" is a question about source code. `model_interleaving_scan` routes it. Neither the model nor the diagram settles it.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Automata as a verification target
|
|
2
|
+
|
|
3
|
+
What `model_automaton_verify` decides, why each decision is a theorem rather than a heuristic, and where
|
|
4
|
+
the boundary sits. Read it when a report has to be defended, or when a question lands on the edge:
|
|
5
|
+
liveness, infinite words, or a product that will not finish.
|
|
6
|
+
|
|
7
|
+
## Scope
|
|
8
|
+
|
|
9
|
+
Finite words over an explicit alphabet. A run starts at `init`, reads one symbol per transition, and is
|
|
10
|
+
accepted if it ends in `accepting`.
|
|
11
|
+
|
|
12
|
+
Not in scope, and the report says so:
|
|
13
|
+
|
|
14
|
+
- liveness, fairness, "eventually" properties on an infinite run;
|
|
15
|
+
- timing, clocks, deadlines;
|
|
16
|
+
- conformance by observation rather than by language;
|
|
17
|
+
- any abstraction. The tool reads a model, never program source.
|
|
18
|
+
|
|
19
|
+
## What each check decides, and on what authority
|
|
20
|
+
|
|
21
|
+
| Check | Decision | Authority |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `AUT003` nondeterminism | whether some state has two transitions on one symbol | the definition of a deterministic automaton |
|
|
24
|
+
| `AUT001` unreachable | whether a state is reachable from `init` | reachability is decidable in linear space |
|
|
25
|
+
| `AUT002` trap | whether a reachable state can still reach acceptance | the same reachability, run backwards |
|
|
26
|
+
| `AUT004` empty language | whether any accepting state is reachable | emptiness of a finite automaton is decidable |
|
|
27
|
+
| `AUT005` alphabet mismatch | whether the two machines can be compared at all | a language relation needs one alphabet |
|
|
28
|
+
| `AUT006` equivalence | whether two machines accept the same words | decide `L(A) \ L(B)` and `L(B) \ L(A)` |
|
|
29
|
+
| `AUT007` subset | whether every word of the first is a word of the second | decide `L(A) \ L(B)` |
|
|
30
|
+
| `AUT008` superset | the same, with the sides exchanged | decide `L(B) \ L(A)` |
|
|
31
|
+
| `AUT009` undecided | the product search stopped at its cap | a stopped search proves nothing |
|
|
32
|
+
|
|
33
|
+
Equivalence and inclusion are decided by exploring the product of the two automata and asking whether an
|
|
34
|
+
accepting side pairs with a rejecting one. A breadth-first walk returns the **shortest** word that does,
|
|
35
|
+
so the witness is the smallest counterexample there is, not merely one that exists.
|
|
36
|
+
|
|
37
|
+
## The wall, stated plainly
|
|
38
|
+
|
|
39
|
+
These are decidable problems, not approximations: automaton equivalence is NL-complete, inclusion for
|
|
40
|
+
nondeterministic machines and LTL model checking are PSPACE-complete. The cost is what grows, not the
|
|
41
|
+
certainty. Two machines of `n` states each can produce `n × n` pairs, and a model with counters or
|
|
42
|
+
queues in it can be unbounded before anyone writes a single transition.
|
|
43
|
+
|
|
44
|
+
So a cap is honest and a larger cap is not a strategy. When the product stops, the report carries
|
|
45
|
+
`AUT009_UNDECIDED` and sets `truncated: true`: the verdict is "not known", never "equal". If the same
|
|
46
|
+
happens to a state machine in `model_verify`, the report names the escalation instead of suggesting a
|
|
47
|
+
bigger budget.
|
|
48
|
+
|
|
49
|
+
## Reading, by what each one settles
|
|
50
|
+
|
|
51
|
+
Foundations, for the constructions above:
|
|
52
|
+
|
|
53
|
+
- Hopcroft, Motwani, Ullman, *Introduction to Automata Theory, Languages, and Computation* — subset
|
|
54
|
+
construction, product automata, the equivalence test.
|
|
55
|
+
- Sipser, *Introduction to the Theory of Computation* — closure properties and decidability, in the
|
|
56
|
+
gentler telling.
|
|
57
|
+
|
|
58
|
+
Model checking, which is where liveness lives and this family stops:
|
|
59
|
+
|
|
60
|
+
- Baier and Katoen, *Principles of Model Checking* — LTL, CTL, Büchi automata, fairness. The boundary in
|
|
61
|
+
the scope section above is this book's first half.
|
|
62
|
+
- Clarke, Grumberg, Peled, *Model Checking* — the classical account, including why explicit enumeration
|
|
63
|
+
runs out.
|
|
64
|
+
|
|
65
|
+
The automata-theoretic framing this tool is a finite-word shadow of:
|
|
66
|
+
|
|
67
|
+
- Kurshan, *Computer-Aided Verification of Coordinating Processes* — systems as automata, properties as
|
|
68
|
+
automata, language inclusion as the decision procedure.
|
|
69
|
+
- Vardi and Wolper, *An automata-theoretic approach to automatic program verification* — the same idea
|
|
70
|
+
for LTL, with Büchi acceptance.
|
|
71
|
+
|
|
72
|
+
Conformance, for what "implementation matches specification" means when it is made precise:
|
|
73
|
+
|
|
74
|
+
- Tretmans, *Model Based Testing with Labelled Transition Systems* — `ioco` and the family of
|
|
75
|
+
implementation relations; `subset` and `superset` are the language-level versions of that choice.
|
|
76
|
+
- Lynch and Vaandrager, *Forward and backward simulations* — refinement in two directions, which is
|
|
77
|
+
exactly the difference between asking `subset` and asking `superset`.
|
|
78
|
+
|
|
79
|
+
## What a pass does not mean
|
|
80
|
+
|
|
81
|
+
A passing report says the stated words are accepted or rejected as claimed. It does not say the model is
|
|
82
|
+
the system: the alphabet is whatever the modeller wrote, and a property that needs a symbol nobody
|
|
83
|
+
declared cannot be seen. State the alphabet next to the claim, or the verdict is about a machine that
|
|
84
|
+
exists only in the report.
|
|
85
|
+
|
|
86
|
+
## Provenance
|
|
87
|
+
|
|
88
|
+
Which parts are borrowed, and which are this repository's own decisions. A check that came from a
|
|
89
|
+
textbook is cited so a reader can check the argument; a choice that is not in any book is marked as one.
|
|
90
|
+
|
|
91
|
+
| Part | Where it comes from |
|
|
92
|
+
|---|---|
|
|
93
|
+
| subset construction for determinisation | Hopcroft, Motwani and Ullman |
|
|
94
|
+
| deciding equivalence and inclusion on the product | Hopcroft, Motwani and Ullman; Kurshan for the framing |
|
|
95
|
+
| the shortest-witness search | breadth-first search on the product; the choice to return the shortest word is this repository's |
|
|
96
|
+
| the check codes and their grouping | this repository's convention, shared with the other families |
|
|
97
|
+
| `truncated` and the `_UNDECIDED` suffix | this repository's convention: a stopped search is not a pass |
|
|
98
|
+
| the cap on the product | this repository's decision, and a practical one, not a theoretical boundary |
|
|
99
|
+
| `subset` and `superset` as the two refinements | Tretmans; Lynch and Vaandrager |
|
|
100
|
+
|
|
101
|
+
The theory above decides the checks. Nothing in this family is a heuristic dressed as a decision: every
|
|
102
|
+
code either proves a property or says it could not.
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
# Model Everything —— 并发类断言
|
|
2
|
-
|
|
3
|
-
这项技能**不**证明并发安全,它产出的任何报告都不该被读成证明。它在文档、计划或代码评审里挖出关于**工作怎样被执行**的断言——线程、同步原语、异步任务、中断、共享状态——把每一条标成 `UNVERIFIED`,再转给真正能判定它的工具。
|
|
4
|
-
|
|
5
|
-
它继承的断言核验教义——枚举可核验的断言、给出 `file:line`、读 `verdict` 而不读 `ok`——在 `model-everything` 技能里。当任务是状态机的行为核验、而不是对并发断言下判断时,加载那一份。
|
|
6
|
-
|
|
7
|
-
English: [SKILL.md](SKILL.md)
|
|
8
|
-
|
|
9
|
-
## 什么时候适用
|
|
10
|
-
|
|
11
|
-
**先确认目标真的有并发需求或并发行为**——多线程、异步任务、中断、共享状态、并行执行。目标如果是纯顺序的,就不要启用并发挖掘:那里没有东西可挖。
|
|
12
|
-
|
|
13
|
-
异步也算并发,而且是最常被漏掉的那一种:单线程事件循环照样在交错执行,下面每一条失败模式都适用于它。
|
|
14
|
-
|
|
15
|
-
| 断言 | 怎么处理 |
|
|
16
|
-
|---|---|
|
|
17
|
-
| 绝对式:「thread-safe」「lock-free」「no data race」「interrupt-safe」「ISR-safe」 | error / `UNVERIFIED`,除非给出专门的证据 |
|
|
18
|
-
| 绝对式(异步):「non-blocking」「never blocks」「no blocking」 | error / `UNVERIFIED` —— 事件循环是共享资源,而这句断言是无条件的 |
|
|
19
|
-
| 风险关键词:「race condition」「shared variable」「mutex」「atomic」「shared memory」「critical section」、`ISR`、`IRQ`、`NMI`、`disable_irq` / `enable_irq` | warning —— 检查计划是否真的处理了它 |
|
|
20
|
-
| 异步关键词:「async」「await」「promise」「event loop」「callback」「microtask」「coroutine」「fire-and-forget」「backpressure」 | warning —— 要审的是交错,不是词汇 |
|
|
21
|
-
| lock/unlock、alloc/free、start/stop 这类顺序敏感的配对 | 转给 `model_verify`(A4 配对对称性),它能在被建模的机器上判定是否平衡 |
|
|
22
|
-
|
|
23
|
-
在 DSH 里跑 `model_interleaving_scan` 工具。人工审查请照 [`references/concurrency-risk-guide.md`](references/concurrency-risk-guide.md)。
|
|
24
|
-
|
|
25
|
-
## 路由:每条断言由什么来判定
|
|
26
|
-
|
|
27
|
-
挖出一条断言不等于核验了它。把每一条交给能判定的工具:
|
|
28
|
-
|
|
29
|
-
| 维度 | 判定它的工具 |
|
|
30
|
-
|---|---|
|
|
31
|
-
| 数据竞争、加锁顺序、无锁算法 | ThreadSanitizer、Helgrind,或在真实代码上的模型检查器(CBMC) |
|
|
32
|
-
| 中断/ISR 竞争、临界区 | 具备 RTOS 感知的中断分析,或 ISR 与任务交错顺序的 TLA+ 模型 |
|
|
33
|
-
| 离散事件之间的协议级交错 | `model_verify`(S1-S8 / A1-A14)与 `model_compose_verify`(C1/C2) |
|
|
34
|
-
| 异步任务交错、丢失唤醒、永不发生的握手 | TLA+(由 `model_export` 导出),或两任务情形用 `model_compose_verify` |
|
|
35
|
-
| 两个任务都更新的同一个共享位置(丢更新、无序写) | 用 `shared` + `accesses` 调 `model_compose_verify`:C5 报出模型没有做成原子的读-改-写对,C4 报无序写,C3 报指向不存在对象的声明。两侧点名同一把锁的会被排除,报告会数出来 |
|
|
36
|
-
| 超时、截止期、可能永远不来的回调 | 带 `maxTicks` + `tickEvents` 的 `model_verify`,或 `model_export` → UPPAAL(时钟) |
|
|
37
|
-
| 异步处理器里的阻塞调用、漏掉的 `await`、没人接的 promise | **这里判不了。** 需要运行时或静态检查(事件循环阻塞检测、调用路径的 lint/评审)——说出那个检查名字,绝不要说设计是干净的 |
|
|
38
|
-
| 硬实时:截止期、周期、抢占 | 调度分析(RMA/EDF)与计时工具 —— 不是本工具箱 |
|
|
39
|
-
| 概率或可靠性断言 | PRISM/Storm、故障树分析 |
|
|
40
|
-
|
|
41
|
-
完整路由表(含硬实时、混合控制与执行成本三个维度)在 [`../model-everything/references/gap-routing-guide.md`](../model-everything/references/gap-routing-guide.md)。`model_verify` 的报告会在匹配的模型上,以 informational 的 `coverageNotes` 带上同样的路由。
|
|
42
|
-
|
|
43
|
-
## 异步审查看不到什么
|
|
44
|
-
|
|
45
|
-
异步的缺陷藏在模型表达不了的地方,所以报告必须说出来,而不是暗示自己覆盖了:
|
|
46
|
-
|
|
47
|
-
1. **异步处理器里的阻塞调用。** 模型没有时钟也没有运行时,它分不出同步读取和 `await` 过的读取。「这个处理器是非阻塞的」需要运行时检查(事件循环延迟、阻塞检测器),不是一次扫描。
|
|
48
|
-
2. **漏掉的 `await`。** 那是一个不存在的转移,照着计划建出来的模型会忠实地漏掉它。静态审查调用路径才能抓到;扫描只告诉你该去哪里看。
|
|
49
|
-
3. **跨 `await` 持有的锁。** 扫描器能在同一页上看到 `mutex` 和 `await`,看不出它们重叠。如果这个位置真要较真,就在 `shared` 里声明它、在 `accesses` 里声明两侧:模型没做成原子时 `model_compose_verify` 会报 C5,并数出被命名锁排除掉的对数。锁是否真的在整个操作期间持有,仍是 `model_verify` 的单机问题。
|
|
50
|
-
|
|
51
|
-
这三处都是「没有发现」和「没有问题」不同的地方。说清楚你查了哪一个、用什么查的。
|
|
52
|
-
|
|
53
|
-
## 本模式的规则
|
|
54
|
-
|
|
55
|
-
1. **挖,不是证——除了被声明的共享位置。** 并发断言报成 `UNVERIFIED` 并给出路由目标;永远不要报成通过。唯一的例外是两个模型都碰的那个位置:把 `shared` 与 `accesses` 交给 `model_compose_verify`,它判 C3/C4/C5,你要引用它的 verdict 与见证,而不是把断言说成未核验。
|
|
56
|
-
2. **答案里不许出现绝对语气。**「这是线程安全的」正是被挖的那条断言,不是这项技能能产出的结果。
|
|
57
|
-
3. **一个反例就足以推翻。** 若怀疑存在竞争,交付物是能打破它的那个交错序列,以及把它演出来的 harness(TSan/Helgrind 的输出),而不是一段论证。
|
|
58
|
-
4. **纯顺序的目标不在范围内。** 如果没有东西并发运行,说出来并停下。单线程的异步服务不是纯顺序的:每一个 `await` 处都存在交错。
|
|
59
|
-
5. **扫描器是 `model_interleaving_scan`。** 如果本部署没有注册它,就照上面的关键词表人工挖文本,并按同样的方式路由每一条断言。
|
|
60
|
-
6. **用文字说出断言和它的路由。**「QoS 1 只投递一次」加上判定它的工具,绝不是一个光秃秃的检查项名字。没背下本技能表格的读者,从一串枚举里学不到任何东西。完整规则在 `model_verify` 技能的「Writing the Answer」一节。
|
|
1
|
+
# Model Everything —— 并发类断言
|
|
2
|
+
|
|
3
|
+
这项技能**不**证明并发安全,它产出的任何报告都不该被读成证明。它在文档、计划或代码评审里挖出关于**工作怎样被执行**的断言——线程、同步原语、异步任务、中断、共享状态——把每一条标成 `UNVERIFIED`,再转给真正能判定它的工具。
|
|
4
|
+
|
|
5
|
+
它继承的断言核验教义——枚举可核验的断言、给出 `file:line`、读 `verdict` 而不读 `ok`——在 `model-everything` 技能里。当任务是状态机的行为核验、而不是对并发断言下判断时,加载那一份。
|
|
6
|
+
|
|
7
|
+
English: [SKILL.md](SKILL.md)
|
|
8
|
+
|
|
9
|
+
## 什么时候适用
|
|
10
|
+
|
|
11
|
+
**先确认目标真的有并发需求或并发行为**——多线程、异步任务、中断、共享状态、并行执行。目标如果是纯顺序的,就不要启用并发挖掘:那里没有东西可挖。
|
|
12
|
+
|
|
13
|
+
异步也算并发,而且是最常被漏掉的那一种:单线程事件循环照样在交错执行,下面每一条失败模式都适用于它。
|
|
14
|
+
|
|
15
|
+
| 断言 | 怎么处理 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| 绝对式:「thread-safe」「lock-free」「no data race」「interrupt-safe」「ISR-safe」 | error / `UNVERIFIED`,除非给出专门的证据 |
|
|
18
|
+
| 绝对式(异步):「non-blocking」「never blocks」「no blocking」 | error / `UNVERIFIED` —— 事件循环是共享资源,而这句断言是无条件的 |
|
|
19
|
+
| 风险关键词:「race condition」「shared variable」「mutex」「atomic」「shared memory」「critical section」、`ISR`、`IRQ`、`NMI`、`disable_irq` / `enable_irq` | warning —— 检查计划是否真的处理了它 |
|
|
20
|
+
| 异步关键词:「async」「await」「promise」「event loop」「callback」「microtask」「coroutine」「fire-and-forget」「backpressure」 | warning —— 要审的是交错,不是词汇 |
|
|
21
|
+
| lock/unlock、alloc/free、start/stop 这类顺序敏感的配对 | 转给 `model_verify`(A4 配对对称性),它能在被建模的机器上判定是否平衡 |
|
|
22
|
+
|
|
23
|
+
在 DSH 里跑 `model_interleaving_scan` 工具。人工审查请照 [`references/concurrency-risk-guide.md`](references/concurrency-risk-guide.md)。
|
|
24
|
+
|
|
25
|
+
## 路由:每条断言由什么来判定
|
|
26
|
+
|
|
27
|
+
挖出一条断言不等于核验了它。把每一条交给能判定的工具:
|
|
28
|
+
|
|
29
|
+
| 维度 | 判定它的工具 |
|
|
30
|
+
|---|---|
|
|
31
|
+
| 数据竞争、加锁顺序、无锁算法 | ThreadSanitizer、Helgrind,或在真实代码上的模型检查器(CBMC) |
|
|
32
|
+
| 中断/ISR 竞争、临界区 | 具备 RTOS 感知的中断分析,或 ISR 与任务交错顺序的 TLA+ 模型 |
|
|
33
|
+
| 离散事件之间的协议级交错 | `model_verify`(S1-S8 / A1-A14)与 `model_compose_verify`(C1/C2) |
|
|
34
|
+
| 异步任务交错、丢失唤醒、永不发生的握手 | TLA+(由 `model_export` 导出),或两任务情形用 `model_compose_verify` |
|
|
35
|
+
| 两个任务都更新的同一个共享位置(丢更新、无序写) | 用 `shared` + `accesses` 调 `model_compose_verify`:C5 报出模型没有做成原子的读-改-写对,C4 报无序写,C3 报指向不存在对象的声明。两侧点名同一把锁的会被排除,报告会数出来 |
|
|
36
|
+
| 超时、截止期、可能永远不来的回调 | 带 `maxTicks` + `tickEvents` 的 `model_verify`,或 `model_export` → UPPAAL(时钟) |
|
|
37
|
+
| 异步处理器里的阻塞调用、漏掉的 `await`、没人接的 promise | **这里判不了。** 需要运行时或静态检查(事件循环阻塞检测、调用路径的 lint/评审)——说出那个检查名字,绝不要说设计是干净的 |
|
|
38
|
+
| 硬实时:截止期、周期、抢占 | 调度分析(RMA/EDF)与计时工具 —— 不是本工具箱 |
|
|
39
|
+
| 概率或可靠性断言 | PRISM/Storm、故障树分析 |
|
|
40
|
+
|
|
41
|
+
完整路由表(含硬实时、混合控制与执行成本三个维度)在 [`../model-everything/references/gap-routing-guide.md`](../model-everything/references/gap-routing-guide.md)。`model_verify` 的报告会在匹配的模型上,以 informational 的 `coverageNotes` 带上同样的路由。
|
|
42
|
+
|
|
43
|
+
## 异步审查看不到什么
|
|
44
|
+
|
|
45
|
+
异步的缺陷藏在模型表达不了的地方,所以报告必须说出来,而不是暗示自己覆盖了:
|
|
46
|
+
|
|
47
|
+
1. **异步处理器里的阻塞调用。** 模型没有时钟也没有运行时,它分不出同步读取和 `await` 过的读取。「这个处理器是非阻塞的」需要运行时检查(事件循环延迟、阻塞检测器),不是一次扫描。
|
|
48
|
+
2. **漏掉的 `await`。** 那是一个不存在的转移,照着计划建出来的模型会忠实地漏掉它。静态审查调用路径才能抓到;扫描只告诉你该去哪里看。
|
|
49
|
+
3. **跨 `await` 持有的锁。** 扫描器能在同一页上看到 `mutex` 和 `await`,看不出它们重叠。如果这个位置真要较真,就在 `shared` 里声明它、在 `accesses` 里声明两侧:模型没做成原子时 `model_compose_verify` 会报 C5,并数出被命名锁排除掉的对数。锁是否真的在整个操作期间持有,仍是 `model_verify` 的单机问题。
|
|
50
|
+
|
|
51
|
+
这三处都是「没有发现」和「没有问题」不同的地方。说清楚你查了哪一个、用什么查的。
|
|
52
|
+
|
|
53
|
+
## 本模式的规则
|
|
54
|
+
|
|
55
|
+
1. **挖,不是证——除了被声明的共享位置。** 并发断言报成 `UNVERIFIED` 并给出路由目标;永远不要报成通过。唯一的例外是两个模型都碰的那个位置:把 `shared` 与 `accesses` 交给 `model_compose_verify`,它判 C3/C4/C5,你要引用它的 verdict 与见证,而不是把断言说成未核验。
|
|
56
|
+
2. **答案里不许出现绝对语气。**「这是线程安全的」正是被挖的那条断言,不是这项技能能产出的结果。
|
|
57
|
+
3. **一个反例就足以推翻。** 若怀疑存在竞争,交付物是能打破它的那个交错序列,以及把它演出来的 harness(TSan/Helgrind 的输出),而不是一段论证。
|
|
58
|
+
4. **纯顺序的目标不在范围内。** 如果没有东西并发运行,说出来并停下。单线程的异步服务不是纯顺序的:每一个 `await` 处都存在交错。
|
|
59
|
+
5. **扫描器是 `model_interleaving_scan`。** 如果本部署没有注册它,就照上面的关键词表人工挖文本,并按同样的方式路由每一条断言。
|
|
60
|
+
6. **用文字说出断言和它的路由。**「QoS 1 只投递一次」加上判定它的工具,绝不是一个光秃秃的检查项名字。没背下本技能表格的读者,从一串枚举里学不到任何东西。完整规则在 `model_verify` 技能的「Writing the Answer」一节。
|