dsh-logicprobe 0.4.0 → 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.
Files changed (33) hide show
  1. package/README.en-US.md +7 -1
  2. package/README.md +7 -1
  3. package/lib/concurrency-tool.js +34 -0
  4. package/lib/concurrency.js +76 -0
  5. package/lib/data-engine.js +930 -0
  6. package/lib/data-tool.js +61 -0
  7. package/lib/engine.js +1622 -1364
  8. package/lib/index.js +291 -277
  9. package/lib/tool.js +57 -57
  10. package/lib/types/concurrency-tool.d.ts +8 -0
  11. package/lib/types/concurrency.d.ts +20 -0
  12. package/lib/types/data-engine.d.ts +199 -0
  13. package/lib/types/data-tool.d.ts +10 -0
  14. package/lib/types/engine.d.ts +171 -151
  15. package/package.json +79 -78
  16. package/skills/logicprobe/SKILL.md +285 -268
  17. package/skills/logicprobe/references/__pycache__/verification-harness.cpython-312.pyc +0 -0
  18. package/skills/logicprobe/references/concurrency-risk-guide.md +54 -0
  19. package/skills/logicprobe/references/dsh-model-schema.md +145 -129
  20. package/skills/logicprobe/references/logic-verification-guide.md +463 -413
  21. package/skills/logicprobe/references/verification-harness.py +806 -582
  22. package/skills/logicprobe-datamodel/SKILL.md +124 -0
  23. package/skills/logicprobe-datamodel/references/__pycache__/data-model-harness.cpython-312.pyc +0 -0
  24. package/skills/logicprobe-datamodel/references/data-model-guide.md +62 -0
  25. package/skills/logicprobe-datamodel/references/data-model-harness.py +528 -0
  26. package/skills/logicprobe-datamodel/references/data-model-schema.md +128 -0
  27. package/src/concurrency-tool.ts +37 -0
  28. package/src/concurrency.ts +102 -0
  29. package/src/data-engine.ts +1001 -0
  30. package/src/data-tool.ts +65 -0
  31. package/src/engine.ts +234 -0
  32. package/src/index.ts +315 -301
  33. package/src/tool.ts +60 -60
