dsh-logicprobe 0.9.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.en-US.md +128 -66
  2. package/README.md +128 -66
  3. package/lib/baseline.js +142 -0
  4. package/lib/client.js +56 -1
  5. package/lib/compose-tool.js +1 -1
  6. package/lib/concurrency.js +14 -0
  7. package/lib/data-engine.js +42 -8
  8. package/lib/engine.js +3151 -2801
  9. package/lib/export-tool.js +27 -2
  10. package/lib/granularity.js +237 -0
  11. package/lib/index.js +63 -41
  12. package/lib/report-diff-tool.js +39 -0
  13. package/lib/structure-tool.js +64 -0
  14. package/lib/structure.js +648 -0
  15. package/lib/tool.js +3 -3
  16. package/lib/types/baseline.d.ts +69 -0
  17. package/lib/types/concurrency.d.ts +10 -0
  18. package/lib/types/data-engine.d.ts +13 -1
  19. package/lib/types/engine.d.ts +419 -277
  20. package/lib/types/granularity.d.ts +106 -0
  21. package/lib/types/index.d.ts +9 -8
  22. package/lib/types/report-diff-tool.d.ts +8 -0
  23. package/lib/types/structure-tool.d.ts +10 -0
  24. package/lib/types/structure.d.ts +156 -0
  25. package/lib/types/tool.d.ts +2 -2
  26. package/lib/types/uml.d.ts +89 -0
  27. package/lib/uml-tool.js +146 -104
  28. package/lib/uml.js +1748 -1544
  29. package/locale/en.json +6 -0
  30. package/locale/zh.json +6 -0
  31. package/package.json +16 -14
  32. package/skills/logicprobe/SKILL.md +84 -58
  33. package/skills/logicprobe/references/dsh-model-schema.md +102 -10
  34. package/skills/logicprobe/references/gap-routing-guide.md +37 -36
  35. package/skills/logicprobe/references/hash-spec.md +153 -0
  36. package/skills/logicprobe/references/logic-verification-guide.md +27 -250
  37. package/skills/logicprobe-concurrency/SKILL.md +43 -0
  38. package/skills/{logicprobe → logicprobe-concurrency}/references/concurrency-risk-guide.md +1 -1
  39. package/skills/logicprobe-datamodel/SKILL.md +5 -4
  40. package/skills/logicprobe-datamodel/references/data-model-guide.md +1 -1
  41. package/skills/logicprobe-datamodel/references/data-model-schema.md +1 -1
  42. package/skills/logicprobe-structure/SKILL.md +95 -0
  43. package/skills/logicprobe-structure/references/structure-review-guide.md +177 -0
  44. package/skills/logicprobe-uml/SKILL.md +57 -0
  45. package/skills/{logicprobe → logicprobe-uml}/references/uml-modeling-guide.md +121 -8
  46. package/src/baseline.ts +180 -0
  47. package/src/client.js +56 -1
  48. package/src/compose-tool.ts +47 -47
  49. package/src/concurrency.ts +23 -0
  50. package/src/data-engine.ts +51 -9
  51. package/src/engine.ts +503 -72
  52. package/src/export-tool.ts +73 -48
  53. package/src/granularity.ts +312 -0
  54. package/src/index.ts +63 -41
  55. package/src/report-diff-tool.ts +43 -0
  56. package/src/structure-tool.ts +68 -0
  57. package/src/structure.ts +724 -0
  58. package/src/tool.ts +3 -3
  59. package/src/uml-tool.ts +53 -10
  60. package/src/uml.ts +288 -24
  61. package/skills/logicprobe/references/logicprobe-engine.py +0 -4943
  62. package/skills/logicprobe/references/verification-harness.py +0 -959
  63. package/skills/logicprobe-datamodel/references/data-model-harness.py +0 -528
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Logic Probe",
4
+ "description": "Verifies claims about designs and code. Facts go against the source. Behaviour goes through an executable model."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "逻辑探针",
4
+ "description": "核验设计与代码里的声称:事实类对着源码查,行为类跑可执行模型。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-logicprobe",
3
- "version": "0.9.0",
4
- "description": "Design document & plan claim verification — enumerate claims, verify against codebase facts, then escalate to state-machine verification (S1-S8/A1-A12, including budget/worst-case path-cost checks) and data-model verification (DS/DA/DD) for behavioral claims. Supports before/after regression, idempotency/monotonic/sequence/leads-to/atomicity constraints, and concurrency risk mining. Ships a native DeepSeek Harness (dsh) bundle that injects the claim-verification gate into the first model step.",
3
+ "version": "1.1.0",
4
+ "description": "Verifies claims about designs and code. Facts go against the source. Behaviour goes through an executable model: state machines, protocols, composition, data models, migrations. Structure diagrams are read as dependency graphs, at one level or several. Two reports can be compared for regression. Exports UPPAAL, TLA+, PRISM and SPIN input. Ships a native DeepSeek Harness bundle that injects the verification gate into the first model step.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -12,13 +12,15 @@
12
12
  },
13
13
  "./cordis.patch.yml": "./cordis.patch.yml",
14
14
  "./client": "./lib/client.js",
15
- "./package.json": "./package.json"
15
+ "./package.json": "./package.json",
16
+ "./locale/*.json": "./locale/*.json"
16
17
  },
17
18
  "files": [
18
19
  "lib",
19
20
  "src",
20
21
  "skills",
21
- "cordis.patch.yml"
22
+ "cordis.patch.yml",
23
+ "locale"
22
24
  ],
23
25
  "dsh": {
24
26
  "engines": {
@@ -38,7 +40,7 @@
38
40
  ]
39
41
  },
