dsh-logicprobe 1.1.0 → 1.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 +17 -6
- package/README.md +17 -6
- package/lib/compose-tool.js +8 -2
- package/lib/concurrency-tool.js +8 -2
- package/lib/data-tool.js +8 -2
- package/lib/engine.js +3151 -3151
- package/lib/export-tool.js +8 -2
- package/lib/index.js +28 -40
- package/lib/report-diff-tool.js +8 -2
- package/lib/report-view.js +295 -0
- package/lib/structure-tool.js +8 -2
- package/lib/tool.js +8 -2
- package/lib/types/engine.d.ts +419 -419
- package/lib/types/index.d.ts +5 -4
- package/lib/types/report-view.d.ts +43 -0
- package/lib/types/uml.d.ts +293 -256
- package/lib/uml-tool.js +21 -14
- package/lib/uml.js +76 -12
- package/package.json +2 -2
- package/skills/logicprobe/SKILL.md +42 -6
- package/skills/logicprobe/references/dsh-model-schema.md +1 -1
- package/skills/logicprobe/references/gap-routing-guide.md +10 -9
- package/skills/logicprobe/references/logic-verification-guide.md +1 -1
- package/skills/logicprobe-concurrency/SKILL.md +2 -0
- package/skills/logicprobe-datamodel/SKILL.md +5 -0
- package/skills/logicprobe-structure/SKILL.md +1 -0
- package/skills/logicprobe-uml/SKILL.md +3 -0
- package/skills/logicprobe-uml/references/uml-modeling-guide.md +70 -2
- package/src/compose-tool.ts +8 -2
- package/src/concurrency-tool.ts +8 -2
- package/src/data-tool.ts +9 -3
- package/src/export-tool.ts +8 -2
- package/src/index.ts +28 -40
- package/src/report-diff-tool.ts +8 -2
- package/src/report-view.ts +343 -0
- package/src/structure-tool.ts +8 -2
- package/src/tool.ts +8 -2
- package/src/uml-tool.ts +21 -14
- package/src/uml.ts +94 -11
package/lib/uml-tool.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { REPORT_SCHEMAS, DEFAULT_HASH_SPEC, modelHash, refusalVerdict, verdictOf, verdictOfFindings } from './engine.js';
|
|
4
|
-
import { renderUml, parseUml, parseFindings, reviewUml, explainLabels, UmlError } from './uml.js';
|
|
4
|
+
import { renderUml, parseUml, parseFindings, reviewUml, explainLabels, checkUmlIntent, UmlError } from './uml.js';
|
|
5
|
+
import { renderReportText } from './report-view.js';
|
|
5
6
|
export const LOGICPROBE_UML_TOOL_NAME = 'logicprobe_uml';
|
|
6
7
|
/**
|
|
7
8
|
* DSH tool wrapping the UML front end: model a code flow as a UML diagram
|
|
@@ -17,7 +18,7 @@ export const LOGICPROBE_UML_TOOL_NAME = 'logicprobe_uml';
|
|
|
17
18
|
*/
|
|
18
19
|
export const logicProbeUmlTool = defineTool({
|
|
19
20
|
name: LOGICPROBE_UML_TOOL_NAME,
|
|
20
|
-
description: 'Model a code flow as UML, and audit the modelling. action="render" turns a LogicModelV1 into diagram source: mermaid (state, activity, sequence) or plantuml (state, sequence). action="parse" reads Mermaid or PlantUML state or activity text back into a LogicModelV1, so a hand-drawn diagram can be verified. A sequence diagram is refused: a trace cannot reconstruct a machine. So is any other diagram family (class, ER, gantt, mindmap). That refusal carries errorCode "UML_NOT_A_STATE_DIAGRAM". A PlantUML component, package or deployment diagram declares no kind, so the parser detects those constructs itself. It returns a by-product model and reports the error UML_NOT_A_STATE_DIAGRAM, with `discardedConstructs` and `discardedEdges`. Never treat that model as a model of the file. action="review" audits the modelling: structural defects (UML002-UML009), documentation gaps (UML010-UML015), and a fidelity check that re-parses the rendered diagram (UML017). Give it a model, a diagram, or both. action="explain-labels" prints the label and comment conventions the parser accepts, without needing a diagram. Rendering never invents structure. A construct the notation cannot express becomes a warning. For dependency questions on a component or class diagram, use `logicprobe_structure_verify` instead. Read `verdict`, not `ok`: error findings mean a failed review.',
|
|
21
|
+
description: 'Model a code flow as UML, and audit the modelling. action="render" turns a LogicModelV1 into diagram source: mermaid (state, activity, sequence) or plantuml (state, sequence). action="parse" reads Mermaid or PlantUML state or activity text back into a LogicModelV1, so a hand-drawn diagram can be verified. A sequence diagram is refused: a trace cannot reconstruct a machine. So is any other diagram family (class, ER, gantt, mindmap). That refusal carries errorCode "UML_NOT_A_STATE_DIAGRAM". A PlantUML component, package or deployment diagram declares no kind, so the parser detects those constructs itself. It returns a by-product model and reports the error UML_NOT_A_STATE_DIAGRAM, with `discardedConstructs` and `discardedEdges`. Never treat that model as a model of the file. action="review" audits the modelling: structural defects (UML002-UML009), documentation gaps (UML010-UML015), and a fidelity check that re-parses the rendered diagram (UML017). Give it a model, a diagram, or both. action="explain-labels" prints the label and comment conventions the parser accepts, without needing a diagram. Rendering never invents structure. A construct the notation cannot express becomes a warning. For dependency questions on a component or class diagram, use `logicprobe_structure_verify` instead. Declare `intent` (present, verify, fidelity) to say what the artifact is for: a view that cannot serve it is refused before any work, with errorCode UML_INTENT_UNSERVABLE, UML_VIEW_UNREPRESENTABLE or UML_INTENT_MISMATCH. Omit it and nothing changes. Read `verdict`, not `ok`: error findings mean a failed review.',
|
|
21
22
|
parameters: {
|
|
22
23
|
action: {
|
|
23
24
|
type: 'string',
|
|
@@ -43,6 +44,11 @@ export const logicProbeUmlTool = defineTool({
|
|
|
43
44
|
enum: ['state', 'activity', 'sequence'],
|
|
44
45
|
description: 'Diagram kind to render. Default state. sequence is one BFS trace, not the whole machine. PlantUML activity is refused (its structured-flowchart syntax cannot faithfully carry a graph with merges or cycles) — use mermaid for that view.',
|
|
45
46
|
},
|
|
47
|
+
intent: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
enum: ['present', 'verify', 'fidelity'],
|
|
50
|
+
description: 'What the artifact is for, declared up front: present = a human will read the diagram (any view), verify = it must be parseable into a LogicModelV1 for the engine (state or activity), fidelity = the point is the render-and-reparse proof (review only, state or activity). A view that cannot serve the intent is refused before any work, with errorCode UML_INTENT_UNSERVABLE, UML_VIEW_UNREPRESENTABLE or UML_INTENT_MISMATCH. Omit it and nothing changes: a sequence view is still rendered, and review still reports UML019.',
|
|
51
|
+
},
|
|
46
52
|
roundTrip: {
|
|
47
53
|
type: 'boolean',
|
|
48
54
|
description: 'review only: render and re-parse the model to prove the diagram carries it. Default true.',
|
|
@@ -51,23 +57,21 @@ export const logicProbeUmlTool = defineTool({
|
|
|
51
57
|
type: 'integer',
|
|
52
58
|
description: 'Cap on the sequence trace length when rendering kind=sequence. Default 60.',
|
|
53
59
|
},
|
|
60
|
+
reportView: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
enum: ['digest', 'full'],
|
|
63
|
+
description: 'digest (default) prints the diagram or report body; full prints the structured result as JSON.',
|
|
64
|
+
},
|
|
54
65
|
},
|
|
55
66
|
output: {
|
|
56
67
|
schema: {
|
|
57
68
|
type: 'json',
|
|
58
69
|
description: 'Render result (diagram source), parse result (LogicModelV1 + labels), or the modelling review report with findings, round-trip diff and next steps.',
|
|
59
70
|
},
|
|
60
|
-
render(
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
if (typeof record.diagram === 'string') {
|
|
65
|
-
return [
|
|
66
|
-
{ type: 'text', text: record.diagram },
|
|
67
|
-
{ type: 'text', text: JSON.stringify(value, null, 2) },
|
|
68
|
-
];
|
|
69
|
-
}
|
|
70
|
-
return [{ type: 'text', text: JSON.stringify(value, null, 2) }];
|
|
71
|
+
render(args, value) {
|
|
72
|
+
// A rendered diagram is source text: the report body prints it verbatim, once.
|
|
73
|
+
// Echoing the whole result as JSON printed the same diagram a second time, escaped.
|
|
74
|
+
return [{ type: 'text', text: renderReportText(value, { full: args.reportView === 'full' }) }];
|
|
71
75
|
},
|
|
72
76
|
},
|
|
73
77
|
timeoutMs: 10_000,
|
|
@@ -77,12 +81,13 @@ export const logicProbeUmlTool = defineTool({
|
|
|
77
81
|
if (args.action === 'render') {
|
|
78
82
|
if (args.model === undefined)
|
|
79
83
|
return errorResult('action=render needs `model` (a LogicModelV1 object)');
|
|
80
|
-
const result = renderUml(args.model, (args.notation === undefined || args.notation === 'auto' ? 'mermaid' : args.notation), (args.kind ?? 'state'), args.maxSteps);
|
|
84
|
+
const result = renderUml(args.model, (args.notation === undefined || args.notation === 'auto' ? 'mermaid' : args.notation), (args.kind ?? 'state'), args.maxSteps, args.intent);
|
|
81
85
|
return { ok: true, ran: true, ...verdictOf(0, result.warnings.length), schema: REPORT_SCHEMAS.umlRender, action: 'render', notation: result.notation, kind: result.diagram, diagram: result.primary, hashes: { diagram: createHash('sha256').update(result.primary).digest('hex') }, warnings: result.warnings };
|
|
82
86
|
}
|
|
83
87
|
if (args.action === 'parse') {
|
|
84
88
|
if (args.diagram === undefined)
|
|
85
89
|
return errorResult('action=parse needs `diagram` (Mermaid or PlantUML text)');
|
|
90
|
+
checkUmlIntent(args.intent, 'parse');
|
|
86
91
|
const result = parseUml(args.diagram, args.notation ?? 'auto');
|
|
87
92
|
// A diagram from another family still parses into *something*. `parseFindings`
|
|
88
93
|
// says so, and the verdict is what stops that something from being trusted:
|
|
@@ -108,6 +113,7 @@ export const logicProbeUmlTool = defineTool({
|
|
|
108
113
|
// R9: the label contract was documented in the library and in `explainLabels()`, but no
|
|
109
114
|
// tool exposed it, so it was reachable only by reading the source or the docs.
|
|
110
115
|
if (args.action === 'explain-labels') {
|
|
116
|
+
checkUmlIntent(args.intent, 'labels');
|
|
111
117
|
const notation = (args.notation === undefined || args.notation === 'auto' ? 'mermaid' : args.notation);
|
|
112
118
|
return {
|
|
113
119
|
ok: true,
|
|
@@ -125,6 +131,7 @@ export const logicProbeUmlTool = defineTool({
|
|
|
125
131
|
diagramKind: (args.kind ?? 'state'),
|
|
126
132
|
roundTrip: args.roundTrip,
|
|
127
133
|
maxSteps: args.maxSteps,
|
|
134
|
+
intent: args.intent,
|
|
128
135
|
});
|
|
129
136
|
return report;
|
|
130
137
|
}
|
package/lib/uml.js
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
import { REPORT_SCHEMAS, validateModel, modelHash, metadataKeysOf, narrativeComplete, narrativeCoverageOf, verdictOfFindings, DEFAULT_HASH_SPEC } from './engine.js';
|
|
34
34
|
export const UML_NOTATIONS = ['mermaid', 'plantuml'];
|
|
35
35
|
export const UML_DIAGRAMS = ['state', 'activity', 'sequence'];
|
|
36
|
+
export const UML_INTENTS = ['present', 'verify', 'fidelity'];
|
|
36
37
|
/** Marker every generated diagram carries; renderers ignore it, the parser uses it. */
|
|
37
38
|
const DIRECTIVE_NAMESPACE = 'logicprobe:';
|
|
38
39
|
/** State id / event name characters that would break the generated label syntax. */
|
|
@@ -286,28 +287,90 @@ function renderSequence(context, notation, maxSteps) {
|
|
|
286
287
|
lines.push('@enduml');
|
|
287
288
|
return { text: lines.join('\n') + '\n', truncated };
|
|
288
289
|
}
|
|
290
|
+
/** What each action hands back, so a declared intent can be matched against it. */
|
|
291
|
+
const ACTION_PRODUCES = {
|
|
292
|
+
render: 'a diagram',
|
|
293
|
+
parse: 'a LogicModelV1 read out of a diagram',
|
|
294
|
+
review: 'an audit of the modelling',
|
|
295
|
+
labels: 'the label and comment conventions the parser accepts',
|
|
296
|
+
};
|
|
289
297
|
/**
|
|
290
|
-
*
|
|
298
|
+
* The intents each action can serve.
|
|
291
299
|
*
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
300
|
+
* `fidelity` is a review job: render produces a diagram, and a diagram nothing has
|
|
301
|
+
* compared back to its model proves nothing about it.
|
|
302
|
+
*/
|
|
303
|
+
const ACTION_INTENTS = {
|
|
304
|
+
render: ['present', 'verify'],
|
|
305
|
+
parse: ['verify'],
|
|
306
|
+
review: ['present', 'verify', 'fidelity'],
|
|
307
|
+
labels: [],
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* The `(notation, view)` cells this module can draw.
|
|
297
311
|
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
312
|
+
* PlantUML activity is the cell that does not exist: its activity syntax is a
|
|
313
|
+
* structured flowchart language, so a graph with merges or cycles needs a while/if
|
|
314
|
+
* reconstruction this module does not perform. Refusing is the honest outcome —
|
|
315
|
+
* quietly emitting a state diagram under an "activity" request would mislabel the
|
|
316
|
+
* model.
|
|
302
317
|
*/
|
|
303
|
-
export function
|
|
318
|
+
export function assertUmlView(notation, diagram) {
|
|
304
319
|
if (!UML_NOTATIONS.includes(notation))
|
|
305
320
|
throw new UmlError('unknown notation "' + String(notation) + '"; expected ' + UML_NOTATIONS.join(' | '));
|
|
306
321
|
if (!UML_DIAGRAMS.includes(diagram))
|
|
307
322
|
throw new UmlError('unknown diagram "' + String(diagram) + '"; expected ' + UML_DIAGRAMS.join(' | '));
|
|
308
323
|
if (notation === 'plantuml' && diagram === 'activity') {
|
|
309
|
-
throw new UmlError('plantuml has no faithful activity view here (its activity syntax is a structured flowchart language; a graph with merges or cycles needs a while/if reconstruction logicprobe does not perform) — use notation "mermaid" for the activity view, or diagram "state"');
|
|
324
|
+
throw new UmlError('plantuml has no faithful activity view here (its activity syntax is a structured flowchart language; a graph with merges or cycles needs a while/if reconstruction logicprobe does not perform) — use notation "mermaid" for the activity view, or diagram "state"', 'UML_VIEW_UNREPRESENTABLE');
|
|
310
325
|
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Refuse, before any work, a request whose declared purpose the view cannot serve.
|
|
329
|
+
*
|
|
330
|
+
* Without an intent this changes nothing: the review still reports `UML019` when the
|
|
331
|
+
* fidelity check does not apply to the view it was given. With one, an impossible
|
|
332
|
+
* pairing is an error carrying a code, instead of a report about the wrong artifact —
|
|
333
|
+
* which is the failure this check exists to prevent.
|
|
334
|
+
*
|
|
335
|
+
* @param intent - the declared purpose, or `undefined` to leave the behaviour unchanged.
|
|
336
|
+
* @param action - which action is about to run.
|
|
337
|
+
* @param view - the requested `(notation, diagram)`, for the actions that have one.
|
|
338
|
+
*/
|
|
339
|
+
export function checkUmlIntent(intent, action, view) {
|
|
340
|
+
if (intent === undefined)
|
|
341
|
+
return;
|
|
342
|
+
if (!UML_INTENTS.includes(intent))
|
|
343
|
+
throw new UmlError('unknown intent "' + String(intent) + '"; expected ' + UML_INTENTS.join(' | '));
|
|
344
|
+
const served = ACTION_INTENTS[action];
|
|
345
|
+
if (!served.includes(intent)) {
|
|
346
|
+
throw new UmlError('intent "' + intent + '" cannot be served by action=' + action + ', which returns ' + ACTION_PRODUCES[action] + '; it serves ' +
|
|
347
|
+
(served.length === 0 ? 'no intent — leave `intent` off' : served.join(' | ')), 'UML_INTENT_MISMATCH');
|
|
348
|
+
}
|
|
349
|
+
if (view === undefined)
|
|
350
|
+
return;
|
|
351
|
+
assertUmlView(view.notation, view.diagram);
|
|
352
|
+
if (intent === 'present' || view.diagram !== 'sequence')
|
|
353
|
+
return;
|
|
354
|
+
throw new UmlError('intent "' + intent + '" needs a machine, and a sequence view is one BFS trace: ' +
|
|
355
|
+
(intent === 'fidelity'
|
|
356
|
+
? 'the render/parse fidelity check does not apply to a trace, so nothing would be proven. Review kind "state" or "activity" to have the diagram checked against the model, and render the trace separately with intent "present".'
|
|
357
|
+
: '`parse` refuses a trace because it cannot reconstruct a machine, so the diagram cannot feed verification. Model the machine as a state or activity diagram, and render the trace separately with intent "present".'), 'UML_INTENT_UNSERVABLE');
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Render a LogicModelV1 as UML.
|
|
361
|
+
*
|
|
362
|
+
* Mermaid covers all three views; PlantUML covers state and sequence (see
|
|
363
|
+
* `assertUmlView` for why activity is refused).
|
|
364
|
+
*
|
|
365
|
+
* @param input - candidate LogicModelV1.
|
|
366
|
+
* @param notation - `mermaid` (default) or `plantuml`.
|
|
367
|
+
* @param diagram - `state` (default), `activity`, or `sequence`.
|
|
368
|
+
* @param maxSteps - cap on the sequence trace length.
|
|
369
|
+
* @param intent - what the diagram is for; a view that cannot serve it is refused first.
|
|
370
|
+
*/
|
|
371
|
+
export function renderUml(input, notation = 'mermaid', diagram = 'state', maxSteps = 60, intent) {
|
|
372
|
+
assertUmlView(notation, diagram);
|
|
373
|
+
checkUmlIntent(intent, 'render', { notation, diagram });
|
|
311
374
|
const context = prepareRender(input);
|
|
312
375
|
const warnings = [...context.warnings];
|
|
313
376
|
let primary;
|
|
@@ -1563,6 +1626,7 @@ export function reviewUml(options) {
|
|
|
1563
1626
|
throw new UmlError('review needs `model`, `diagram`, or both');
|
|
1564
1627
|
let notation = options.notation === undefined || options.notation === 'auto' ? 'mermaid' : options.notation;
|
|
1565
1628
|
const kind = options.diagramKind ?? 'state';
|
|
1629
|
+
checkUmlIntent(options.intent, 'review', { notation, diagram: kind });
|
|
1566
1630
|
let model;
|
|
1567
1631
|
let labels;
|
|
1568
1632
|
let parsed;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-logicprobe",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
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",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"build": "tsc -p tsconfig.json && node scripts/build-client.mjs",
|
|
80
80
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
81
81
|
"bump": "node scripts/bump-version.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",
|
|
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/report-view/run.mjs && node tests/external/run.mjs && node tests/python/run.mjs",
|
|
83
83
|
"test:full": "npm run build && node tests/full-suite.mjs",
|
|
84
84
|
"test:python": "npm run build && node tests/python/run.mjs"
|
|
85
85
|
},
|
|
@@ -60,7 +60,7 @@ This step is NOT skippable — it creates an explicit, auditable record of what
|
|
|
60
60
|
|-------|----------|
|
|
61
61
|
| LIGHTWEIGHT | All 5 checklist items (file paths, API/type names, line numbers, behavioral claims, mechanism feasibility) answered in context with explicit results per item |
|
|
62
62
|
| STANDARD | Phase 1-2: enumerate every verifiable claim → verify each against codebase with evidence |
|
|
63
|
-
| ESCALATED | Full pipeline: Phase 1-5 including Logic Primitive Verification (Phase 2a
|
|
63
|
+
| ESCALATED | Full pipeline: Phase 1-5 including Logic Primitive Verification (Phase 2a structural, Phase 2b adversarial) |
|
|
64
64
|
|
|
65
65
|
### Plan Verification Block
|
|
66
66
|
|
|
@@ -151,7 +151,7 @@ Document claims → Extract model → Runtime check:
|
|
|
151
151
|
|
|
152
152
|
Refactoring variant:
|
|
153
153
|
Old code + Refactoring plan → Extract BEFORE model + AFTER model
|
|
154
|
-
→ Run pipeline on AFTER model (
|
|
154
|
+
→ Run the pipeline on the AFTER model (the same checks)
|
|
155
155
|
→ Compare BEFORE vs AFTER: behavioral preservation, regression, complexity delta
|
|
156
156
|
→ Flag any invariant that held in BEFORE but fails in AFTER
|
|
157
157
|
|
|
@@ -171,8 +171,10 @@ UML modelling variant (the task is to draw a flow, not to check a claim):
|
|
|
171
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. |
|
|
172
172
|
| `logicprobe_export` | Emits external-checker input from a verified model: UPPAAL, TLA+, PRISM, SPIN. |
|
|
173
173
|
| `logicprobe_uml` | render / parse / review / explain-labels for UML modelling — the diagram domain belongs to the `logicprobe-uml` skill. |
|
|
174
|
+
| `logicprobe_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 `logicprobe-structure` skill. |
|
|
175
|
+
| `logicprobe_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. Without the tool, `verify --baseline REPORT` prints the same diff. |
|
|
174
176
|
|
|
175
|
-
The repository engine mirrors the same checks
|
|
177
|
+
The repository engine mirrors the same checks for hosts without the native tools, and its `--help` lists the subcommands. Two capabilities have no mirror. Data-model verification takes the data harness or the manual mode there. The concurrency claim scan is the same story: `logicprobe-concurrency` routes the claims instead. That engine prints the report JSON, not the body — the body is the dsh tools' rendering.
|
|
176
178
|
|
|
177
179
|
### Reading a Report: `ok` Is Not a Verdict
|
|
178
180
|
|
|
@@ -191,6 +193,8 @@ Every tool report carries the same outcome contract. **`ok` says a report was pr
|
|
|
191
193
|
| `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
194
|
| `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
195
|
|
|
196
|
+
A tool prints a body, not JSON. Passing checks stay in the `CHECKS` inventory line, and a fact that several checks report is listed once. Only error findings inline their evidence. Pass `reportView: "full"` when you need the structured report itself, for example to hand it to `logicprobe_report_diff`.
|
|
197
|
+
|
|
194
198
|
Turn the verdict into an answer, never into a summary of `ok`:
|
|
195
199
|
|
|
196
200
|
- `verdict: "pass"` — no error and no warning finding. Safe to report as verified, still with the scope the model covered.
|
|
@@ -199,6 +203,25 @@ Turn the verdict into an answer, never into a summary of `ok`:
|
|
|
199
203
|
|
|
200
204
|
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
205
|
|
|
206
|
+
### Writing the Answer: Name the Finding, Not Its Code
|
|
207
|
+
|
|
208
|
+
`S2_NO_TRANSITIONS`, `UML019`, `DA2` are values of `findings[].code`, not names. A reader
|
|
209
|
+
who has not memorized the schema learns nothing from one, and cannot tell whether their
|
|
210
|
+
machine is sound or stuck.
|
|
211
|
+
|
|
212
|
+
- **Say what it means**, in the user's language and in the terms of their own code:
|
|
213
|
+
「启动超时后 ERROR 没有任何出口迁移,机器会停在那里」, not 「S2 命中」. The finding's
|
|
214
|
+
`message` is written for the report; the sentence for the user is written from it.
|
|
215
|
+
- **Keep the identifier where the identifier is the subject**: a report field quoted
|
|
216
|
+
verbatim, a baseline diff, a test name, or a question about the check itself.
|
|
217
|
+
- **Name the property, not the checking.** "This path locks without unlocking" beats
|
|
218
|
+
"A4 failed". A check's name earns its place when the reader asked about the checking.
|
|
219
|
+
- **Carry the verdict in words.** "Not verified" or "verified, within the scope of this
|
|
220
|
+
model" — never a bare pass, and never a warning presented without its label.
|
|
221
|
+
|
|
222
|
+
A reader who cannot tell what failed will either trust a report they cannot read, or
|
|
223
|
+
ignore one they should act on.
|
|
224
|
+
|
|
202
225
|
### Slice Acceptance: Baseline Diffs
|
|
203
226
|
|
|
204
227
|
The acceptance criterion for a refactoring slice is usually "no **new** findings", not
|
|
@@ -231,7 +254,7 @@ When the document under review is a refactoring plan (modifying existing state m
|
|
|
231
254
|
1. **Extract the BEFORE model** from the existing codebase (not the plan — verify what the code actually does, not what the plan claims it does)
|
|
232
255
|
2. **Extract the AFTER model** from the refactoring plan
|
|
233
256
|
3. **Show both tables AND their model narratives** to the user side by side and confirm the delta is intentional
|
|
234
|
-
4. **Run Phase 2a + 2b on the AFTER model** — same
|
|
257
|
+
4. **Run Phase 2a + 2b on the AFTER model** — the same checks a new design gets
|
|
235
258
|
5. **Compare BEFORE vs AFTER**:
|
|
236
259
|
|
|
237
260
|
| Check | Method | Severity if Violated |
|
|
@@ -248,7 +271,7 @@ When the document under review is a refactoring plan (modifying existing state m
|
|
|
248
271
|
|
|
249
272
|
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`.
|
|
250
273
|
|
|
251
|
-
### Phase 2a: Structural Primitives
|
|
274
|
+
### Phase 2a: Structural Primitives
|
|
252
275
|
|
|
253
276
|
Run these FIRST. They establish basic well-formedness before adversarial probing.
|
|
254
277
|
|
|
@@ -263,7 +286,7 @@ Run these FIRST. They establish basic well-formedness before adversarial probing
|
|
|
263
286
|
| S7 | **Invariant validity** | Does every reachable state satisfy the plan's stated "always/never/guaranteed" assertions? | Error — plan claim is false |
|
|
264
287
|
| S8 | **Monotonic variables** | If a variable is declared `monotonic: inc/dec`, do all updates respect that direction? | Error — counter can move backwards |
|
|
265
288
|
|
|
266
|
-
### Phase 2b: Adversarial Probes
|
|
289
|
+
### Phase 2b: Adversarial Probes
|
|
267
290
|
|
|
268
291
|
Run these SECOND. Each probe actively tries to BREAK the model. If any probe succeeds (finds a violation), the plan has a behavior gap.
|
|
269
292
|
|
|
@@ -402,6 +425,19 @@ This skill owns behavioural claims. Three neighbouring domains have their own sk
|
|
|
402
425
|
|
|
403
426
|
---
|
|
404
427
|
|
|
428
|
+
## Red Flags
|
|
429
|
+
|
|
430
|
+
If you catch yourself thinking any of these, stop:
|
|
431
|
+
|
|
432
|
+
| You think | Reality |
|
|
433
|
+
|-----------|---------|
|
|
434
|
+
| "Too simple to check" | The check is cheap. The silent skip is not. |
|
|
435
|
+
| "I read the code, so I know" | Knowing is not evidence. Cite `file:line`, or run the model, or call the claim unverified. |
|
|
436
|
+
| "The spec or the diagram says so" | Both are claims about the code. Reconcile them with a source-side scan. |
|
|
437
|
+
| "I'll check while implementing" | Check before the decision, not after. |
|
|
438
|
+
| "Reasoning is enough" | Reasoning is not a run. One counter-example kills a universal claim. |
|
|
439
|
+
| "The report passed, so the code is fine" | The report covers the model you gave it. Reconcile it, and say what you did not check. |
|
|
440
|
+
|
|
405
441
|
## Rules
|
|
406
442
|
|
|
407
443
|
1. Never trust a document's claim without codebase verification.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DSH Model Schema v1 — logicprobe_verify
|
|
2
2
|
|
|
3
|
-
The dsh-native `logicprobe_verify` tool accepts a structured JSON model. The engine runs
|
|
3
|
+
The dsh-native `logicprobe_verify` tool accepts a structured JSON model. The engine runs the structural and adversarial checks (S1-S8, A1-A14) 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
4
|
|
|
5
5
|
## Top-level model
|
|
6
6
|
|
|
@@ -10,14 +10,15 @@ as outside this engine and points at tooling that can handle it.
|
|
|
10
10
|
|
|
11
11
|
| Dimension | What logicprobe covers today | Claim examples | Dedicated tooling | Why not here |
|
|
12
12
|
|---|---|---|---|---|
|
|
13
|
-
| Hard real time (timing) | Order, counts, path budgets (A12)
|
|
13
|
+
| Hard real time (timing) | Order, counts, path budgets (A12), and deadlines over discrete ticks (A14). Time otherwise appears as counters and events | "500 ms to SAFE", "no deadline miss", "period ≤ 1 ms" | UPPAAL, IMITATOR (timed automata); binary-level timing analysis for WCET | No continuous clocks. A deadline that is not a tick count cannot be expressed |
|
|
14
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
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
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
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 |
|
|
19
|
-
|
|
|
20
|
-
|
|
|
18
|
+
| Multi-machine composition | `logicprobe_compose_verify` (dsh) and the engine's `compose` subcommand (non-dsh) check machines together: C1 composition deadlock, C2 a rendezvous that never fires. They stop at one handshake event per rendezvous | "A sends E, B always handles E", "these two never deadlock" | CSP (FDR), mCRL2, TLA+ (compositional models) | No payloads, no rate ratio and no fairness bound; each machine's own step order is free |
|
|
19
|
+
| Protocol semantics (message contents, channels, per-message ordering) | Events and handshakes between machines | "QoS 1 delivers exactly once", "the broker never reorders", "the queue never overflows" | TLA+, mCRL2, SPIN (Promela channels) | The model has states and events, not messages, queues or payloads |
|
|
20
|
+
| Nested/hierarchical statecharts | Flat models only; flatten before verification | parent/child states, orthogonal regions | SCXML / Stateflow (native hierarchy) | A flat state list only. `logicprobe_compose_verify` places machines side by side; it does not nest states. Flatten manually and re-confirm |
|
|
21
|
+
| 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 (it is a dsh-only capability; without it, route the claim by hand) |
|
|
21
22
|
|
|
22
23
|
## Where the routing surfaces
|
|
23
24
|
|
|
@@ -30,8 +31,8 @@ as outside this engine and points at tooling that can handle it.
|
|
|
30
31
|
interrupt-safe, ...) carry `suggestions` naming dedicated tools.
|
|
31
32
|
- Manual review: when reading a plan, match its claims against the table above and
|
|
32
33
|
require dedicated evidence before accepting "always"/"never"/"guaranteed" language
|
|
33
|
-
- Generators: `
|
|
34
|
-
TLA+ (TLC spec + safety), PRISM (.pm + .pctl),
|
|
35
|
-
LogicModelV1
|
|
36
|
-
integers) and
|
|
37
|
-
|
|
34
|
+
- Generators: `logicprobe_export` (dsh) and the engine's `export` subcommand (non-dsh) emit
|
|
35
|
+
native inputs for UPPAAL (.xta + queries), TLA+ (TLC spec + safety), PRISM (.pm + .pctl),
|
|
36
|
+
and SPIN (Promela + ltl) from a LogicModelV1. Both translate the core machine (guards,
|
|
37
|
+
updates, weights; booleans as integers) and return unrepresentable invariants as explicit
|
|
38
|
+
warnings.
|
|
@@ -202,7 +202,7 @@ When a probe finds a counter-example, classify it:
|
|
|
202
202
|
|
|
203
203
|
### Model Fidelity Warning
|
|
204
204
|
|
|
205
|
-
The model is an APPROXIMATION. It models state transitions, not execution semantics. A model that passes
|
|
205
|
+
The model is an APPROXIMATION. It models state transitions, not execution semantics. A model that passes every check (S1-S8 structural, A1-A14) means the plan's LOGIC is consistent — NOT that the implementation will work. Always follow logic verification with code-level review.
|
|
206
206
|
|
|
207
207
|
## Refactoring Verification
|
|
208
208
|
|
|
@@ -41,3 +41,5 @@ The full routing table, including hard-real-time, hybrid-control and execution-c
|
|
|
41
41
|
2. **No absolute language in the answer.** "This is thread-safe" is exactly the claim being mined, not a result this skill can produce.
|
|
42
42
|
3. **One counterexample is enough to refute.** If a race is suspected, the deliverable is the interleaving that breaks it plus the harness that demonstrates it (TSan/Helgrind output), not an argument.
|
|
43
43
|
4. **Sequential targets are out of scope.** If nothing runs concurrently, say so and stop.
|
|
44
|
+
5. **The scanner is dsh-only.** `logicprobe_concurrency_scan` has no mirror subcommand. Without it, mine the text by hand against the keyword table above and route each claim the same way.
|
|
45
|
+
6. **Name the claim and its routing in words.** 「QoS 1 只投递一次」plus the tool that decides it, never a bare check name. A reader who has not memorized this skill's tables learns nothing from an enumeration. The full rule is under "Writing the Answer" in the `logicprobe` skill.
|
|
@@ -92,6 +92,11 @@ The **DataModelV1 shape** is in [`references/data-model-schema.md`](references/d
|
|
|
92
92
|
| DD3 | Delta summary | Warning |
|
|
93
93
|
| DD4 | Breaking change regression | Error/Warning |
|
|
94
94
|
|
|
95
|
+
Every `#` in these tables is a report field, not a name. Write what the check found for the
|
|
96
|
+
reader (「回滚与备份不对称」), in their language; keep the id for a report field quoted
|
|
97
|
+
verbatim, a baseline diff or a test name. The full rule is under "Writing the Answer" in the
|
|
98
|
+
`logicprobe` skill.
|
|
99
|
+
|
|
95
100
|
## Extraction Rule
|
|
96
101
|
|
|
97
102
|
Before writing any verification code, output a data-model table:
|
|
@@ -91,5 +91,6 @@ This tool audits the **diagram**; an include or dependency scan audits the **cod
|
|
|
91
91
|
2. **Quote the rule id for every judged edge.** "Not allowed" without the rule is an opinion; `matchedRules` makes it a finding.
|
|
92
92
|
3. **Run the numbers, never the impression.** An isolated node and a back edge are exactly what a reader misses by eye; that is why the check exists.
|
|
93
93
|
4. **Report the diagram-code difference, not just the diagram.** A structure review that never touches the source is a review of a drawing.
|
|
94
|
+
5. **Report the rule id with its meaning, never the id alone.** Rule 2 keeps the id on every judged edge, so the finding is defensible; the sentence the reader gets says what the edge violated (「HAL 反向依赖了上层」), in their language. The full rule is under "Writing the Answer" in the `logicprobe` skill.
|
|
94
95
|
|
|
95
96
|
The full matrix schema, a worked example and the reconciliation worksheet are in [`references/structure-review-guide.md`](references/structure-review-guide.md).
|
|
@@ -32,6 +32,8 @@ code flow → model (citation per element) → logicprobe_uml action=render →
|
|
|
32
32
|
- **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?
|
|
33
33
|
- **explain-labels** — the parser's own account of labels and comments: the accepted spellings, the form the renderer writes, and which lines it ignores. No diagram needed. It answers "why does my hand-drawn diagram report drift or ignored lines?" without reading the source.
|
|
34
34
|
|
|
35
|
+
The view follows the question, not the machine, and no tool picks it for you. Declare the question with `intent` (`present` / `verify` / `fidelity`) and a view that cannot serve it is refused before any work, with a code that names why. The ordered procedure, the intent-by-action table and those codes are under [Choosing the view](references/uml-modeling-guide.md#choosing-the-view).
|
|
36
|
+
|
|
35
37
|
A host without the tools runs the same four actions through the repository engine. The engine is deliberately single-source — do not copy it into this skill.
|
|
36
38
|
|
|
37
39
|
## A Structure Diagram Is the Dangerous Case, Because It Parses
|
|
@@ -53,5 +55,6 @@ Structural defects: unreachable states, dead ends, ambiguous or non-exhaustive b
|
|
|
53
55
|
3. **Check the verdict before the picture.** `ok: true` with `verdict: "fail"` means the review failed; a diagram whose review failed is not something to show as if it were checked.
|
|
54
56
|
4. **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 — hand those over to the `logicprobe` skill.
|
|
55
57
|
5. **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.
|
|
58
|
+
6. **Name a finding for the reader, not by its code.** `UML017_ROUND_TRIP_MISMATCH` is a report field; the sentence the reader gets says what disagreed (「图里少了 ERROR→COOLDOWN 这条迁移」), in their language. Keep the code for a report field quoted verbatim, a diff or a test name. The full rule is under "Writing the Answer" in the `logicprobe` skill.
|
|
56
59
|
|
|
57
60
|
The full checklist (codes `UML001` to `UML019` plus `UML_NOT_A_STATE_DIAGRAM`), the directive format generated diagrams carry, a worked example, and the limits of each view are in [`references/uml-modeling-guide.md`](references/uml-modeling-guide.md).
|
|
@@ -4,7 +4,17 @@ This guide covers two jobs: drawing a code flow as UML, and reviewing that drawi
|
|
|
4
4
|
|
|
5
5
|
One rule runs through the whole guide. **A diagram is a model, and a model can be wrong.** A tidy flow chart is not evidence about the code. Worse, a diagram that disagrees with the model it came from will mislead every reader who trusts it.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Choosing the view
|
|
8
|
+
|
|
9
|
+
The view follows the question, not the machine. Decide in this order.
|
|
10
|
+
|
|
11
|
+
**1. Is the question about where dependencies point?** Architecture, layering, module
|
|
12
|
+
structure, "may this call that" — that question belongs to the `logicprobe-structure`
|
|
13
|
+
skill, which reads the same component, package, class or deployment text as a dependency
|
|
14
|
+
graph. The state front end refuses that text by name
|
|
15
|
+
(`UML_NOT_A_STATE_DIAGRAM`) instead of reviewing it.
|
|
16
|
+
|
|
17
|
+
**2. Otherwise fix the boundary first, then pick the view by the reader's question.**
|
|
8
18
|
|
|
9
19
|
| Situation | View that answers it |
|
|
10
20
|
|---|---|
|
|
@@ -14,7 +24,65 @@ One rule runs through the whole guide. **A diagram is a model, and a model can b
|
|
|
14
24
|
| "Somebody gave me a diagram. Is it right?" | Any view. Feed it to the review and compare it against the code. |
|
|
15
25
|
| "This diagram and this model disagree." | Feed both to the review. The round-trip check names every difference. |
|
|
16
26
|
|
|
17
|
-
|
|
27
|
+
**3. Check the choice against the next step.** A view that cannot feed the check you are
|
|
28
|
+
about to run is the wrong view, however readable it looks.
|
|
29
|
+
|
|
30
|
+
| Next step | Views that can feed it |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `logicprobe_verify` (S1-S8 and A1-A14) | State or activity: `parse` reads either into a LogicModelV1 |
|
|
33
|
+
| `logicprobe_uml action=review` with a model, for the fidelity check | State or activity: only those round-trip |
|
|
34
|
+
| `logicprobe_uml action=review` with a model alone | Any view. With `kind: "sequence"` the trace is rendered and the fidelity check is reported inapplicable (`UML019`) |
|
|
35
|
+
| A human reading a protocol exchange | Sequence, which is the honest view there |
|
|
36
|
+
|
|
37
|
+
**4. Say that out loud, and the tool refuses a pairing that cannot serve it.** `intent`
|
|
38
|
+
declares what the artifact is for. The check runs before any work, so an impossible
|
|
39
|
+
pairing is a refusal with a code rather than a report about the wrong artifact.
|
|
40
|
+
|
|
41
|
+
| Intent | What it means | Actions that serve it | View it needs |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| `present` | a human is going to read the diagram | render, review | any view the notation can draw |
|
|
44
|
+
| `verify` | it must be parseable into a LogicModelV1 for the engine | render, parse, review | state or activity: a trace cannot be parsed back |
|
|
45
|
+
| `fidelity` | the point is the render-and-reparse proof | review | state or activity: only those round-trip |
|
|
46
|
+
|
|
47
|
+
| `errorCode` | What happened |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `UML_INTENT_UNSERVABLE` | The view exists but cannot serve the intent — a sequence view for `verify` or `fidelity`. |
|
|
50
|
+
| `UML_VIEW_UNREPRESENTABLE` | The `(notation, view)` cell does not exist — PlantUML activity. |
|
|
51
|
+
| `UML_INTENT_MISMATCH` | The intent names something this action does not do — `fidelity` on render (render proves nothing), `present` or `fidelity` on parse (parse returns a model). |
|
|
52
|
+
|
|
53
|
+
Omitting `intent` changes nothing: a sequence view still renders, and a review of one
|
|
54
|
+
still reports `UML019`. The intent is an opt-in statement of purpose, and nothing infers
|
|
55
|
+
it. The CLI mirror takes the same values: `--intent present|verify|fidelity` on
|
|
56
|
+
`uml-render`, `uml-parse` and `uml-review`.
|
|
57
|
+
|
|
58
|
+
When the question is still unclear, model the state machine. It is the safe default, and
|
|
59
|
+
the other views render from the same model afterwards.
|
|
60
|
+
|
|
61
|
+
### Nothing picks the view for you
|
|
62
|
+
|
|
63
|
+
`render` takes `kind` from the caller and defaults to `state`; it never guesses. A guess
|
|
64
|
+
between state and activity would be a presentation decision, and the machine cannot make
|
|
65
|
+
it: the same guarded branch is a state machine to one reader and an error path to another.
|
|
66
|
+
`parse` does detect the notation and the diagram family from the text, and it refuses the
|
|
67
|
+
families it cannot model, by name.
|
|
68
|
+
|
|
69
|
+
Mechanically decidable, and nothing else:
|
|
70
|
+
|
|
71
|
+
- the notation and the family the text declares — a Mermaid header (`stateDiagram`,
|
|
72
|
+
`flowchart`, `sequenceDiagram`, or a known other-family header) or a PlantUML body
|
|
73
|
+
keyword;
|
|
74
|
+
- whether the requested notation-and-kind combination exists at all (PlantUML has no
|
|
75
|
+
activity view here);
|
|
76
|
+
- whether a view can carry the fidelity check (a sequence cannot).
|
|
77
|
+
|
|
78
|
+
Everything else is a fact about the question, not about the artifact. A model can tell you
|
|
79
|
+
its shape — its state count, its guarded branches, its cycles — and its shape does not
|
|
80
|
+
choose the view.
|
|
81
|
+
|
|
82
|
+
Do not use this guide for a behavioural claim about a specific machine. That is the job of
|
|
83
|
+
`logicprobe_verify` (S1-S8 and A1-A14). The review here covers the modelling, not the
|
|
84
|
+
behaviour. Every finding it produces names the engine check that settles the behavioural
|
|
85
|
+
half.
|
|
18
86
|
|
|
19
87
|
## The three views
|
|
20
88
|
|
package/src/compose-tool.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
2
2
|
import type { JsonValue } from './json-value.js'
|
|
3
3
|
import { runCompositionVerification } from './engine.js'
|
|
4
|
+
import { renderReportText } from './report-view.js'
|
|
4
5
|
|
|
5
6
|
export const LOGICPROBE_COMPOSE_TOOL_NAME = 'logicprobe_compose_verify'
|
|
6
7
|
|
|
@@ -26,14 +27,19 @@ export const logicProbeComposeTool = defineTool({
|
|
|
26
27
|
type: 'integer',
|
|
27
28
|
description: 'Maximum composite states to explore. Default 10000.',
|
|
28
29
|
},
|
|
30
|
+
reportView: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
enum: ['digest', 'full'],
|
|
33
|
+
description: 'digest (default) prints the readable body; full prints the structured report, which logicprobe_report_diff needs.',
|
|
34
|
+
},
|
|
29
35
|
},
|
|
30
36
|
output: {
|
|
31
37
|
schema: {
|
|
32
38
|
type: 'json',
|
|
33
39
|
description: 'Composition verification report with C1/C2 findings.',
|
|
34
40
|
},
|
|
35
|
-
render(
|
|
36
|
-
return [{ type: 'text' as const, text:
|
|
41
|
+
render(args, value) {
|
|
42
|
+
return [{ type: 'text' as const, text: renderReportText(value, { full: args.reportView === 'full' }) }]
|
|
37
43
|
},
|
|
38
44
|
},
|
|
39
45
|
timeoutMs: 10_000,
|
package/src/concurrency-tool.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
2
2
|
import type { JsonValue } from './json-value.js'
|
|
3
3
|
import { runConcurrencyScan } from './concurrency.js'
|
|
4
|
+
import { renderReportText } from './report-view.js'
|
|
4
5
|
|
|
5
6
|
export const LOGICPROBE_CONCURRENCY_SCAN_TOOL_NAME = 'logicprobe_concurrency_scan'
|
|
6
7
|
|
|
@@ -20,14 +21,19 @@ export const logicProbeConcurrencyScanTool = defineTool({
|
|
|
20
21
|
required: true,
|
|
21
22
|
description: 'Document or plan text to scan for concurrency-related claims.',
|
|
22
23
|
},
|
|
24
|
+
reportView: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
enum: ['digest', 'full'],
|
|
27
|
+
description: 'digest (default) prints the readable body; full prints the structured report, which logicprobe_report_diff needs.',
|
|
28
|
+
},
|
|
23
29
|
},
|
|
24
30
|
output: {
|
|
25
31
|
schema: {
|
|
26
32
|
type: 'json',
|
|
27
33
|
description: 'Concurrency scan report with findings and summary.',
|
|
28
34
|
},
|
|
29
|
-
render(
|
|
30
|
-
return [{ type: 'text' as const, text:
|
|
35
|
+
render(args, value) {
|
|
36
|
+
return [{ type: 'text' as const, text: renderReportText(value, { full: args.reportView === 'full' }) }]
|
|
31
37
|
},
|
|
32
38
|
},
|
|
33
39
|
timeoutMs: 10_000,
|