@@ -1,129 +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 14 checks (S1-S7 structural, A1-A7 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
- }
21
- ```
22
-
23
- | Field | Required | Meaning |
24
- |---|---|---|
25
- | `schemaVersion` | yes | Must be `1` |
26
- | `init` | yes | Initial state id |
27
- | `states` | yes | `{ id, terminal? }`; `terminal` exempts S2/S3/S5/A1 |
28
- | `transitions` | yes | `{ from, event, to, guard?, updates? }` |
29
- | `variables` | no | `{ name, kind: integer\|boolean, init, min?, max? }` |
30
- | `invariants` | no | See invariant kinds below |
31
- | `concurrentPairs` | no | `["eventA", "eventB"]` pairs for A2 |
32
- | `boundaryChecks` | no | `{ variable, values: number[] }` for A5 |
33
- | `resourcePairs` | no | `{ resource, acquireEvent, releaseEvent, failEvent? }` for A4/A6 |
34
-
35
- ## Guards
36
-
37
- A guard is exactly one of:
38
-
39
- ```json
40
- { "variable": "retry", "op": "<", "value": 3 }
41
- { "all": [ { "variable": "armed", "op": "==", "value": true }, { "variable": "retry", "op": ">", "value": 0 } ] }
42
- { "any": [ { "variable": "mode", "op": "==", "value": 1 }, { "variable": "mode", "op": "==", "value": 2 } ] }
43
- { "not": { "variable": "locked", "op": "==", "value": true } }
44
- ```
45
-
46
- - Boolean variables only support `==` / `!=`.
47
- - 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.
48
- - 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.
49
-
50
- ## Updates
51
-
52
- ```json
53
- { "variable": "retry", "op": "inc", "value": 1 }
54
- { "variable": "retry", "op": "set", "value": 0 }
55
- { "variable": "retry", "op": "dec", "value": 1 }
56
- ```
57
-
58
- `inc`/`dec` default to 1 when `value` is omitted. `set` defaults to 0.
59
-
60
- ## Invariants
61
-
62
- | Kind | Shape | Checks |
63
- |---|---|---|
64
- | `never-states` | `{ states: ["ERROR"] }` | No reachable runtime state may be in the forbidden set |
65
- | `var-in-range` | `{ variable, min?, max? }` | Every reachable runtime state keeps the variable in range |
66
- | `event-before-state` | `{ event: "power_ready", state: "ACTIVE" }` | Every path entering `state` must have passed through `event` first |
67
-
68
- A7 reports the shortest violating path for each failed invariant. An empty path means the initial state already violates it.
69
-
70
- ## Permission presets and interaction mode
71
-
72
- | Preset | sandbox | approval | logicprobe behavior |
73
- |---|---|---|---|
74
- | `workspace-write` | workspace-write | ask | Evidence stays in workspace; model confirmation defaults to ask |
75
- | `danger-full-access` | danger-full-access | never | Full file access; interaction resolves to auto; never request sandbox escalation |
76
- | custom | any | any | The session folds the last `sandbox/mode` and `approval/policy` events; interaction follows approval only |
77
-
78
- 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`.
79
-
80
- ## Minimal example
81
-
82
- ```json
83
- {
84
- "schemaVersion": 1,
85
- "init": "INIT",
86
- "states": [
87
- { "id": "INIT" },
88
- { "id": "RETRY" },
89
- { "id": "FATAL", "terminal": true }
90
- ],
91
- "transitions": [
92
- { "from": "INIT", "event": "timeout", "guard": { "variable": "retry", "op": "<", "value": 3 }, "to": "RETRY", "updates": [{ "variable": "retry", "op": "inc" }] },
93
- { "from": "INIT", "event": "timeout", "guard": { "variable": "retry", "op": ">=", "value": 3 }, "to": "FATAL" }
94
- ],
95
- "variables": [{ "name": "retry", "kind": "integer", "init": 0, "min": 0, "max": 3 }],
96
- "boundaryChecks": [{ "variable": "retry", "values": [0, 1, 2, 3] }]
97
- }
98
- ```
99
-
100
- ## Before/after comparison (D1-D4)
101
-
102
- When `beforeModel` is passed to `logicprobe_verify`, the engine treats `model` as AFTER and runs four extra checks after S1-A7:
103
-
104
- | Check | Purpose |
105
- |---|---|
106
- | D1 Behavioral Preservation | Every BEFORE (state, event) that could fire must still be fireable from the mapped AFTER state |
107
- | D2 Invariant Continuity | Every BEFORE invariant (mapped through `stateMapping`) must still hold in AFTER |
108
- | D3 Regression Delta | Lists added/removed states, events, and transitions |
109
- | D4 Deadlock/Liveness Regression | New deadlock states or closed SCCs not present in BEFORE |
110
-
111
- `stateMapping` maps BEFORE state ids to AFTER state ids. Omit it when state names are unchanged.
112
-
113
- Example tool call shape:
114
-
115
- ```json
116
- {
117
- "model": { "...": "AFTER LogicModelV1" },
118
- "beforeModel": { "...": "BEFORE LogicModelV1" },
119
- "stateMapping": { "OLD_INIT": "INIT", "OLD_ACTIVE": "ACTIVE" }
120
- }
121
- ```
122
-
123
- The report's `comparison` object includes both model hashes, state/transition counts, and delta arrays.
124
-
125
- ## Limits
126
-
127
- - State-space exploration caps at `maxStates` (default 10000); larger guards/domains may report truncation instead of a false pass.
128
- - A3 samples the first `maxPermutationEvents` events (default 5).
129
- - The engine is a finite-state model checker. It cannot prove properties of the real implementation; follow with code-level review.
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.