40
42
  "compatibility": {
41
- "dsh": "^0.1.0-rc.7 || ^0.1.1-rc.1 || ^0.1.2-alpha.2 || ^0.1.2-alpha.3 || ^0.1.2-alpha.4 || ^0.1.2-alpha.5 || ^0.1.2-rc.1 || ^0.1.3-alpha.1 || ^0.1.3-alpha.2 || ^0.1.5-alpha.1 || ^0.1.5-rc.1 || ^0.1.5-alpha.2 || ^0.1.5-rc.2 || ^0.1.5-rc.3 || ^0.1.6-alpha.1 || ^0.1.6-alpha.2 || ^0.1.7-alpha.1 || ^0.1.7-alpha.2 || ^0.1.7-rc.1 || ^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
43
+ "dsh": "^0.1.0-rc.7 || ^0.1.1-rc.1 || ^0.1.2-alpha.2 || ^0.1.2-alpha.3 || ^0.1.2-alpha.4 || ^0.1.2-alpha.5 || ^0.1.2-rc.1 || ^0.1.3-alpha.1 || ^0.1.3-alpha.2 || ^0.1.5-alpha.1 || ^0.1.5-rc.1 || ^0.1.5-alpha.2 || ^0.1.5-rc.2 || ^0.1.5-rc.3 || ^0.1.6-alpha.1 || ^0.1.6-alpha.2 || ^0.1.7-alpha.1 || ^0.1.7-alpha.2 || ^0.1.7-rc.1 || ^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2",
42
44
  "dshReleases": {
43
45
  "0.1.0-rc.7": "compatible",
44
46
  "0.1.0-rc.8": "compatible",
@@ -64,7 +66,8 @@
64
66
  "0.1.7-rc.2": "compatible",
65
67
  "0.2.0-rc.1": "compatible",
66
68
  "0.2.0-rc.2": "compatible",
67
- "0.2.1-alpha.1": "compatible"
69
+ "0.2.1-alpha.1": "compatible",
70
+ "0.2.1-alpha.2": "compatible"
68
71
  },
69
72
  "profiles": [
70
73
  "headless",
@@ -76,17 +79,17 @@
76
79
  "build": "tsc -p tsconfig.json && node scripts/build-client.mjs",
77
80
  "typecheck": "tsc -p tsconfig.json --noEmit",
78
81
  "bump": "node scripts/bump-version.mjs",
79
- "test:engine": "npm run build && node tests/engine/run.mjs && node tests/data-engine/run.mjs && node tests/concurrency/run.mjs && node tests/uml/run.mjs && node tests/apply-smoke.mjs && node tests/dsh-client-half.test.mjs && node tests/dsh-volatile-fallback.test.mjs && node tests/exporters/run.mjs && node tests/external/run.mjs && node tests/python/run.mjs",
82
+ "test:engine": "npm run build && node tests/engine/run.mjs && node tests/data-engine/run.mjs && node tests/concurrency/run.mjs && node tests/uml/run.mjs && node tests/apply-smoke.mjs && node tests/dsh-client-half.test.mjs && node tests/dsh-volatile-fallback.test.mjs && node tests/claude-session-start-hook.test.mjs && node tests/skills/run.mjs && node tests/structure/run.mjs && node tests/baseline/run.mjs && node tests/granularity/run.mjs && node tests/exporters/run.mjs && node tests/external/run.mjs && node tests/python/run.mjs",
80
83
  "test:full": "npm run build && node tests/full-suite.mjs",
81
84
  "test:python": "npm run build && node tests/python/run.mjs"
82
85
  },
83
86
  "peerDependencies": {
84
87
  "@deepseek-ai/cordis": "^4.0.4",
85
- "@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
86
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
87
- "@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
88
- "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
89
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1",
88
+ "@deepseek-ai/dsh-agent": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2",
89
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2",
90
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2",
91
+ "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8 || ^0.2.0-rc.1 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2",
92
+ "@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-alpha.1 || ^0.2.1-alpha.2",
90
93
  "@deepseek-ai/schemastery": "^3.18.4"
91
94
  },
92
95
  "devDependencies": {
@@ -104,11 +107,10 @@
104
107
  "@deepseek-ai/dsh-skill": "^0.2.0-rc.2",
105
108
  "@deepseek-ai/dsh-skill-filesystem": "^0.2.0-rc.2",
106
109
  "@deepseek-ai/dsh-system-prompt": "^0.2.0-rc.2",
107
- "@deepseek-ai/dsh-timeout": "^0.2.0-rc.2",
108
110
  "@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
109
111
  "@deepseek-ai/dsh-user-approval": "^0.2.0-rc.2",
110
112
  "@deepseek-ai/schemastery": "^3.18.4",
111
- "@types/node": "^26.6.3",
113
+ "@types/node": "^26.6.4",
112
114
  "typescript": "^7.0.2"
113
115
  },
114
116
  "author": {
@@ -1,11 +1,27 @@
1
1
  ---
2
2
  name: logicprobe
3
- description: "Use when reviewing design documents, architecture specs, technical proposals, or refactoring plans that make claims about API names, file locations, enum values, or mechanism feasibility. Escalate into logic-primitive verification — generate and run an executable model before trusting the claim — when the document asserts state-machine or protocol behaviour (≥3 states, ACK/NACK/retry sequences, guards, lock/unlock pairing), a quantitative or temporal guarantee (worst-case path cost ≤ budget, P(reach SAFE) ≥ p, 'must leave within 2 ticks'), a cross-machine handshake (req/ack, power-up sequencing between two components), concurrency guarantees ('thread-safe', 'lock-free', 'ISR-safe' — mined and routed, never proven here), or a refactoring that changes state topology or guard conditions, where the pipeline compares before/after models for behavioral preservation and regression freedom. ALSO use when the task is to model a code flow as UML, or to audit a diagram somebody drew: the skill renders the model as a state, activity or sequence diagram, reads a hand-drawn diagram back into a model, and reviews the modelling — unreachable states, dead ends, ambiguous branches, documentation gaps, diagram-versus-model round-trip fidelity. Data-model, schema and migration claims belong to the sibling logicprobe-datamodel skill. ALSO proactively SUGGEST this skill (do not require) when a user asks code-level behavioral questions — 'check this timing for bugs', 'could this state machine deadlock', 'is this retry limit safe' — since plan-level verification has usually already been done."
3
+ description: "Use when you want to verify something about code: a design doc, spec, plan, review comment, README or refactor asserting API names, paths, enums, feasibility, state-machine or protocol behaviour, timing guarantees, or 'always/never' properties. Enumerates the claims, verifies each against the code (file:line), and escalates to executable model checks (S1-S8 + A1-A14) when behaviour is at stake. Diagrams: logicprobe-uml; concurrency: logicprobe-concurrency; data: logicprobe-datamodel."
4
4
  ---
5
5
 
6
6
  # Logic Probe
7
7
 
8
- Documents are not truth — code is. Verify every verifiable claim before accepting or acting on any design.
8
+ For an unverified design, failure is only a matter of time. Complex code becomes clear once you model it and run it. Check every claim before you act on it.
9
+
10
+ ## When This Skill Applies
11
+
12
+ **This is the entry point.** If you have any thought of checking whether something about the code is actually true — however small, however informal the claim — load this skill. It owns the doctrine (enumerate the claims, verify each against the code, cite `file:line`, read `verdict` and never `ok`) and the executable verification for behaviour. When the task lands in a neighbouring domain, its routing table below hands it over rather than stretching the doctrine to cover it.
13
+
14
+ | The task involves… | What it does |
15
+ |---|---|
16
+ | Any claim about code you want to check — a design doc, spec, plan, review comment, README, commit message, refactor proposal, or a "this is safe / this always holds / this can't deadlock" assertion | Enumerate the verifiable claims (Phase 1), verify each against the codebase with `file:line` evidence (Phase 2), classify the gaps (Phase 3) |
17
+ | A state machine or protocol — ≥3 states, guards, ACK/NACK/retry, lock/unlock, start/stop ordering | Build an executable model: S1-S8 structural checks, A1-A14 adversarial probes |
18
+ | A quantitative or temporal guarantee — worst-case path cost ≤ budget, "≥90% of runs reach SAFE", "must leave within 2 ticks" | A12 budget, A13 probabilistic reachability, A14 deadlines, each with a counterexample path |
19
+ | A handshake or power-up sequencing across two or more components | `logicprobe_compose_verify`: C1 composition deadlock, C2 rendezvous that never fires |
20
+ | A refactoring that changes state topology or guard conditions | BEFORE/AFTER models compared for behavioral preservation, invariant continuity and deadlock regression (D1-D4) |
21
+ | Explicit request to prove code correct, formally verify a module, or check a migration for breakage | Route by domain — the table under [Routing to the Sibling Skills](#routing-to-the-sibling-skills) — and keep the doctrine |
22
+ | An architecture or dependency question about a component/package/class diagram | `logicprobe-structure`: parse the diagram into a dependency graph and judge every edge against the dependency matrix |
23
+
24
+ **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.
9
25
 
10
26
  <HARD-GATE>
11
27
 
@@ -131,9 +147,7 @@ When Phase 2 triggers escalation, do NOT proceed to Phase 3 until the verificati
131
147
  ```text
132
148
  Document claims → Extract model → Runtime check:
133
149
  ├── DSH + `logicprobe_verify` tool available → build Model schema v1 (references/dsh-model-schema.md) → call the tool → structured report
134
- ├── Python available + LogicModelV1 JSON at hand → references/logicprobe-engine.py verify model.json (S1-S8/A1-A14/D1-D4; subcommands compose / export add C1-C2 and UPPAAL/TLA+/PRISM/SPIN output)
135
- ├── Python available + model only as extracted dicts → fill in references/verification-harness.py → run → report
136
- └── No Python → Manual Verification Mode (see references/logic-verification-guide.md#manual-verification-mode)
150
+ └── No engine available → Manual Verification Mode (see references/logic-verification-guide.md#manual-verification-mode)
137
151
 
138
152
  Refactoring variant:
139
153
  Old code + Refactoring plan → Extract BEFORE model + AFTER model
@@ -156,9 +170,59 @@ UML modelling variant (the task is to draw a flow, not to check a claim):
156
170
  | `logicprobe_compose_verify` | Two or more machines checked together (rendezvous handshake semantics): C1 composition deadlock, C2 rendezvous never fires. |
157
171
  | `logicprobe_concurrency_scan` | Mines concurrency claims (thread-safe, lock-free, race condition, mutex, ISR-safe) and routes them to dedicated verification. It does not prove concurrency safety. |
158
172
  | `logicprobe_export` | Emits external-checker input from a verified model: UPPAAL, TLA+, PRISM, SPIN. |
159
- | `logicprobe_uml` | render / parse / review for UML modelling — see [UML Modelling and Modelling Review](#uml-modelling-and-modelling-review). |
173
+ | `logicprobe_uml` | render / parse / review / explain-labels for UML modelling — the diagram domain belongs to the `logicprobe-uml` skill. |
174
+
175
+ The repository engine mirrors the same checks and carries the `compose` and `export` subcommands for hosts without the native tools.
176
+
177
+ ### Reading a Report: `ok` Is Not a Verdict
178
+
179
+ 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.
180
+
181
+ | Field | Meaning |
182
+ |-------|---------|
183
+ | `schema` | The versioned report contract (`logicprobe/verify/v1`, `logicprobe/uml/review/v1`, …). Branch on this instead of sniffing fields. |
184
+ | `ran` | The tool executed and produced this report. `false` only when the tool refused the request before running (see `errorCode`/`error`). |
185
+ | `verdict` | `pass` \| `pass_with_findings` \| `fail`. **This is the outcome you act on.** |
186
+ | `verdictReason` | Why, e.g. `2 error finding(s) (first: S2_NO_TRANSITIONS)` or `no error findings; 3 warning finding(s)`. |
187
+ | `findings[]` | `{code, severity, message, detail?, evidence?, path?}`. Any `severity: "error"` forces `verdict: "fail"`. |
188
+ | `hashSpec` | Which published model-hash specification `modelHash` follows — see `references/hash-spec.md`. |
189
+ | `hashes` | Every hash the report carries, in one place (a model hash, a diagram hash, before/after hashes). |
190
+ | `nextSteps[]` | What to do next, derived from the findings; never empty, and identical for two runs over the same input. |
191
+ | `metadataKeys[]` | Paths of the `_`-prefixed annotation keys the schema ignored, e.g. `["_source", "_verified", "states[0]._note"]` (present only when the input carried any). |
192
+ | `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. |
193
+
194
+ Turn the verdict into an answer, never into a summary of `ok`:
160
195
 
161
- `references/logicprobe-engine.py` mirrors the same checks and carries `compose` and `export` subcommands for hosts without the native tools.
196
+ - `verdict: "pass"` — no error and no warning finding. Safe to report as verified, still with the scope the model covered.
197
+ - `verdict: "pass_with_findings"` — verification ran clean, but warnings exist (e.g. `S5` implicit-ignore events, `UML012_NO_TERMINAL`). Report the pass **and** the warnings; do not silently upgrade it to "no issues".
198
+ - `verdict: "fail"` — an error-severity finding exists, or the input was rejected (`MODEL_INVALID`). Say plainly that the claim is **not** verified, quote the counterexample path the finding carries, and only then propose a correction. Never describe a `fail` as "the tool ran successfully".
199
+
200
+ Exit codes: `0` for `pass` / `pass_with_findings`, `2` for `fail`, a refusal, or an unreadable input. In DSH the native tools return the report as data — read `verdict`, and treat `errorCode`/`error` as the refusal path.
201
+
202
+ ### Slice Acceptance: Baseline Diffs
203
+
204
+ The acceptance criterion for a refactoring slice is usually "no **new** findings", not
205
+ "zero findings". Do not compare two JSON reports by eye — run the comparison:
206
+
207
+ - DSH: `logicprobe_report_diff { baseline: <earlier report>, current: <new report> }`
208
+ - Any host without the tools: run the repository engine against the same JSON.
209
+ (also available on `compose`, `structure` and `uml-review`)
210
+
211
+ A finding's identity is its **check id + code + canonical locator** (built from
212
+ `evidence`/`path`; the message only when a finding carries neither), so a reworded
213
+ message reads as `changed`, never as a new finding. The diff's `verdict` describes the
214
+ **delta** — a newly added error finding fails it — while `currentVerdict` keeps the
215
+ absolute result visible, and a clean delta over a still-failing report says so in
216
+ `nextSteps` rather than passing quietly. Two runs over the same input add zero findings:
217
+ run that self-check before trusting any baseline.
218
+
219
+ ### Archiving a Model: `_`-Prefixed Metadata
220
+
221
+ Keep provenance with the model instead of in a sidecar that drifts:
222
+
223
+ - Any key starting with `_` at any level (`_source`, `_verified`, `_uml`, `_extraction_caveats`, `states[0]._note`) is **annotation metadata**: the schema ignores it, `modelHash` excludes it, and the report echoes it as `metadataKeys`.
224
+ - Everything else stays closed — a mistyped `sttes` is still a validation error, and that is deliberate.
225
+ - Because the hash ignores `_` keys, "the model as archived" and "the model with metadata stripped" hash identically; record the reported `hashSpec` next to the hash so a later reader can reproduce it (`verify model.json --hash-check <hex>` answers whether a recorded hash belongs to a published spec at all).
162
226
 
163
227
  ### Refactoring Verification Mode
164
228
 
@@ -182,15 +246,7 @@ When the document under review is a refactoring plan (modifying existing state m
182
246
 
183
247
  6. **Flag any behavioral delta not documented in the plan** — the most common refactoring bug is an unintended side effect that the plan doesn't acknowledge
184
248
 
185
- **Detection step**: Before generating any verification code, run `python3 --version 2>&1` or `python --version 2>&1`. Check the output:
186
-
187
- - Returns `Python 3.x.y` with x ≥ 6 → use Python harness
188
- - Returns anything else (command not found, "Python was not found" Windows stub, version < 3.6) → fall back to Manual Verification Mode
189
- - On Windows, if `python` launches the Microsoft Store, treat as unavailable
190
-
191
- Do NOT attempt to install Python — the user's embedded development machine may be air-gapped or locked down.
192
-
193
- In DSH, prefer the native `logicprobe_verify` tool (model JSON, structured guard DSL, path-aware invariants) — see `references/dsh-model-schema.md`. For non-DSH hosts: when the model is already a LogicModelV1 JSON, run the standalone JSON engine `references/logicprobe-engine.py` (verify | compose | export — an exact Python mirror of the DSH tools, cross-checked byte-for-byte by tests/python/run.mjs); when the model exists only as extracted dicts, fill in the reusable template `references/verification-harness.py`. For detailed probe patterns, model extraction methodology, and manual verification procedures, load `references/logic-verification-guide.md`.
249
+ Run the checks with the native `logicprobe_verify` tool (model JSON, structured guard DSL, path-aware invariants) — see `references/dsh-model-schema.md`. A host without the tools can run the repository engine against the same JSON. For probe patterns, extraction methodology and manual procedures, load `references/logic-verification-guide.md`.
194
250
 
195
251
  ### Phase 2a: Structural Primitives (8 Checks)
196
252
 
@@ -325,35 +381,6 @@ If the user says yes, extract the model from the existing code (not a plan docum
325
381
 
326
382
  This covers the gap where behavioral verification is useful even when no design document is being reviewed.
327
383
 
328
- ## UML Modelling and Modelling Review
329
-
330
- Use this when the task is to **draw** a code flow rather than to check a claim. Typical cases are reverse-engineering a handler, documenting a protocol exchange, and auditing a diagram somebody else drew.
331
-
332
- A diagram is a model, and a model can be wrong. A tidy flow chart is not evidence about the code. A diagram that disagrees with its own model is worse than no diagram, because a reader will believe it.
333
-
334
- Pipeline (DSH):
335
-
336
- ```text
337
- code flow → model (citation per element) → logicprobe_uml action=render → diagram source
338
- → logicprobe_uml action=review → modelling findings + round-trip fidelity
339
- → logicprobe_verify → behaviour (S1-S8 structural, A1-A14 adversarial)
340
- ```
341
-
342
- - **render** — model to diagram. Mermaid covers `state`, `activity` and `sequence`. PlantUML covers `state` and `sequence`. Any construct the notation cannot carry becomes a warning, never a silent drop. PlantUML activity is refused instead of approximated.
343
- - **parse** — diagram to model. It reads Mermaid and PlantUML state or activity text, so a hand-drawn diagram can be verified like any other model. A sequence diagram is refused, because a trace cannot reconstruct a machine.
344
- - **review** — it answers one of three questions. Give it a model: is the machine well-modelled? Give it a diagram: what does the diagram say? Give it both: does the diagram match the model?
345
-
346
- The review reports structural defects and documentation gaps. The structural defects are unreachable states, dead ends, ambiguous or non-exhaustive branches, self-loops with no exit, and duplicate transitions. The documentation gaps are a missing narrative, unbounded variables, states the reader cannot map back to code, and label drift. It also runs the fidelity check. Any structural difference between the diagram and its model is `UML017_ROUND_TRIP_MISMATCH`.
347
-
348
- Rules for this mode:
349
-
350
- 1. **A diagram is not evidence.** Every state, event, guard and action needs a citation. Use `file:line` for code and a section reference for a document. Present the citations with the diagram.
351
- 2. **Review before you present.** Run `logicprobe_uml action=review` and fix the error findings first. An ambiguous or dead-ended diagram misleads every later reader.
352
- 3. **The review never replaces verification.** It covers the modelling. S1-S8 and A1-A14 cover the behaviour, and each finding names the check that settles it.
353
- 4. **Keep the narrative with the model.** Write `narrative.states`, `narrative.events` and `narrative.scenarios`. Then the diagram stays readable against the code, and label drift shows up as a finding instead of as a stale picture.
354
-
355
- The full checklist (codes `UML001` to `UML019`), the directive format generated diagrams carry, a worked example, and the limits of each view are in `references/uml-modeling-guide.md`.
356
-
357
384
  ### When NOT to Escalate
358
385
 
359
386
  Skip logic-primitive verification when:
@@ -362,19 +389,16 @@ Skip logic-primitive verification when:
362
389
  - The state machine has ≤2 states, no guards, and trivial transitions (IDLE↔ACTIVE)
363
390
  - The claim is purely structural (file paths, type names, numeric constants) — Phase 2 grep verification is sufficient
364
391
 
365
- ## Concurrency Risk Mining
366
-
367
- **Only use this after confirming the verification target actually has concurrency requirements or behavior** — e.g., multiple threads, async tasks, interrupts, shared state, or parallel execution. If the target is purely sequential, do not invoke concurrency mining.
368
-
369
- logicprobe does **not** prove concurrency safety. It mines documents and plans for concurrency-related claims and flags them for dedicated verification.
370
-
371
- - Absolute claims ("thread-safe", "lock-free", "no data race") → error / `UNVERIFIED` unless dedicated evidence is provided.
372
- - Risk keywords ("race condition", "shared variable", "mutex", "atomic", "shared memory") → warning; review whether the plan addresses them.
373
- - Interrupt safety is included: `interrupt-safe` / `ISR-safe` are absolute claims; `ISR`, `IRQ`, `NMI`, `critical section`, `disable_irq` / `enable_irq` are risk keywords.
392
+ ### Routing to the Sibling Skills
374
393
 
375
- In DSH, use the `logicprobe_concurrency_scan` tool. For manual review, follow `references/concurrency-risk-guide.md`.
394
+ This skill owns behavioural claims. Three neighbouring domains have their own skill, and loading the wrong one wastes the verification:
376
395
 
377
- For routing claims in dimensions logicprobe does not verify — hard real time (deadlines/periods), preemptive concurrency, hybrid control stability, probabilistic reliability, and execution-cost budgets — to dedicated tools, see `references/gap-routing-guide.md`. In `logicprobe_verify` reports, matching models carry informational `coverageNotes` with the same routing.
396
+ | Domain | Skill |
397
+ |---|---|
398
+ | Drawing a code flow as UML, or auditing a diagram somebody drew (render / parse / review / explain-labels, round-trip fidelity, component and class diagrams refused) | `logicprobe-uml` |
399
+ | Reviewing architecture, module structure or a dependency diagram (isolated nodes, dangling endpoints, cycles, allowed-dependency and layer violations, missing required edges) | `logicprobe-structure` |
400
+ | Concurrency claims — "thread-safe", "lock-free", "no data race", "ISR-safe" — mined and routed to TSan/Helgrind/CBMC/TLA+, never proven here | `logicprobe-concurrency` |
401
+ | Entities, fields, relationships, data invariants, schema migrations (DS1-DS4, DA1-DA12, DD1-DD4) | `logicprobe-datamodel` |
378
402
 
379
403
  ---
380
404
 
@@ -386,5 +410,7 @@ For routing claims in dimensions logicprobe does not verify — hard real time (
386
410
  4. Don't fix during review — point the way, let implementation happen after approval.
387
411
  5. **For behavioral claims: verify with code, not reasoning.** If a plan says "always", "never", or "guaranteed", generate and run a model. One counter-example is enough to refute a universal claim.
388
412
  6. **Confirm the model before running it** — unless the runtime reports `logicprobe interaction=auto`. Extraction errors are the dominant failure mode of formal verification. In auto mode, substitute evidence-cited extraction + round-trip validation and mark the report `UNCONFIRMED`.
389
- 7. **Don't verify what the code already checks.** If the existing codebase has compile-time assertions, static analysis, or runtime checks for a property, cite those — don't re-verify in a Python model.
390
- 8. **A diagram is a model, not evidence.** When you model a code flow as UML, cite the source for every state, event, guard and action. Run `logicprobe_uml` with `action=review` before you show the diagram. A diagram that does not read back as the model it was drawn from is mis-modelled, however tidy it looks.
413
+ 7. **Don't verify what the code already checks.** If the existing codebase has compile-time assertions, static analysis, or runtime checks for a property, cite those — don't re-verify in a model.
414
+ 8. **Hand a neighbouring domain to its own skill.** A diagram is a model, not evidence: modelling or auditing one belongs to `logicprobe-uml`. A concurrency claim is mined and routed, never proven here: that is `logicprobe-concurrency`. Schema, data invariants and migrations are `logicprobe-datamodel`. This skill keeps the doctrine and the behavioural checks.
415
+ 9. **Say what this does not prove.** For dimensions logicprobe does not verify — hard real time (deadlines, periods), preemptive concurrency, hybrid-control stability, probabilistic reliability, execution-cost budgets — route to the dedicated tool named in `references/gap-routing-guide.md`. `logicprobe_verify` reports carry the same routing as informational `coverageNotes` on matching models.
416
+ 10. **Write-site analysis is out of scope, and stays there.** "Only the ISR writes this flag", "one owner per register" — logicprobe verifies models and diagrams, not *who writes what in the source*. That claim needs a source-side AST/rule check or a static analyzer; this plugin's contribution is to flag the claim as unverified and route it (`logicprobe_concurrency_scan` does exactly that). Do not imply the diagram or the model settled it.
@@ -56,6 +56,67 @@ Declared keys per part:
56
56
 
57
57
  `boundaryChecks` is the one place where two schemas share a field name: `logicprobe_verify` uses `{ variable, values }` (a variable's boundary values for A5), while `logicprobe_datamodel_verify` uses `{ entity, field, values }` (a field's boundary values for DA2). Each validator enforces its own shape, so an `(entity, field)` check passed to the state-machine engine is rejected rather than half-understood.
58
58
 
59
+ ### `_`-prefixed keys are annotation metadata (the one exception)
60
+
61
+ A key whose name starts with `_` is **not** part of the model. At any level — on the
62
+ model, a state, a transition, inside `narrative` — the schema skips it, the hash ignores
63
+ it, and the report lists it under `metadataKeys`:
64
+
65
+ ```json
66
+ {
67
+ "schemaVersion": 1,
68
+ "init": "IDLE",
69
+ "states": [{ "id": "IDLE", "_note": "power-on, not ready" }],
70
+ "_source": "docs/uml/order-service.model.json",
71
+ "_verified": { "modelHash": "0000000000000000…", "at": "2026-10-09" },
72
+ "_extraction_caveats": ["guard thresholds read from the ISR, not the task"]
73
+ }
74
+ ```
75
+
76
+ ```json
77
+ "metadataKeys": ["_extraction_caveats", "_source", "_verified", "states[0]._note"]
78
+ ```
79
+
80
+ The list echoes *this input*, it is not a memory: a `_` key the current object does not
81
+ carry is absent, even if an earlier version of the file had it. Nested keys are spelled
82
+ the way the walker sees them (`states[0]._note`, `invariants[0]._probe`,
83
+ `transitions[0]._why`), and the field is absent entirely when the input carries no `_`
84
+ key at all. Read it as "what this run ignored", never as "what this model has ever
85
+ recorded".
86
+
87
+ Why it exists: provenance, verification snapshots and extraction caveats belong *with*
88
+ the model. Pushed into a sidecar they drift away from it — nobody can say which hash
89
+ belongs to which note. With this exemption the archive record travels inside the file
90
+ and still cannot change the model's identity: `modelHash` excludes `_` keys, so the
91
+ model as archived and the model with the metadata stripped hash identically.
92
+
93
+ The exemption is namespaced, not a loosening of the closed schema. `_` keys are never
94
+ *read* by any check, so ignoring them cannot produce a false result; a mistyped
95
+ non-prefixed key (`sttes`, `gaurd`, `maximum`) is still a validation error, which is
96
+ the whole point of the closed schema.
97
+
98
+ ### Reading a report: `ran`, `verdict`, `ok`
99
+
100
+ `logicprobe_verify` (and `logicprobe_compose_verify`) reports separate "the tool ran"
101
+ from "the review passed":
102
+
103
+ | Field | Meaning |
104
+ |---|---|
105
+ | `schema` | The versioned report contract, e.g. `logicprobe/verify/v1` — branch on this instead of sniffing fields. |
106
+ | `ok` | The engine produced a report. For `verify` this is `false` only when model *validation* failed. It is **not** a verdict. |
107
+ | `ran` | The tool executed. `false` only for a tool-level refusal (`errorCode`/`error` present). |
108
+ | `verdict` | `pass` \| `pass_with_findings` \| `fail`. Any `severity: "error"` finding — or a validation failure — makes this `fail`. |
109
+ | `verdictReason` | e.g. `1 error finding(s) (first: S2_NO_TRANSITIONS)`, `no error findings; 3 warning finding(s)`, `no error or warning findings`. |
110
+ | `hashSpec` | The published hash specification `modelHash` follows — see [hash-spec.md](hash-spec.md). |
111
+ | `hashes` | Every hash the report carries, in one place (`modelHash`, `beforeModelHash`/`afterModelHash` for a comparison). |
112
+ | `metadataKeys` | Present only when the input carried `_` keys (see above). |
113
+ | `narrativeCoverage` | Present only when the input carried a narrative: `covered/total` per dimension. |
114
+ | `nextSteps` | What to do next, derived from the findings; never empty, and identical for two runs over the same model. |
115
+
116
+ A caller that reads `ok` sees `true` for a model with a deadlock; the verdict is what
117
+ says so. Report the verdict, quote the counterexample path from the finding, and never
118
+ describe a `fail` as "the tool ran fine".
119
+
59
120
  ### References must resolve
60
121
 
61
122
  The same reasoning applies to every id a check names. A reference to a state, event, or variable that the model does not declare cannot be satisfied, and because the engine copies each check's target into its findings (`"target": "DONE"`), an unresolvable id reads as authoritative in the report:
@@ -105,13 +166,21 @@ so findings can be read against real scenarios instead of bare ids.
105
166
  }
106
167
  ```
107
168
 
108
- **Completeness contract**: when `narrative` is present, all three parts are
109
- required and must fully cover the model — every declared state needs a
110
- `narrative.states` entry, every event used in `transitions` needs a
111
- `narrative.events` entry, and every distinct `(from, event)` group needs a
112
- `narrative.scenarios` entry. Keys must reference declared ids; unknown
113
- references, missing coverage, and duplicate scenario keys are model validation
114
- errors. The report's `narrative` field echoes the block unchanged.
169
+ **Coverage contract**: a narrative may cover **part** of the model — writing the states
170
+ first, then the events, then the scenarios is the natural authoring order, and a partial
171
+ block is valid. What must hold is that whatever is written is *right*:
172
+
173
+ | Case | Result |
174
+ |---|---|
175
+ | `narrative` absent | Valid. The review reports `UML013_NO_NARRATIVE` (info); `logicprobe_verify` reports no coverage at all. |
176
+ | One or two of `states` / `events` / `scenarios` given | Valid. The report adds `narrativeCoverage: {states: "5/5", events: "3/9", scenarios: "0/12"}` (covered/total per dimension), and `nextSteps` names the gap. Both sides also report it as a finding: `logicprobe_verify` carries `NARRATIVE_PARTIAL` (info) and a UML review carries `UML027_NARRATIVE_PARTIAL` (info). An `info` finding never changes `verdict`, `summary.errors`, `summary.warnings` or the check count. |
177
+ | `narrative` present but `{}` | **Error**: an empty block claims documentation that does not exist. Give at least one dimension. |
178
+ | Unknown state/event id, empty description, duplicate `(from, event)` scenario | **Error**: the narrative is wrong, not merely incomplete. |
179
+
180
+ Totals are the model's own: states = declared states, events = distinct transition
181
+ events, scenarios = distinct `(from, event)` groups (so two guarded transitions of one
182
+ event need one scenario, not two). The report's `narrative` field echoes the block
183
+ unchanged.
115
184
 
116
185
  **Presenting the model**: when showing the extracted model for confirmation, render
117
186
  the natural language INLINE in the model presentation, not as a separate block.
@@ -158,6 +227,13 @@ A guard is exactly one of:
158
227
 
159
228
  ## Invariants
160
229
 
230
+ Every invariant carries `id` and **`description`** — both required strings — plus a
231
+ `kind` and that kind's own fields. `description` is not decoration: it is echoed into
232
+ the finding a violation produces, and it takes part in `modelHash`, so a model that
233
+ gains one hashes differently. An invariant without it is rejected with `MODEL_INVALID`,
234
+ and the report's `nextSteps` names the field to add; a `_`-prefixed key is not a
235
+ substitute for it.
236
+
161
237
  | Kind | Shape | Checks |
162
238
  |---|---|---|
163
239
  | `never-states` | `{ states: ["ERROR"] }` | No reachable runtime state may be in the forbidden set |
@@ -250,10 +326,26 @@ Actions never change state or variables. Checks that care about resource discipl
250
326
  Two or more machines can be checked together with `runCompositionVerification` (DSH tool `logicprobe_compose_verify`):
251
327
 
252
328
  - non-rendezvous events advance exactly one firing machine;
253
- - a rendezvous (handshake) event fires only when at least two machines declare it and every such non-terminal machine has it jointly enabled (guards held); participants advance simultaneously;
254
- - a terminal machine is stopped and does not participate.
329
+ - a rendezvous (handshake) event fires only when at least two machines declare it **and** every such non-terminal machine has it jointly enabled (guards held); participants advance simultaneously. A machine whose alphabet does not contain the event does not participate, and a terminal machine is stopped;
330
+ - therefore a machine that is *waiting* for a rendezvous is not blocked from everything else: it may take any number of its own non-rendezvous steps first. That is how different rates are modelled — there is **no rate ratio** and no fairness bound, so "the 1 ms pump runs N times while the ISR waits" is expressed by the pump's own tick event, not by a tempo setting. A bound would only prune interleavings, never add behaviour; if you need to *forbid* a fast machine from overtaking, encode that in the model (a guard on a counter the slow machine resets), not in the composition options.
331
+ - **there is no cross-machine shared state.** Each machine's `variables` are private to
332
+ it: machine A's `ready` and machine B's `ready` are two different
333
+ quantities, and no guard can read another machine's variable. Rendezvous events are
334
+ the *only* coupling between machines. So "two machines must agree on one predicate"
335
+ cannot be modelled by giving each a copy of it — model the shared condition inside a
336
+ single machine, or make the agreement an explicit handshake. The report names the
337
+ variables it saw when two or more machines each declare some, in `nextSteps`.
338
+
339
+ Inputs: the DSH tool takes an array of model objects (an agent reads the files and passes them); the CLI takes any number of files directly — `compose models/*.json --rendezvous req,ack` — so nothing has to be concatenated by hand.
340
+
341
+ ### Reading C1 and C2
342
+
343
+ Both findings carry the *why*, not just the *what*:
344
+
345
+ - **C1_COMPOSITION_DEADLOCK** — the composite state, the number of steps to reach it (**shortest**, because the search is breadth-first), and `evidence.perMachine`: for every machine, its state, whether it is terminal, and every event in its alphabet with a reason — `rendezvous-needs-partner` (fewer than two machines declare it), `rendezvous-partner-not-ready` (a declaring partner is terminal or has no enabled transition), `no-enabled-transition` (guard false or no such transition), or `enabled`. An event this machine can fire on its own is never labelled `enabled` when the handshake itself is missing. In practice a census only ever shows the three blocked reasons: it is emitted only when no machine can move, and "can move" is decided by the same predicate that would label an event `enabled`, so that fourth label is unreachable there. Treat the three observable values as the contract, and keep tolerating the literal.
346
+ - **C2_RENDEZVOUS_NEVER_FIRES** — an **error**, the same severity as C1: a handshake that can never fire leaves the composition unable to advance through it, so a gate that reads only `verdict` stops on it. `evidence.machines` gives, per machine, whether it declares the event, whether it ever had it enabled, and the states where it did. The reason distinguishes "fewer than two machines declare it" from "machine *i* declares it but never enables it".
255
347
 
256
- Checks: `C1_COMPOSITION_DEADLOCK` (a reachable composite state with no move while at least one machine is not terminal) and `C2_RENDEZVOUS_NEVER_FIRES`. This is a product-space BFS, so composite state count is the product of the machines; keep `maxStates` in mind.
348
+ `maxStates` caps the product space, and the cap is **reported, never hidden**: a truncated run cannot claim "no deadlock reachable" (the C1 check detail says so), and a C2 finding gained under truncation carries "may be an artefact of the cap" in its message. Bump `maxStates` before believing a negative result on a large product. Note that a machine with an unbounded counter produces an infinite composite space and will always truncate.
257
349
 
258
350
  ## Minimal example
259
351
 
@@ -1,36 +1,37 @@
1
- # Gap Routing Guide
2
-
3
- logicprobe is a design-time, qualitative model checker. For semantic dimensions it does
4
- not model, it does not stay silent: it routes claims to dedicated tools. This reference
5
- is the routing table shared by the verification report (`coverageNotes`), the
6
- concurrency scanner (`suggestions` on absolute claims), and manual review.
7
-
8
- Routing is a hint, not a proof. A note never verifies the claim — it marks the dimension
9
- as outside this engine and points at tooling that can handle it.
10
-
11
- | Dimension | What logicprobe covers today | Claim examples | Dedicated tooling | Why not here |
12
- |---|---|---|---|---|
13
- | Hard real time (timing) | Order, counts, path budgets (A12); time modeled only as counters + events | "500 ms to SAFE", "no deadline miss", "period ≤ 1 ms" | UPPAAL, IMITATOR (timed automata); binary-level timing analysis for WCET | No clocks, deadlines, or period semantics |
14
- | Preemptive concurrency | Event-order interleavings (A2/A3), resource pairing (A4), idempotent replay (A8) | "thread-safe", "interrupt-safe", "no priority inversion" | TSan/Helgrind (runtime), CBMC (proof), TLA+ (interleaving model), RTOS-aware analysis | Single-threaded event model; no preemption, IRQ nesting, or atomics at instruction level |
15
- | Hybrid control (continuous plant) | Discrete transitions and modes only | "switching is stable", "no chattering", "settling within T" | SpaceEx, Flow* (hybrid reachability), Simulink/Stateflow verification | No continuous dynamics; stability is not expressible |
16
- | Probabilistic / reliability | Qualitative reachability and invariants | "MTBF ≥ X", "failure rate ≤ p", "availability ≥ 99.9%" | PRISM, Storm (stochastic model checking), fault-tree / FMEA | No probability semantics |
17
- | Execution cost / performance | A12 budget checks over declared transition `cost` (absent = 1) | "worst-case dispatch ≤ 100 cycles" | aiT, RapiTime (real WCET at binary level) | `cost` is a modeler label, not measured execution time |
18
- | Multi-machine composition | Single machine verified; cross-machine contract must be documented separately | "A sends E, B always handles E" | CSP (FDR), mCRL2, TLA+ (compositional models) | No composition semantics between machines |
19
- | Nested/hierarchical statecharts | Flat models only; flatten before verification | parent/child states, orthogonal regions | SCXML / Stateflow (native hierarchy) | Flat state list only — flatten manually and re-confirm |
20
-
21
- ## Where the routing surfaces
22
-
23
- - `logicprobe_verify` report: a model whose state/event/action names match the timing,
24
- preemption, hybrid, or probability vocabulary gets informational `coverageNotes`
25
- with the same routing as above.
26
- - A12 advisory: transitions declaring `cost` without a `budget` invariant produce
27
- `A12_COST_WITHOUT_BUDGET`, pointing at the budget check.
28
- - `logicprobe_concurrency_scan`: absolute concurrency claims (thread-safe, lock-free,
29
- interrupt-safe, ...) carry `suggestions` naming dedicated tools.
30
- - Manual review: when reading a plan, match its claims against the table above and
31
- require dedicated evidence before accepting "always"/"never"/"guaranteed" language
32
- - Generators: `exportModel(model, format)` emits native inputs for UPPAAL (.xta + queries),
33
- TLA+ (TLC spec + safety), PRISM (.pm + .pctl), and SPIN (Promela + ltl) from a
34
- LogicModelV1 — v1 translates the core machine (guards/updates/weights; booleans as
35
- integers) and leaves unrepresentable invariants as explicit warnings.
36
- Self-tests: tests/exporters/run.mjs.
1
+ # Gap Routing Guide
2
+
3
+ logicprobe is a design-time, qualitative model checker. For semantic dimensions it does
4
+ not model, it does not stay silent: it routes claims to dedicated tools. This reference
5
+ is the routing table shared by the verification report (`coverageNotes`), the
6
+ concurrency scanner (`suggestions` on absolute claims), and manual review.
7
+
8
+ Routing is a hint, not a proof. A note never verifies the claim — it marks the dimension
9
+ as outside this engine and points at tooling that can handle it.
10
+
11
+ | Dimension | What logicprobe covers today | Claim examples | Dedicated tooling | Why not here |
12
+ |---|---|---|---|---|
13
+ | Hard real time (timing) | Order, counts, path budgets (A12); time modeled only as counters + events | "500 ms to SAFE", "no deadline miss", "period ≤ 1 ms" | UPPAAL, IMITATOR (timed automata); binary-level timing analysis for WCET | No clocks, deadlines, or period semantics |
14
+ | Preemptive concurrency | Event-order interleavings (A2/A3), resource pairing (A4), idempotent replay (A8) | "thread-safe", "interrupt-safe", "no priority inversion" | TSan/Helgrind (runtime), CBMC (proof), TLA+ (interleaving model), RTOS-aware analysis | Single-threaded event model; no preemption, IRQ nesting, or atomics at instruction level |
15
+ | Hybrid control (continuous plant) | Discrete transitions and modes only | "switching is stable", "no chattering", "settling within T" | SpaceEx, Flow* (hybrid reachability), Simulink/Stateflow verification | No continuous dynamics; stability is not expressible |
16
+ | Probabilistic / reliability | Qualitative reachability and invariants | "MTBF ≥ X", "failure rate ≤ p", "availability ≥ 99.9%" | PRISM, Storm (stochastic model checking), fault-tree / FMEA | No probability semantics |
17
+ | Execution cost / performance | A12 budget checks over declared transition `cost` (absent = 1) | "worst-case dispatch ≤ 100 cycles" | aiT, RapiTime (real WCET at binary level) | `cost` is a modeler label, not measured execution time |
18
+ | Multi-machine composition | Single machine verified; cross-machine contract must be documented separately | "A sends E, B always handles E" | CSP (FDR), mCRL2, TLA+ (compositional models) | No composition semantics between machines |
19
+ | Nested/hierarchical statecharts | Flat models only; flatten before verification | parent/child states, orthogonal regions | SCXML / Stateflow (native hierarchy) | Flat state list only — flatten manually and re-confirm |
20
+ | Write-site / single-owner analysis | **Not covered, and not planned.** logicprobe reviews the diagram and the model; it does not read the source to see *who writes* a variable, a register or a field | "only the ISR writes this", "one owner per flag", "no double write to the CAN mailbox" | A source-side AST/rule check (e.g. the project's own include/arch checker), a static analyzer (clang-tidy, PC-lint, Coverity), or a model checker over the real code (CBMC) | It needs the source and a rule table about statements — a different input than a model or a diagram. `logicprobe_concurrency_scan` will flag the *claim* as unverified and route it here, which is the honest part of this plugin's answer |
21
+
22
+ ## Where the routing surfaces
23
+
24
+ - `logicprobe_verify` report: a model whose state/event/action names match the timing,
25
+ preemption, hybrid, or probability vocabulary gets informational `coverageNotes`
26
+ with the same routing as above.
27
+ - A12 advisory: transitions declaring `cost` without a `budget` invariant produce
28
+ `A12_COST_WITHOUT_BUDGET`, pointing at the budget check.
29
+ - `logicprobe_concurrency_scan`: absolute concurrency claims (thread-safe, lock-free,
30
+ interrupt-safe, ...) carry `suggestions` naming dedicated tools.
31
+ - Manual review: when reading a plan, match its claims against the table above and
32
+ require dedicated evidence before accepting "always"/"never"/"guaranteed" language
33
+ - Generators: `exportModel(model, format)` emits native inputs for UPPAAL (.xta + queries),
34
+ TLA+ (TLC spec + safety), PRISM (.pm + .pctl), and SPIN (Promela + ltl) from a
35
+ LogicModelV1 — v1 translates the core machine (guards/updates/weights; booleans as
36
+ integers) and leaves unrepresentable invariants as explicit warnings.
37
+ Self-tests: tests/exporters/run.mjs.