dsh-logicprobe 0.3.1 → 0.5.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 +7 -1
- package/README.md +9 -2
- package/lib/concurrency-tool.js +34 -0
- package/lib/concurrency.js +76 -0
- package/lib/data-engine.js +930 -0
- package/lib/data-tool.js +61 -0
- package/lib/engine.js +1622 -1103
- package/lib/index.js +291 -277
- package/lib/tool.js +57 -45
- package/lib/types/concurrency-tool.d.ts +8 -0
- package/lib/types/concurrency.d.ts +20 -0
- package/lib/types/data-engine.d.ts +199 -0
- package/lib/types/data-tool.d.ts +10 -0
- package/lib/types/engine.d.ts +171 -133
- package/lib/types/tool.d.ts +4 -2
- package/package.json +79 -78
- package/skills/logicprobe/SKILL.md +285 -266
- package/skills/logicprobe/references/__pycache__/verification-harness.cpython-312.pyc +0 -0
- package/skills/logicprobe/references/concurrency-risk-guide.md +54 -0
- package/skills/logicprobe/references/dsh-model-schema.md +145 -104
- package/skills/logicprobe/references/logic-verification-guide.md +463 -413
- package/skills/logicprobe/references/verification-harness.py +806 -582
- package/skills/logicprobe-datamodel/SKILL.md +124 -0
- package/skills/logicprobe-datamodel/references/__pycache__/data-model-harness.cpython-312.pyc +0 -0
- package/skills/logicprobe-datamodel/references/data-model-guide.md +62 -0
- package/skills/logicprobe-datamodel/references/data-model-harness.py +528 -0
- package/skills/logicprobe-datamodel/references/data-model-schema.md +128 -0
- package/src/concurrency-tool.ts +37 -0
- package/src/concurrency.ts +102 -0
- package/src/data-engine.ts +1001 -0
- package/src/data-tool.ts +65 -0
- package/src/engine.ts +533 -0
- package/src/index.ts +315 -301
- package/src/tool.ts +60 -48
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Concurrency Risk Mining Guide
|
|
2
|
+
|
|
3
|
+
logicprobe does **not** prove concurrency safety. It mines design documents and plans for concurrency-related claims so they are either explicitly verified with dedicated tools or marked as unverified.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
**Prerequisite: confirm the verification target actually has concurrency requirements or behavior** — multiple threads, async tasks, interrupts, shared state, or parallel execution. Do not run concurrency mining on purely sequential designs just because a generic word like "parallel" or "atomic" appears.
|
|
8
|
+
|
|
9
|
+
Use when a document contains:
|
|
10
|
+
|
|
11
|
+
- "thread-safe", "lock-free", "wait-free", "no data race", "race-free"
|
|
12
|
+
- "race condition", "data race", "atomic", "synchronized"
|
|
13
|
+
- "mutex", "semaphore", "spinlock", "reentrant", "interrupt-safe"
|
|
14
|
+
- "concurrent", "parallel", "multi-threaded", "shared variable", "shared memory"
|
|
15
|
+
|
|
16
|
+
## DSH tool
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
logicprobe_concurrency_scan text="..."
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
|
|
24
|
+
- `CONCURRENCY_ABSOLUTE_CLAIM` (error) for guarantees like "thread-safe" / "lock-free" / "no data race"
|
|
25
|
+
- `CONCURRENCY_KEYWORD` (warning) for risk-related terms like "race condition" / "shared memory" / "mutex"
|
|
26
|
+
|
|
27
|
+
## Manual mining checklist
|
|
28
|
+
|
|
29
|
+
- [ ] Scan for absolute concurrency safety claims.
|
|
30
|
+
- [ ] For each absolute claim, require dedicated evidence: TSan report, model-checking result, formal proof, or a clear design argument.
|
|
31
|
+
- [ ] If no evidence exists, mark the claim `UNVERIFIED` and escalate to concurrency analysis.
|
|
32
|
+
- [ ] Do not treat "uses mutex" as "thread-safe" — synchronization primitives are not proof.
|
|
33
|
+
|
|
34
|
+
## Interrupt safety
|
|
35
|
+
|
|
36
|
+
Interrupt safety is a first-class concurrency dimension in embedded/real-time designs. The scan treats the following as interrupt-related risk points:
|
|
37
|
+
|
|
38
|
+
- `interrupt-safe`, `ISR-safe` → absolute claims (error)
|
|
39
|
+
- `interrupt safety`, `interrupt context`, `ISR`, `IRQ`, `NMI`, `critical section`
|
|
40
|
+
- `disable_irq`, `enable_irq`, `spin_lock_irqsave` → warning, verify pairing and nesting
|
|
41
|
+
|
|
42
|
+
Manual checklist:
|
|
43
|
+
|
|
44
|
+
- [ ] If the design claims "interrupt-safe", require evidence: critical sections, IRQ disable windows, atomic operations, or formal reasoning.
|
|
45
|
+
- [ ] Check that `disable_irq` / `enable_irq` are paired on all paths.
|
|
46
|
+
- [ ] Check that ISR-context code does not call blocking/sleeping primitives.
|
|
47
|
+
- [ ] Check that shared variables between ISR and thread context are protected (atomic, critical section, or lock-free protocol).
|
|
48
|
+
|
|
49
|
+
## Escalation targets
|
|
50
|
+
|
|
51
|
+
- C/C++: ThreadSanitizer, Helgrind
|
|
52
|
+
- Java: JCStress, Java PathFinder
|
|
53
|
+
- General: TLA+, SPIN, Alloy
|
|
54
|
+
- Rust: loom, Shuttle
|
|
@@ -1,104 +1,145 @@
|
|
|
1
|
-
# DSH Model Schema v1 — logicprobe_verify
|
|
2
|
-
|
|
3
|
-
The dsh-native `logicprobe_verify` tool accepts a structured JSON model. The engine runs
|
|
4
|
-
|
|
5
|
-
## Top-level model
|
|
6
|
-
|
|
7
|
-
```json
|
|
8
|
-
{
|
|
9
|
-
"schemaVersion": 1,
|
|
10
|
-
"init": "INIT",
|
|
11
|
-
"states": [{ "id": "INIT" }, { "id": "ACTIVE", "terminal": true }],
|
|
12
|
-
"transitions": [
|
|
13
|
-
{ "from": "INIT", "event": "go", "to": "ACTIVE" }
|
|
14
|
-
],
|
|
15
|
-
"variables": [],
|
|
16
|
-
"invariants": [],
|
|
17
|
-
"concurrentPairs": [],
|
|
18
|
-
"boundaryChecks": [],
|
|
19
|
-
"resourcePairs": []
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
33
|
-
| `
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{ "
|
|
43
|
-
{ "
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
{ "variable": "retry", "op": "
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
|
65
|
-
|
|
66
|
-
| `
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"
|
|
92
|
-
{ "
|
|
93
|
-
{ "
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1
|
+
# DSH Model Schema v1 — logicprobe_verify
|
|
2
|
+
|
|
3
|
+
The dsh-native `logicprobe_verify` tool accepts a structured JSON model. The engine runs 19 checks (S1-S8 structural, A1-A11 adversarial) and returns a JSON report. When `beforeModel` is supplied, it also runs D1-D4 before/after regression checks. Guards and updates are structured data — no code strings, no arbitrary execution.
|
|
4
|
+
|
|
5
|
+
## Top-level model
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"schemaVersion": 1,
|
|
10
|
+
"init": "INIT",
|
|
11
|
+
"states": [{ "id": "INIT" }, { "id": "ACTIVE", "terminal": true }],
|
|
12
|
+
"transitions": [
|
|
13
|
+
{ "from": "INIT", "event": "go", "to": "ACTIVE" }
|
|
14
|
+
],
|
|
15
|
+
"variables": [],
|
|
16
|
+
"invariants": [],
|
|
17
|
+
"concurrentPairs": [],
|
|
18
|
+
"boundaryChecks": [],
|
|
19
|
+
"resourcePairs": [],
|
|
20
|
+
"idempotentEvents": []
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| Field | Required | Meaning |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `schemaVersion` | yes | Must be `1` |
|
|
27
|
+
| `init` | yes | Initial state id |
|
|
28
|
+
| `states` | yes | `{ id, terminal? }`; `terminal` exempts S2/S3/S5/A1 |
|
|
29
|
+
| `transitions` | yes | `{ from, event, to, guard?, updates? }` |
|
|
30
|
+
| `variables` | no | `{ name, kind: integer\|boolean, init, min?, max?, monotonic? }` |
|
|
31
|
+
| `invariants` | no | See invariant kinds below |
|
|
32
|
+
| `concurrentPairs` | no | `["eventA", "eventB"]` pairs for A2 |
|
|
33
|
+
| `boundaryChecks` | no | `{ variable, values: number[] }` for A5 |
|
|
34
|
+
| `resourcePairs` | no | `{ resource, acquireEvent, releaseEvent, failEvent? }` for A4/A6 |
|
|
35
|
+
| `idempotentEvents` | no | Events that must be replay-safe; verified by A8 |
|
|
36
|
+
|
|
37
|
+
## Guards
|
|
38
|
+
|
|
39
|
+
A guard is exactly one of:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{ "variable": "retry", "op": "<", "value": 3 }
|
|
43
|
+
{ "all": [ { "variable": "armed", "op": "==", "value": true }, { "variable": "retry", "op": ">", "value": 0 } ] }
|
|
44
|
+
{ "any": [ { "variable": "mode", "op": "==", "value": 1 }, { "variable": "mode", "op": "==", "value": 2 } ] }
|
|
45
|
+
{ "not": { "variable": "locked", "op": "==", "value": true } }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- Boolean variables only support `==` / `!=`.
|
|
49
|
+
- A transition with **no guard** is the default/else branch for its `(from, event)` group. It fires only when no guarded branch in that group is true.
|
|
50
|
+
- Multiple true guards in one `(from, event)` group are reported as S4 nondeterminism; a group with guards and no default must be exhaustive or S6 flags the missing branch.
|
|
51
|
+
|
|
52
|
+
## Updates
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{ "variable": "retry", "op": "inc", "value": 1 }
|
|
56
|
+
{ "variable": "retry", "op": "set", "value": 0 }
|
|
57
|
+
{ "variable": "retry", "op": "dec", "value": 1 }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`inc`/`dec` default to 1 when `value` is omitted. `set` defaults to 0.
|
|
61
|
+
|
|
62
|
+
## Invariants
|
|
63
|
+
|
|
64
|
+
| Kind | Shape | Checks |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `never-states` | `{ states: ["ERROR"] }` | No reachable runtime state may be in the forbidden set |
|
|
67
|
+
| `var-in-range` | `{ variable, min?, max? }` | Every reachable runtime state keeps the variable in range |
|
|
68
|
+
| `event-before-state` | `{ event: "power_ready", state: "ACTIVE" }` | Every path entering `state` must have passed through `event` first |
|
|
69
|
+
| `leads-to` | `{ from: "MIGRATING", to: "DONE" }` | Every path from `from` must eventually reach `to` |
|
|
70
|
+
| `sequence` | `{ events: ["backup", "modify", "commit"] }` | Events must occur in the given order |
|
|
71
|
+
| `atomicity` | `{ events: ["write"], commit: "commit", rollback?: "rollback" }` | Atomic group must end with commit/rollback before leaving scope |
|
|
72
|
+
|
|
73
|
+
A7 reports the shortest violating path for each failed invariant. An empty path means the initial state already violates it.
|
|
74
|
+
|
|
75
|
+
## Permission presets and interaction mode
|
|
76
|
+
|
|
77
|
+
| Preset | sandbox | approval | logicprobe behavior |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| `workspace-write` | workspace-write | ask | Evidence stays in workspace; model confirmation defaults to ask |
|
|
80
|
+
| `danger-full-access` | danger-full-access | never | Full file access; interaction resolves to auto; never request sandbox escalation |
|
|
81
|
+
| custom | any | any | The session folds the last `sandbox/mode` and `approval/policy` events; interaction follows approval only |
|
|
82
|
+
|
|
83
|
+
In `interaction=auto`, do NOT call `ask_user_question` for model confirmation. Round-trip the extracted model into a transition table, compare it against the source extraction, and mark the report `UNCONFIRMED`.
|
|
84
|
+
|
|
85
|
+
## Minimal example
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"schemaVersion": 1,
|
|
90
|
+
"init": "INIT",
|
|
91
|
+
"states": [
|
|
92
|
+
{ "id": "INIT" },
|
|
93
|
+
{ "id": "RETRY" },
|
|
94
|
+
{ "id": "FATAL", "terminal": true }
|
|
95
|
+
],
|
|
96
|
+
"transitions": [
|
|
97
|
+
{ "from": "INIT", "event": "timeout", "guard": { "variable": "retry", "op": "<", "value": 3 }, "to": "RETRY", "updates": [{ "variable": "retry", "op": "inc" }] },
|
|
98
|
+
{ "from": "INIT", "event": "timeout", "guard": { "variable": "retry", "op": ">=", "value": 3 }, "to": "FATAL" }
|
|
99
|
+
],
|
|
100
|
+
"variables": [{ "name": "retry", "kind": "integer", "init": 0, "min": 0, "max": 3 }],
|
|
101
|
+
"boundaryChecks": [{ "variable": "retry", "values": [0, 1, 2, 3] }]
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Before/after comparison (D1-D4)
|
|
106
|
+
|
|
107
|
+
When `beforeModel` is passed to `logicprobe_verify`, the engine treats `model` as AFTER and runs four extra checks after S1-A11:
|
|
108
|
+
|
|
109
|
+
| Check | Purpose |
|
|
110
|
+
|---|---|
|
|
111
|
+
| D1 Behavioral Preservation | Every BEFORE (state, event) that could fire must still be fireable from the mapped AFTER state |
|
|
112
|
+
| D2 Invariant Continuity | Every BEFORE invariant (mapped through `stateMapping`) must still hold in AFTER |
|
|
113
|
+
| D3 Regression Delta | Lists added/removed states, events, and transitions |
|
|
114
|
+
| D4 Deadlock/Liveness Regression | New deadlock states or closed SCCs not present in BEFORE |
|
|
115
|
+
|
|
116
|
+
`stateMapping` maps BEFORE state ids to AFTER state ids. Omit it when state names are unchanged.
|
|
117
|
+
|
|
118
|
+
Example tool call shape:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"model": { "...": "AFTER LogicModelV1" },
|
|
123
|
+
"beforeModel": { "...": "BEFORE LogicModelV1" },
|
|
124
|
+
"stateMapping": { "OLD_INIT": "INIT", "OLD_ACTIVE": "ACTIVE" }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The report's `comparison` object includes both model hashes, state/transition counts, and delta arrays.
|
|
129
|
+
|
|
130
|
+
## Idempotent replay (A8)
|
|
131
|
+
|
|
132
|
+
List events that must be idempotent in `idempotentEvents`. For every reachable state, applying the event twice must produce the same state as applying it once. This is useful for retries, webhook redelivery, and migration replay.
|
|
133
|
+
|
|
134
|
+
## Advanced constraints (S8, A9-A11)
|
|
135
|
+
|
|
136
|
+
- **S8 Monotonic Variables**: declare `monotonic: "inc"|"dec"` on a variable; updates must not move in the opposite direction.
|
|
137
|
+
- **A9 Leads-To**: `{ kind: "leads-to", from, to }` — every path from `from` must eventually reach `to`.
|
|
138
|
+
- **A10 Sequence**: `{ kind: "sequence", events }` — events must appear in order.
|
|
139
|
+
- **A11 Atomicity**: `{ kind: "atomicity", events, commit, rollback? }` — once an atomic event starts, the machine must reach commit/rollback before leaving the atomic scope or terminating.
|
|
140
|
+
|
|
141
|
+
## Limits
|
|
142
|
+
|
|
143
|
+
- State-space exploration caps at `maxStates` (default 10000); larger guards/domains may report truncation instead of a false pass.
|
|
144
|
+
- A3 samples the first `maxPermutationEvents` events (default 5).
|
|
145
|
+
- The engine is a finite-state model checker. It cannot prove properties of the real implementation; follow with code-level review.
|