dsh-model-everything 0.0.0-stage → 0.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.
- package/LICENSE +21 -0
- package/README.en-US.md +319 -0
- package/README.md +319 -3
- package/cordis.patch.yml +20 -0
- package/examples/README.md +48 -0
- package/examples/control-dispatcher.json +113 -0
- package/examples/control-dispatcher.overbudget.json +113 -0
- package/examples/ecommerce-data-model.json +185 -0
- package/examples/order-state-machine.after.json +116 -0
- package/examples/order-state-machine.before.json +101 -0
- package/examples/user-migration.after.json +29 -0
- package/examples/user-migration.before.json +29 -0
- package/gate/locale/en.json +6 -0
- package/gate/locale/zh.json +6 -0
- package/gate/package.json +5 -0
- package/lib/baseline.js +249 -0
- package/lib/compose-tool.js +76 -0
- package/lib/concurrency-tool.js +40 -0
- package/lib/concurrency.js +206 -0
- package/lib/data-engine.js +1141 -0
- package/lib/data-tool.js +79 -0
- package/lib/design-engine.js +1149 -0
- package/lib/design-tool.js +55 -0
- package/lib/engine.js +4343 -0
- package/lib/export-tool.js +78 -0
- package/lib/exporters.js +434 -0
- package/lib/gate.js +274 -0
- package/lib/granularity.js +237 -0
- package/lib/index.js +237 -0
- package/lib/json-value.js +18 -0
- package/lib/option-shape.js +62 -0
- package/lib/report-diff-tool.js +63 -0
- package/lib/report-view.js +408 -0
- package/lib/structure-tool.js +91 -0
- package/lib/structure.js +711 -0
- package/lib/tool.js +85 -0
- package/lib/types/baseline.d.ts +65 -0
- package/lib/types/compose-tool.d.ts +7 -0
- package/lib/types/concurrency-tool.d.ts +8 -0
- package/lib/types/concurrency.d.ts +37 -0
- package/lib/types/data-engine.d.ts +211 -0
- package/lib/types/data-tool.d.ts +10 -0
- package/lib/types/design-engine.d.ts +215 -0
- package/lib/types/design-tool.d.ts +11 -0
- package/lib/types/engine.d.ts +494 -0
- package/lib/types/export-tool.d.ts +7 -0
- package/lib/types/exporters.d.ts +37 -0
- package/lib/types/gate.d.ts +91 -0
- package/lib/types/granularity.d.ts +106 -0
- package/lib/types/index.d.ts +45 -0
- package/lib/types/json-value.d.ts +21 -0
- package/lib/types/option-shape.d.ts +22 -0
- package/lib/types/report-diff-tool.d.ts +8 -0
- package/lib/types/report-view.d.ts +43 -0
- package/lib/types/structure-tool.d.ts +10 -0
- package/lib/types/structure.d.ts +152 -0
- package/lib/types/tool.d.ts +11 -0
- package/lib/types/uml-communication.d.ts +109 -0
- package/lib/types/uml-composite.d.ts +107 -0
- package/lib/types/uml-interaction-overview.d.ts +91 -0
- package/lib/types/uml-profile.d.ts +112 -0
- package/lib/types/uml-structure.d.ts +53 -0
- package/lib/types/uml-syntax.d.ts +296 -0
- package/lib/types/uml-timing.d.ts +152 -0
- package/lib/types/uml-tool.d.ts +12 -0
- package/lib/types/uml-usecase.d.ts +58 -0
- package/lib/types/uml.d.ts +303 -0
- package/lib/uml-communication.js +353 -0
- package/lib/uml-composite.js +442 -0
- package/lib/uml-interaction-overview.js +277 -0
- package/lib/uml-profile.js +373 -0
- package/lib/uml-structure.js +306 -0
- package/lib/uml-syntax.js +545 -0
- package/lib/uml-timing.js +974 -0
- package/lib/uml-tool.js +213 -0
- package/lib/uml-usecase.js +532 -0
- package/lib/uml.js +2110 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +124 -6
- package/skills/model-everything/SKILL.md +482 -0
- package/skills/model-everything/references/dsh-model-schema.md +437 -0
- package/skills/model-everything/references/gap-routing-guide.md +42 -0
- package/skills/model-everything/references/hash-spec.md +152 -0
- package/skills/model-everything/references/logic-verification-guide.md +422 -0
- package/skills/model-everything-datamodel/SKILL.md +130 -0
- package/skills/model-everything-datamodel/references/data-model-guide.md +84 -0
- package/skills/model-everything-datamodel/references/data-model-schema.md +128 -0
- package/skills/model-everything-design/SKILL.md +115 -0
- package/skills/model-everything-interleaving/SKILL.md +63 -0
- package/skills/model-everything-interleaving/SKILL.zh-CN.md +60 -0
- package/skills/model-everything-interleaving/references/concurrency-risk-guide.md +63 -0
- package/skills/model-everything-report-reading/SKILL.md +137 -0
- package/skills/model-everything-report-reading/references/reading-a-report.md +166 -0
- package/skills/model-everything-report-reading/references/reading-a-report.mmd +59 -0
- package/skills/model-everything-structure/SKILL.md +96 -0
- package/skills/model-everything-structure/references/structure-review-guide.md +201 -0
- package/skills/model-everything-uml/SKILL.md +60 -0
- package/skills/model-everything-uml/references/uml-modeling-guide.md +551 -0
- package/src/baseline.ts +288 -0
- package/src/compose-tool.ts +78 -0
- package/src/concurrency-tool.ts +44 -0
- package/src/concurrency.ts +254 -0
- package/src/data-engine.ts +1208 -0
- package/src/data-tool.ts +83 -0
- package/src/design-engine.ts +1263 -0
- package/src/design-tool.ts +60 -0
- package/src/engine.ts +4564 -0
- package/src/export-tool.ts +81 -0
- package/src/exporters.ts +399 -0
- package/src/gate.ts +330 -0
- package/src/granularity.ts +312 -0
- package/src/index.ts +289 -0
- package/src/json-value.ts +20 -0
- package/src/option-shape.ts +64 -0
- package/src/report-diff-tool.ts +67 -0
- package/src/report-view.ts +451 -0
- package/src/structure-tool.ts +93 -0
- package/src/structure.ts +786 -0
- package/src/tool.ts +94 -0
- package/src/uml-communication.ts +428 -0
- package/src/uml-composite.ts +520 -0
- package/src/uml-interaction-overview.ts +321 -0
- package/src/uml-profile.ts +439 -0
- package/src/uml-structure.ts +317 -0
- package/src/uml-syntax.ts +764 -0
- package/src/uml-timing.ts +1106 -0
- package/src/uml-tool.ts +230 -0
- package/src/uml-usecase.ts +566 -0
- package/src/uml.ts +2139 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# DataModelV1 — model-everything-datamodel Schema
|
|
2
|
+
|
|
3
|
+
The `model_datamodel_verify` tool accepts a structured JSON data model. The engine runs DS/DA checks, and DD1-DD4 when `beforeModel` is supplied. The schema is host-agnostic: the native tool and the repository engine take the same JSON.
|
|
4
|
+
|
|
5
|
+
## Top-level model
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"schemaVersion": 1,
|
|
10
|
+
"entities": [
|
|
11
|
+
{
|
|
12
|
+
"name": "User",
|
|
13
|
+
"fields": [
|
|
14
|
+
{ "name": "id", "type": "uuid", "required": true, "unique": true },
|
|
15
|
+
{ "name": "email", "type": "string", "required": true, "unique": true }
|
|
16
|
+
],
|
|
17
|
+
"primaryKey": ["id"]
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"relationships": [
|
|
21
|
+
{ "fromEntity": "Order", "fromField": "userId", "toEntity": "User", "toField": "id", "onDelete": "restrict" }
|
|
22
|
+
],
|
|
23
|
+
"invariants": [],
|
|
24
|
+
"boundaryChecks": []
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| Field | Required | Meaning |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `schemaVersion` | yes | Must be `1` |
|
|
31
|
+
| `entities` | yes | `{ name, fields, primaryKey?, uniqueKeys?, indexes? }` |
|
|
32
|
+
| `relationships` | no | `{ fromEntity, fromField, toEntity, toField?, onDelete? }` |
|
|
33
|
+
| `invariants` | no | See invariant kinds below |
|
|
34
|
+
| `boundaryChecks` | no | `{ entity, field, values? }` for DA2 |
|
|
35
|
+
|
|
36
|
+
## Field
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"name": "age",
|
|
41
|
+
"type": "integer",
|
|
42
|
+
"required": true,
|
|
43
|
+
"unique": false,
|
|
44
|
+
"nullable": false,
|
|
45
|
+
"default": 0,
|
|
46
|
+
"min": 0,
|
|
47
|
+
"max": 150,
|
|
48
|
+
"minLength": null,
|
|
49
|
+
"maxLength": null,
|
|
50
|
+
"pattern": null,
|
|
51
|
+
"enum": null,
|
|
52
|
+
"ref": null,
|
|
53
|
+
"items": null,
|
|
54
|
+
"monotonic": null
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Supported `type` values: `string`, `integer`, `number`, `boolean`, `uuid`, `date`, `datetime`, `timestamp`, `json`, `enum`, `array`, `object`, `binary`, or any custom non-empty type name.
|
|
59
|
+
|
|
60
|
+
## Invariants
|
|
61
|
+
|
|
62
|
+
| Kind | Shape | Checks |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `field-required` | `{ entity, field }` | Field must be required |
|
|
65
|
+
| `unique` | `{ entity, fields: [] }` | Unique constraint must exist |
|
|
66
|
+
| `referential-integrity` | `{ entity, field, refEntity, refField? }` | Reference target must exist |
|
|
67
|
+
| `range` | `{ entity, field, min?, max? }` | Range must be respected |
|
|
68
|
+
| `count-equal` | `{ sourceEntity, targetEntity }` | Source/target counts must match |
|
|
69
|
+
| `field-equal` | `{ sourceEntity, sourceField, targetEntity, targetField }` | Two fields must be equal |
|
|
70
|
+
| `no-orphan` | `{ entity, field, refEntity }` | No dangling references |
|
|
71
|
+
| `idempotent-copy` | `{ sourceEntity, targetEntity }` | A matching copy pair must exist; the copy is intended to be replay-safe |
|
|
72
|
+
| `idempotent-migration` | `{ from, to }` | A matching migration mapping must exist; split/merge/drop are flagged as non-idempotent |
|
|
73
|
+
| `monotonic` | `{ entity, field, direction: "inc"\|"dec" }` | Field must move only in the declared direction |
|
|
74
|
+
| `sequence` | `{ steps: ["c1", "m1"] }` | Referenced copy/migration step ids must exist |
|
|
75
|
+
| `leads-to` | `{ entity, field, from, to }` | For enum/status fields, both values must exist |
|
|
76
|
+
| `atomicity` | `{ steps: ["c1", "m1"] }` | Steps must exist; non-atomic transforms and missing backups are flagged |
|
|
77
|
+
|
|
78
|
+
## Tool arguments
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"model": { "...": "AFTER DataModelV1" },
|
|
83
|
+
"beforeModel": { "...": "BEFORE DataModelV1" },
|
|
84
|
+
"fieldMapping": { "User.name": "User.fullName" },
|
|
85
|
+
"copyPairs": [
|
|
86
|
+
{ "id": "c1", "sourceEntity": "Source", "targetEntity": "Target", "mapping": { "a": "x" } }
|
|
87
|
+
],
|
|
88
|
+
"migrationMappings": [
|
|
89
|
+
{ "id": "m1", "from": "User.name", "to": "User.fullName", "transform": "rename" }
|
|
90
|
+
],
|
|
91
|
+
"backupPairs": [
|
|
92
|
+
{ "id": "b1", "sourceEntity": "Source", "targetEntity": "Target", "mapping": { "x": "a" } }
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Checks
|
|
98
|
+
|
|
99
|
+
- **DS1-DS4**: schema well-formedness, required-field completeness, relationship integrity, type/nullability consistency
|
|
100
|
+
- **DA1-DA12**: null/empty injection, boundary blast, uniqueness, referential integrity, migration coverage, copy consistency, rollback/backup symmetry, idempotent constraints, data monotonic, data sequence, data leads-to, data atomicity
|
|
101
|
+
- **DD1-DD4**: data behavior preservation, data invariant continuity, delta summary, breaking-change regression
|
|
102
|
+
|
|
103
|
+
## Minimal example
|
|
104
|
+
|
|
105
|
+
```json
|
|
106
|
+
{
|
|
107
|
+
"schemaVersion": 1,
|
|
108
|
+
"entities": [
|
|
109
|
+
{
|
|
110
|
+
"name": "User",
|
|
111
|
+
"fields": [
|
|
112
|
+
{ "name": "id", "type": "uuid", "required": true },
|
|
113
|
+
{ "name": "age", "type": "integer", "min": 0, "max": 150 }
|
|
114
|
+
],
|
|
115
|
+
"primaryKey": ["id"]
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"boundaryChecks": [
|
|
119
|
+
{ "entity": "User", "field": "age", "values": [-1, 0, 150, 151] }
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Limits
|
|
125
|
+
|
|
126
|
+
- The engine is a design-time static verifier. It does not execute against a live database.
|
|
127
|
+
- Data invariants like `count-equal` and `field-equal` are checked structurally (referenced entities/fields exist) unless sample data is provided in a future version.
|
|
128
|
+
- Follow with runtime tools (Great Expectations, Soda, Pandera) for live data validation.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: model-everything-design
|
|
3
|
+
description: "Use when a design has to keep its own declarations: does the layering hold, do responsibilities match the dependencies they own, can a subtype stand in for its supertype, is an interface wider than its callers. Also reports the graph's shape (cycles and the fewest edges to break them, load-bearing elements, ranks, fan-in/out) without judging the design. A drawing of an architecture audited against a matrix is model-everything-structure. Doctrine: the model-everything skill."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Model Everything — Design Review
|
|
7
|
+
|
|
8
|
+
A design makes claims about itself: which layer may depend on which, which responsibility owns
|
|
9
|
+
which dependency, which subtype may stand in for its supertype. Those claims are checkable, and
|
|
10
|
+
this skill is about checking them — plus the shape of the graph they are drawn on.
|
|
11
|
+
|
|
12
|
+
The claim-verification doctrine it inherits — cite evidence, read `verdict` and never `ok` —
|
|
13
|
+
lives in the `model-everything` skill. Load that one for behaviour (state machines, protocols,
|
|
14
|
+
timing) and `model-everything-structure` for a dependency diagram audited against a matrix.
|
|
15
|
+
Load this one when the question is whether the *design* keeps its own declarations.
|
|
16
|
+
|
|
17
|
+
## The One Rule That Matters Here
|
|
18
|
+
|
|
19
|
+
**This review compares a design against what the design declares. It never says a design is
|
|
20
|
+
good.**
|
|
21
|
+
|
|
22
|
+
Every finding is one of three things, and the report keeps them apart:
|
|
23
|
+
|
|
24
|
+
| Level | What it means | Decides the verdict? |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| **violation** | The design contradicts something it declared. `DES1`, `DES2`, `DES3`, `DES5`, `DES6`, `DES7`, `DES9` | Yes |
|
|
27
|
+
| **signal** | A structural fact, reported without claiming it is wrong. `DES4`, `DES8`, `DES10`, `DES11` | No — it is a warning |
|
|
28
|
+
| **fact** | A count or computed structure, in `facts` | No |
|
|
29
|
+
|
|
30
|
+
A layer is a declaration. If the design declares three layers and one edge runs from the
|
|
31
|
+
first to the third, that is not a style opinion: the declaration is contradicted, and `DES2`
|
|
32
|
+
says so. If instead the design declares layers and one node carries every dependency, the
|
|
33
|
+
report says *that node is load-bearing* and stops there, because whether it should be is a
|
|
34
|
+
question about the design that no model can answer.
|
|
35
|
+
|
|
36
|
+
The same line applies to the principles. `DES7` reports that a subtype refuses an event its
|
|
37
|
+
supertype declares it handles, which is a strengthened precondition and contradicts the
|
|
38
|
+
inheritance the model states (Liskov & Wing, *A Behavioral Notion of Subtyping*, TOPLAS 1994).
|
|
39
|
+
It does not report that the hierarchy is badly designed.
|
|
40
|
+
|
|
41
|
+
## When This Skill Applies
|
|
42
|
+
|
|
43
|
+
| The task involves… | What it does |
|
|
44
|
+
|---|---|
|
|
45
|
+
| "Is the layering right", "does anything reach across a boundary", "where are the tangled parts" | `DES1`-`DES6` over the declared layers, boundaries and required edges |
|
|
46
|
+
| "Does this follow single responsibility", "tag each module's responsibilities" | `DES10` compares the declared responsibilities with the declared dependencies; see the warning below |
|
|
47
|
+
| "Is this interface too fat", "ISP", "does every caller need all of it" | `DES8` unused operations, `DES9` client groups that share no operation |
|
|
48
|
+
| "LSP", "can this subtype replace its base", "is the contract preserved" | `DES7` over `extends`, `transitions`, `forbids` and operation signatures |
|
|
49
|
+
| "Is this abstraction depending on details", "DIP" | `DES11` |
|
|
50
|
+
| A dependency graph whose structure matters more than its rules | `facts`: ranks, fan-in/out, components, density, cyclomatic complexity, mutually reachable groups |
|
|
51
|
+
|
|
52
|
+
## What It Checks
|
|
53
|
+
|
|
54
|
+
| Code | Level | What it means |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `DES1_CYCLE` | violation | A dependency cycle. Reported with the fewest edges whose removal makes the graph acyclic - an exact minimum for small cyclic parts, and an upper bound past that, with `facts.feedbackArcsExact` saying which - plus the largest mutually reachable group. |
|
|
57
|
+
| `DES2_LAYER_ORDER` | violation | An edge that skips a declared layer, an upward edge, or a node two layers both claim. |
|
|
58
|
+
| `DES3_BOUNDARY_LEAK` | violation | An edge across a declared boundary that no `allowedEdges` rule permits. Deny beats allow. |
|
|
59
|
+
| `DES4_LOAD_BEARING_ELEMENT` | signal | An articulation point (removing it disconnects the graph) or a bridge (the only edge joining its two sides). |
|
|
60
|
+
| `DES5_UNDECLARED_NODE` | violation | A node in no declared layer and no declared boundary. |
|
|
61
|
+
| `DES6_MISSING_REQUIRED_EDGE` | violation | A `requiredEdges` entry the architecture does not have. |
|
|
62
|
+
| `DES7_LSP_CONTRACT` | violation | A subtype refuses an event its supertype handles, or an inherited operation changes arity. A differing guard text is a warning: two strings cannot decide whether a precondition was strengthened. |
|
|
63
|
+
| `DES8_ISP_UNUSED_OPERATION` | signal | An interface operation no client in this model calls. |
|
|
64
|
+
| `DES9_ISP_DISJOINT_CLIENTS` | violation | An interface called by client groups that share no operation: two interfaces wearing one name. |
|
|
65
|
+
| `DES10_RESPONSIBILITY_GAP` | signal | A dependency no declared responsibility owns, a responsibility owning nothing, or one dependency claimed by two responsibilities. |
|
|
66
|
+
| `DES11_CONCRETE_DEPENDENCY` | signal | A type declared `interface`/`abstract-class` depending on a declared concrete class. |
|
|
67
|
+
|
|
68
|
+
## `skip` Is Not `pass`
|
|
69
|
+
|
|
70
|
+
A check with nothing to hold the design to reports `skip` and is listed in
|
|
71
|
+
`facts.checksSkipped`. A design that declares no layers cannot violate a layer order — and
|
|
72
|
+
reporting that as a pass would read as "this design's layering was verified". It was not.
|
|
73
|
+
|
|
74
|
+
The same applies to the principle checks, because each needs vocabulary the model must supply:
|
|
75
|
+
|
|
76
|
+
| Check | Needs | Without it |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `DES7` | `transitions` or `forbids` on a type, and `extends` | No behavioural contract is stated, so nothing to compare |
|
|
79
|
+
| `DES8`, `DES9` | `interface` types with `operations`, and `uses` naming what each client calls | No caller list, so "unused" cannot be decided |
|
|
80
|
+
| `DES10` | `responsibilities` with `uses` | No tags, so nothing to compare the dependencies against |
|
|
81
|
+
| `DES11` | A declared `interface`/`abstract-class` and a declared concrete type | Nothing is declared abstract, so inversion is not a question |
|
|
82
|
+
|
|
83
|
+
An empty vocabulary is not a pass. It is a design that declared nothing for those checks.
|
|
84
|
+
|
|
85
|
+
## On Responsibility Tags
|
|
86
|
+
|
|
87
|
+
Tagging a type with its responsibilities is what makes `DES10` possible, and it is worth being
|
|
88
|
+
exact about what it decides. `DES10` compares two declarations the model makes — the
|
|
89
|
+
responsibility list and the dependency list — and reports where they disagree. It cannot say
|
|
90
|
+
whether a responsibility is the right one, whether two responsibilities belong together,
|
|
91
|
+
whether a name is honest, or whether the code implements the split. A tag list that matches the
|
|
92
|
+
dependencies is a *consistent* declaration, not a *good* one, and the report says so.
|
|
93
|
+
|
|
94
|
+
## What This Review Does Not Prove
|
|
95
|
+
|
|
96
|
+
- **It reviews a model, not code.** Whether the code obeys the model is the extractor's
|
|
97
|
+
question. Reconcile with a source-side scan.
|
|
98
|
+
- **LSP is decided only where the contract is stated.** Behavioural substitutability in general
|
|
99
|
+
is not decidable from a design; `DES7` decides the declared fragment — refused events,
|
|
100
|
+
operation arity, guard text that differs. A subtype that is substitutable in the model may
|
|
101
|
+
still violate its base in the implementation.
|
|
102
|
+
- **Guard comparison is textual.** Two guard strings that differ are reported for a reader to
|
|
103
|
+
judge, because whether the difference strengthens or weakens a precondition is not decidable
|
|
104
|
+
from the strings.
|
|
105
|
+
- **`DES4` is about the graph, not the design.** A gateway layer is supposed to be a node
|
|
106
|
+
everything routes through; the point of the finding is that the design did not say so.
|
|
107
|
+
- **The edge count is a minimum only where it says so.** A minimum feedback arc set is NP-hard
|
|
108
|
+
(Garey & Johnson, 1979). `DES1` decides it exactly by subset search while the cyclic part is
|
|
109
|
+
small, and past that limit reports the edges a canonical peel cannot remove - an upper bound.
|
|
110
|
+
`facts.feedbackArcsExact` is the flag, and the wording of the finding follows it.
|
|
111
|
+
- **Complexity numbers are counts, not judgements.** `facts.cyclomatic` is McCabe's `E - V + 2P`
|
|
112
|
+
over the dependency graph; a high number is a fact about the graph.
|
|
113
|
+
- **This is not topology.** Ranks, articulation points, bridges and mutual reachability are
|
|
114
|
+
combinatorial graph properties. Persistent homology and Betti numbers have no established
|
|
115
|
+
reading for a dependency diagram, and this plugin does not compute them.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: model-everything-interleaving
|
|
3
|
+
description: "Use when a design or plan claims concurrency, synchrony or async safety, or names concurrent writers, mutexes, interrupts, async tasks, promises or an event loop. It mines the claims (thread-safe, lock-free, no data race, ISR-safe, non-blocking) and routes each to dedicated verification (TSan, Helgrind, CBMC, TLA+, UPPAAL); it does not prove safety. Doctrine: the model-everything skill."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Model Everything — Concurrency Claims
|
|
7
|
+
|
|
8
|
+
This skill does **not** prove concurrency safety, and no report from it should ever be read as a proof. It mines a document, plan or code review for claims about **how work is executed** - threads, synchronization primitives, async tasks, interrupts, shared state - marks each one `UNVERIFIED`, and routes it to the tool that can actually decide it.
|
|
9
|
+
|
|
10
|
+
The claim-verification doctrine it inherits — enumerate verifiable claims, cite `file:line`, read `verdict` and never `ok` — lives in the `model-everything` skill. Load that one when the task is behavioural verification of a state machine rather than a judgement about concurrency claims.
|
|
11
|
+
|
|
12
|
+
## When This Skill Applies
|
|
13
|
+
|
|
14
|
+
**Only after confirming the target actually has concurrency requirements or behaviour** — multiple threads, async tasks, interrupts, shared state, or parallel execution. If the target is purely sequential, do not invoke concurrency mining; there is nothing to mine.
|
|
15
|
+
|
|
16
|
+
Async counts as concurrency here, and it is the case most often missed: a single-threaded event loop still runs interleaved work, and every failure mode below applies to it.
|
|
17
|
+
|
|
18
|
+
| The claim | How it is treated |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Absolute: "thread-safe", "lock-free", "no data race", "interrupt-safe", "ISR-safe" | error / `UNVERIFIED` unless dedicated evidence is provided |
|
|
21
|
+
| Risk keyword: "race condition", "shared variable", "mutex", "atomic", "shared memory", "critical section", `ISR`, `IRQ`, `NMI`, `disable_irq` / `enable_irq` | warning — review whether the plan actually addresses it |
|
|
22
|
+
| Async: "non-blocking", "never blocks", "no blocking" | error / `UNVERIFIED` — the event loop is a shared resource and the claim is absolute |
|
|
23
|
+
| Async keyword: "async", "await", "promise", "event loop", "callback", "microtask", "coroutine", "fire-and-forget", "backpressure" | warning — review the interleaving, not the vocabulary |
|
|
24
|
+
| Lock/unlock, alloc/free, start/stop pairing where ordering matters | routed to `model_verify` (A4 pair symmetry), which can decide balance inside the modelled machine |
|
|
25
|
+
|
|
26
|
+
In DSH, run the `model_interleaving_scan` tool. For manual review, follow [`references/concurrency-risk-guide.md`](references/concurrency-risk-guide.md).
|
|
27
|
+
|
|
28
|
+
## Routing: What Decides Each Claim
|
|
29
|
+
|
|
30
|
+
Mining a claim is not verifying it. Hand each one to a tool that can:
|
|
31
|
+
|
|
32
|
+
| Dimension | Tool that decides it |
|
|
33
|
+
|---|---|
|
|
34
|
+
| Data races, lock-ordering, lock-free algorithms | ThreadSanitizer, Helgrind, or a model checker over the real code (CBMC) |
|
|
35
|
+
| Interrupt/ISR races, critical sections | RTOS-aware interrupt analysis, or a TLA+ model of the ISR/task interleaving |
|
|
36
|
+
| Protocol-level interleaving of discrete events | `model_verify` (S1-S8 / A1-A14) and `model_compose_verify` (C1/C2) |
|
|
37
|
+
| Async task interleaving, lost wakeups, a handshake that never fires | TLA+ (export from `model_export`), or `model_compose_verify` for the two-task case |
|
|
38
|
+
| A shared location two tasks both update (lost update, unordered write) | `model_compose_verify` with `shared` + `accesses`: C5 reports a read-modify-write pair the model does not make atomic, C4 an unordered write, C3 a declaration that names nothing. Two accesses naming one lock are excluded, and the report counts them |
|
|
39
|
+
| Timeouts, deadlines, a callback that may never arrive | `model_verify` with `maxTicks` + `tickEvents`, or `model_export` -> UPPAAL for clocks |
|
|
40
|
+
| A blocking call inside an async handler, a missing `await`, a promise nobody awaits | **Not decidable here.** A runtime or static check (blocked-event-loop detection, a lint/review of the call path) - name the check, never claim the design is clean |
|
|
41
|
+
| Hard real time: deadlines, periods, preemption | Scheduling analysis (RMA/EDF) and a timing tool — not this toolbox |
|
|
42
|
+
| Probability or reliability claims | PRISM/Storm, fault-tree analysis |
|
|
43
|
+
|
|
44
|
+
The full routing table, including hard-real-time, hybrid-control and execution-cost dimensions, is [`../model-everything/references/gap-routing-guide.md`](../model-everything/references/gap-routing-guide.md). `model_verify` reports carry the same routing as informational `coverageNotes` on matching models.
|
|
45
|
+
|
|
46
|
+
## What an Async Review Cannot See
|
|
47
|
+
|
|
48
|
+
Async defects live in what a model cannot express, so the report must say so rather than imply coverage:
|
|
49
|
+
|
|
50
|
+
1. **A blocking call inside an async handler.** The model has no clock and no runtime; it cannot tell a synchronous read from an awaited one. The claim "the handler is non-blocking" needs a runtime check (event-loop lag, a blocked-loop detector), not a scan.
|
|
51
|
+
2. **A missing `await`.** This is an absent transition, and a model built from the plan will faithfully omit it. Static review of the call path is what catches it; the scan only tells you where to look.
|
|
52
|
+
3. **A lock held across an `await`.** The scanner sees `mutex` and `await` on the same page and cannot see that they overlap. If the location does matter, declare it in `shared` and both sides in `accesses`: `model_compose_verify` reports the pair as C5 when the model does not make it atomic, and counts the pairs a named lock excluded. Whether the lock is really held across the whole operation is still a single-machine question for `model_verify`.
|
|
53
|
+
|
|
54
|
+
Each of these is a place where "no finding" and "no problem" differ. Say which one you checked, and with what.
|
|
55
|
+
|
|
56
|
+
## Rules for This Mode
|
|
57
|
+
|
|
58
|
+
1. **Mining, not proof - except for a declared shared location.** Report a concurrency claim as `UNVERIFIED` with the routing target; never as passing. The one exception is a location two models both touch: hand `shared` and `accesses` to `model_compose_verify`, which decides C3/C4/C5, and quote its verdict with its witness rather than calling the claim unverified.
|
|
59
|
+
2. **No absolute language in the answer.** "This is thread-safe" is exactly the claim being mined, not a result this skill can produce.
|
|
60
|
+
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.
|
|
61
|
+
4. **Sequential targets are out of scope.** If nothing runs concurrently, say so and stop. A single-threaded async service is not sequential: interleaving exists at every `await`.
|
|
62
|
+
5. **The scanner is `model_interleaving_scan`.** If it is not registered in this deployment, mine the text by hand against the keyword table above and route each claim the same way.
|
|
63
|
+
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 `model_verify` skill.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Model Everything —— 并发类断言
|
|
2
|
+
|
|
3
|
+
这项技能**不**证明并发安全,它产出的任何报告都不该被读成证明。它在文档、计划或代码评审里挖出关于**工作怎样被执行**的断言——线程、同步原语、异步任务、中断、共享状态——把每一条标成 `UNVERIFIED`,再转给真正能判定它的工具。
|
|
4
|
+
|
|
5
|
+
它继承的断言核验教义——枚举可核验的断言、给出 `file:line`、读 `verdict` 而不读 `ok`——在 `model-everything` 技能里。当任务是状态机的行为核验、而不是对并发断言下判断时,加载那一份。
|
|
6
|
+
|
|
7
|
+
English: [SKILL.md](SKILL.md)
|
|
8
|
+
|
|
9
|
+
## 什么时候适用
|
|
10
|
+
|
|
11
|
+
**先确认目标真的有并发需求或并发行为**——多线程、异步任务、中断、共享状态、并行执行。目标如果是纯顺序的,就不要启用并发挖掘:那里没有东西可挖。
|
|
12
|
+
|
|
13
|
+
异步也算并发,而且是最常被漏掉的那一种:单线程事件循环照样在交错执行,下面每一条失败模式都适用于它。
|
|
14
|
+
|
|
15
|
+
| 断言 | 怎么处理 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| 绝对式:「thread-safe」「lock-free」「no data race」「interrupt-safe」「ISR-safe」 | error / `UNVERIFIED`,除非给出专门的证据 |
|
|
18
|
+
| 绝对式(异步):「non-blocking」「never blocks」「no blocking」 | error / `UNVERIFIED` —— 事件循环是共享资源,而这句断言是无条件的 |
|
|
19
|
+
| 风险关键词:「race condition」「shared variable」「mutex」「atomic」「shared memory」「critical section」、`ISR`、`IRQ`、`NMI`、`disable_irq` / `enable_irq` | warning —— 检查计划是否真的处理了它 |
|
|
20
|
+
| 异步关键词:「async」「await」「promise」「event loop」「callback」「microtask」「coroutine」「fire-and-forget」「backpressure」 | warning —— 要审的是交错,不是词汇 |
|
|
21
|
+
| lock/unlock、alloc/free、start/stop 这类顺序敏感的配对 | 转给 `model_verify`(A4 配对对称性),它能在被建模的机器上判定是否平衡 |
|
|
22
|
+
|
|
23
|
+
在 DSH 里跑 `model_interleaving_scan` 工具。人工审查请照 [`references/concurrency-risk-guide.md`](references/concurrency-risk-guide.md)。
|
|
24
|
+
|
|
25
|
+
## 路由:每条断言由什么来判定
|
|
26
|
+
|
|
27
|
+
挖出一条断言不等于核验了它。把每一条交给能判定的工具:
|
|
28
|
+
|
|
29
|
+
| 维度 | 判定它的工具 |
|
|
30
|
+
|---|---|
|
|
31
|
+
| 数据竞争、加锁顺序、无锁算法 | ThreadSanitizer、Helgrind,或在真实代码上的模型检查器(CBMC) |
|
|
32
|
+
| 中断/ISR 竞争、临界区 | 具备 RTOS 感知的中断分析,或 ISR 与任务交错顺序的 TLA+ 模型 |
|
|
33
|
+
| 离散事件之间的协议级交错 | `model_verify`(S1-S8 / A1-A14)与 `model_compose_verify`(C1/C2) |
|
|
34
|
+
| 异步任务交错、丢失唤醒、永不发生的握手 | TLA+(由 `model_export` 导出),或两任务情形用 `model_compose_verify` |
|
|
35
|
+
| 两个任务都更新的同一个共享位置(丢更新、无序写) | 用 `shared` + `accesses` 调 `model_compose_verify`:C5 报出模型没有做成原子的读-改-写对,C4 报无序写,C3 报指向不存在对象的声明。两侧点名同一把锁的会被排除,报告会数出来 |
|
|
36
|
+
| 超时、截止期、可能永远不来的回调 | 带 `maxTicks` + `tickEvents` 的 `model_verify`,或 `model_export` → UPPAAL(时钟) |
|
|
37
|
+
| 异步处理器里的阻塞调用、漏掉的 `await`、没人接的 promise | **这里判不了。** 需要运行时或静态检查(事件循环阻塞检测、调用路径的 lint/评审)——说出那个检查名字,绝不要说设计是干净的 |
|
|
38
|
+
| 硬实时:截止期、周期、抢占 | 调度分析(RMA/EDF)与计时工具 —— 不是本工具箱 |
|
|
39
|
+
| 概率或可靠性断言 | PRISM/Storm、故障树分析 |
|
|
40
|
+
|
|
41
|
+
完整路由表(含硬实时、混合控制与执行成本三个维度)在 [`../model-everything/references/gap-routing-guide.md`](../model-everything/references/gap-routing-guide.md)。`model_verify` 的报告会在匹配的模型上,以 informational 的 `coverageNotes` 带上同样的路由。
|
|
42
|
+
|
|
43
|
+
## 异步审查看不到什么
|
|
44
|
+
|
|
45
|
+
异步的缺陷藏在模型表达不了的地方,所以报告必须说出来,而不是暗示自己覆盖了:
|
|
46
|
+
|
|
47
|
+
1. **异步处理器里的阻塞调用。** 模型没有时钟也没有运行时,它分不出同步读取和 `await` 过的读取。「这个处理器是非阻塞的」需要运行时检查(事件循环延迟、阻塞检测器),不是一次扫描。
|
|
48
|
+
2. **漏掉的 `await`。** 那是一个不存在的转移,照着计划建出来的模型会忠实地漏掉它。静态审查调用路径才能抓到;扫描只告诉你该去哪里看。
|
|
49
|
+
3. **跨 `await` 持有的锁。** 扫描器能在同一页上看到 `mutex` 和 `await`,看不出它们重叠。如果这个位置真要较真,就在 `shared` 里声明它、在 `accesses` 里声明两侧:模型没做成原子时 `model_compose_verify` 会报 C5,并数出被命名锁排除掉的对数。锁是否真的在整个操作期间持有,仍是 `model_verify` 的单机问题。
|
|
50
|
+
|
|
51
|
+
这三处都是「没有发现」和「没有问题」不同的地方。说清楚你查了哪一个、用什么查的。
|
|
52
|
+
|
|
53
|
+
## 本模式的规则
|
|
54
|
+
|
|
55
|
+
1. **挖,不是证——除了被声明的共享位置。** 并发断言报成 `UNVERIFIED` 并给出路由目标;永远不要报成通过。唯一的例外是两个模型都碰的那个位置:把 `shared` 与 `accesses` 交给 `model_compose_verify`,它判 C3/C4/C5,你要引用它的 verdict 与见证,而不是把断言说成未核验。
|
|
56
|
+
2. **答案里不许出现绝对语气。**「这是线程安全的」正是被挖的那条断言,不是这项技能能产出的结果。
|
|
57
|
+
3. **一个反例就足以推翻。** 若怀疑存在竞争,交付物是能打破它的那个交错序列,以及把它演出来的 harness(TSan/Helgrind 的输出),而不是一段论证。
|
|
58
|
+
4. **纯顺序的目标不在范围内。** 如果没有东西并发运行,说出来并停下。单线程的异步服务不是纯顺序的:每一个 `await` 处都存在交错。
|
|
59
|
+
5. **扫描器是 `model_interleaving_scan`。** 如果本部署没有注册它,就照上面的关键词表人工挖文本,并按同样的方式路由每一条断言。
|
|
60
|
+
6. **用文字说出断言和它的路由。**「QoS 1 只投递一次」加上判定它的工具,绝不是一个光秃秃的检查项名字。没背下本技能表格的读者,从一串枚举里学不到任何东西。完整规则在 `model_verify` 技能的「Writing the Answer」一节。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Concurrency Risk Mining Guide
|
|
2
|
+
|
|
3
|
+
This plugin 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
|
+
- Async: "non-blocking", "never blocks", "async", "await", "promise", "event loop",
|
|
16
|
+
"callback", "microtask", "coroutine", "fire-and-forget", "backpressure"
|
|
17
|
+
|
|
18
|
+
The families are threads, synchronization, async, interrupts and shared state. A
|
|
19
|
+
single-threaded async service is not sequential: interleaving exists at every `await`.
|
|
20
|
+
|
|
21
|
+
## DSH tool
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
model_interleaving_scan text="..."
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
|
|
29
|
+
- `CONCURRENCY_ABSOLUTE_CLAIM` (error) for guarantees like "thread-safe" / "lock-free" / "no data race" / "non-blocking"
|
|
30
|
+
- `CONCURRENCY_KEYWORD` (warning) for risk-related terms like "race condition" / "shared memory" / "mutex" / "async" / "event loop"
|
|
31
|
+
|
|
32
|
+
Each finding carries a `family` (threads, synchronization, async, interrupts, shared-state), and the routing in its `suggestions` follows the family: threads to TSan/Helgrind/CBMC/TLA+, interrupts to RTOS-aware analysis, async to TLA+/UPPAAL plus the runtime checks a model cannot make.
|
|
33
|
+
|
|
34
|
+
## Manual mining checklist
|
|
35
|
+
|
|
36
|
+
- [ ] Scan for absolute concurrency safety claims.
|
|
37
|
+
- [ ] For each absolute claim, require dedicated evidence: TSan report, model-checking result, formal proof, or a clear design argument.
|
|
38
|
+
- [ ] If no evidence exists, mark the claim `UNVERIFIED` and escalate to concurrency analysis.
|
|
39
|
+
- [ ] Do not treat "uses mutex" as "thread-safe" — synchronization primitives are not proof.
|
|
40
|
+
|
|
41
|
+
## Interrupt safety
|
|
42
|
+
|
|
43
|
+
Interrupt safety is a first-class concurrency dimension in embedded/real-time designs. The scan treats the following as interrupt-related risk points:
|
|
44
|
+
|
|
45
|
+
- `interrupt-safe`, `ISR-safe` → absolute claims (error)
|
|
46
|
+
- `interrupt safety`, `interrupt context`, `ISR`, `IRQ`, `NMI`, `critical section`
|
|
47
|
+
- `disable_irq`, `enable_irq`, `spin_lock_irqsave` → warning, verify pairing and nesting
|
|
48
|
+
|
|
49
|
+
Manual checklist:
|
|
50
|
+
|
|
51
|
+
- [ ] If the design claims "interrupt-safe", require evidence: critical sections, IRQ disable windows, atomic operations, or formal reasoning.
|
|
52
|
+
- [ ] Check that `disable_irq` / `enable_irq` are paired on all paths.
|
|
53
|
+
- [ ] Check that ISR-context code does not call blocking/sleeping primitives.
|
|
54
|
+
- [ ] Check that shared variables between ISR and thread context are protected (atomic, critical section, or lock-free protocol).
|
|
55
|
+
|
|
56
|
+
## Escalation targets
|
|
57
|
+
|
|
58
|
+
- C/C++: ThreadSanitizer, Helgrind
|
|
59
|
+
- Java: JCStress, Java PathFinder
|
|
60
|
+
- General: TLA+, SPIN, Alloy
|
|
61
|
+
- Rust: loom, Shuttle
|
|
62
|
+
|
|
63
|
+
Other semantic dimensions (hard real time, hybrid control, probability/reliability, execution cost) route through the same pattern — see the full table in the `model_verify` skill: `../model-everything/references/gap-routing-guide.md`.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: model-everything-report-reading
|
|
3
|
+
description: "Use when reading a report this plugin returned: what does the verdict mean, why did it come out this way, which field do I act on, and what does the report not prove. It gives the reading order — did it run, what did it decide, what next — where each family keeps its findings, and the two readings that are easy to get backwards. It reads reports; it does not produce or check models. Producing one is model-everything."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Model Everything — Reading a Report
|
|
7
|
+
|
|
8
|
+
Every tool in this plugin returns a report, and a report is a claim about a model. This skill is the
|
|
9
|
+
reading order: which field answers which question, where the findings are in each family, and what
|
|
10
|
+
the report does not prove.
|
|
11
|
+
|
|
12
|
+
Load the `model-everything` skill to *produce* a model or to check a claim. Load this one when a
|
|
13
|
+
report is already in hand and the question is what it says.
|
|
14
|
+
|
|
15
|
+
## The Reading Order
|
|
16
|
+
|
|
17
|
+
Three questions, in this order. Each one can make the next unnecessary.
|
|
18
|
+
|
|
19
|
+
### Did it run?
|
|
20
|
+
|
|
21
|
+
`ran` separates a tool that refused from one that ran, but it answers that question for one kind of
|
|
22
|
+
refusal only. A call refused at the boundary — an argument in the wrong shape, a format that does not
|
|
23
|
+
exist, a notation that is not one — comes back with `ran: false`, an `errorCode`, and a
|
|
24
|
+
`verdictReason` beginning "the tool did not run". Fix the call; there is no verdict to route on.
|
|
25
|
+
|
|
26
|
+
An input the engine's own schema rejects is a different shape and looks like a review: `ran: true`,
|
|
27
|
+
`ok: false`, `verdict: fail`, no `errorCode`, one finding under a check whose id is `MODEL`,
|
|
28
|
+
`DATA_MODEL` or `DESIGN`, and `summary.checksRun: 0`. Read it as "the input is the problem, not the
|
|
29
|
+
design". A model that was actually reviewed examined something, so a non-zero `checksRun` is what
|
|
30
|
+
separates a defective model from a malformed one.
|
|
31
|
+
|
|
32
|
+
A refusal and a failing review need different responses, and `ran` alone does not tell them apart:
|
|
33
|
+
the test is `ran: false`, or `checksRun: 0` beside a check named after the validation.
|
|
34
|
+
|
|
35
|
+
### What did it decide?
|
|
36
|
+
|
|
37
|
+
`verdict` is the answer:
|
|
38
|
+
|
|
39
|
+
| `verdict` | Means |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `pass` | The checks ran and found nothing to report |
|
|
42
|
+
| `pass_with_findings` | Warnings only; nothing decided against the model |
|
|
43
|
+
| `fail` | At least one error finding |
|
|
44
|
+
|
|
45
|
+
Read `verdict`, never `ok`. `ok` carries a different historical meaning in each family — in most it
|
|
46
|
+
is `true` for a failing review, and a composition sets it to `false` when any error-severity finding
|
|
47
|
+
exists — so it cannot be read as a verdict, and reading it as one is how a reader concludes the
|
|
48
|
+
opposite of what the report says. A `verdict: "fail"` is a successful run that found something;
|
|
49
|
+
that is the normal way this plugin tells you about a defect.
|
|
50
|
+
|
|
51
|
+
`verdictReason` is the one-line why and names the first error code. When the verdict is not what you
|
|
52
|
+
expected, start there.
|
|
53
|
+
|
|
54
|
+
### What should I do?
|
|
55
|
+
|
|
56
|
+
`nextSteps` is never empty and is derived from the findings rather than written beside them. It
|
|
57
|
+
names the route to whatever covers the ground the report does not: another check, a
|
|
58
|
+
source-side scan, or an external checker.
|
|
59
|
+
|
|
60
|
+
## Where the Findings Are
|
|
61
|
+
|
|
62
|
+
This is the part that varies, and it is worth knowing before you go looking:
|
|
63
|
+
|
|
64
|
+
| Where | Families |
|
|
65
|
+
|---|---|
|
|
66
|
+
| Inside each check, as `checks[].findings` | `model_verify`, `model_compose_verify`, `model_datamodel_verify`, `model_design_review` |
|
|
67
|
+
| At the top level, as `findings` | `uml_structure_verify`, the `uml` review path, `model_interleaving_scan` |
|
|
68
|
+
| Nowhere — compare `added` / `changed` / `removed` | `report_diff` |
|
|
69
|
+
|
|
70
|
+
A check-carried finding is attributed to a check, and the check carries a status of its own: `pass`,
|
|
71
|
+
`fail`, or `skip`. A top-level finding has no check to attribute it to, which is why those families
|
|
72
|
+
report a `summary` instead.
|
|
73
|
+
|
|
74
|
+
`report_diff` has no findings because its subject is the difference between two other reports.
|
|
75
|
+
`verdict` describes the delta and `currentVerdict` describes the current run on its own terms. They
|
|
76
|
+
differ exactly when the run is not clean but the delta is empty: comparing a failing report against
|
|
77
|
+
itself gives `verdict: "pass", currentVerdict: "fail"`, and both are true — nothing changed, and the
|
|
78
|
+
run fails.
|
|
79
|
+
|
|
80
|
+
## Severity Before Code
|
|
81
|
+
|
|
82
|
+
Within a finding, the severity decides whether it changed the verdict:
|
|
83
|
+
|
|
84
|
+
- **error** — what makes the verdict `fail`;
|
|
85
|
+
- **warning** — reported, does not fail the delta;
|
|
86
|
+
- **info** — context, for example that one element makes an inseparable group of findings;
|
|
87
|
+
- **undecided** — the search stopped before deciding. Not a pass. `summary.truncated` says the same
|
|
88
|
+
for the report as a whole.
|
|
89
|
+
|
|
90
|
+
The code prefix names the check that owns the finding (`S1`, `A4`, `DS5`, `DA2`, `DES12`, `UML023`),
|
|
91
|
+
so a code tells you where to look before you read its message.
|
|
92
|
+
|
|
93
|
+
### A code is for you, not for the person you are answering
|
|
94
|
+
|
|
95
|
+
The codes exist so you can route the finding to the right reference and re-check it. A user who never
|
|
96
|
+
read the report has no idea what `A4_NO_RELEASE_EVENT` means, and a reply that recites codes makes the
|
|
97
|
+
work look opaque while telling them nothing they can act on.
|
|
98
|
+
|
|
99
|
+
**Say what the finding says, in words.** The finding's own `message` is already a sentence written for a
|
|
100
|
+
reader who does not know the codes - use it. Name the code afterwards only if it helps the user find the
|
|
101
|
+
same line in the report, and then give it a meaning: not "S7 failed" but "the invariant is violated - the
|
|
102
|
+
model reaches C after two events (`S7_INVARIANT_VIOLATION`)".
|
|
103
|
+
|
|
104
|
+
The same goes for a check id: `Event Completeness` is the name, `S5` is the label. Lead with the name.
|
|
105
|
+
|
|
106
|
+
A model whose reachable state space is infinite is reported as `S6_UNBOUNDED_VARIABLE`, an error. It
|
|
107
|
+
is a property of the model, not a defect of the search: no search bound would have decided the
|
|
108
|
+
question. When you relay this one, relay the reason: *any* search bound would leave it undecided.
|
|
109
|
+
|
|
110
|
+
## What a Report Does Not Tell You
|
|
111
|
+
|
|
112
|
+
- **It is about the model, not the code.** A clean verdict is evidence about the drawing you
|
|
113
|
+
supplied. Reconciling it with the source is a separate step, and the difference between the two is
|
|
114
|
+
where the finding usually is.
|
|
115
|
+
- **A truncated search decided nothing.** When `truncated` is true, the checks that stopped early
|
|
116
|
+
report themselves as undecided rather than as passes.
|
|
117
|
+
- **A skipped check examined nothing.** `skip` and `pass` are different answers: a check with no
|
|
118
|
+
vocabulary to work with did not look, and saying so is the point.
|
|
119
|
+
|
|
120
|
+
## The Design Review's Three Lists
|
|
121
|
+
|
|
122
|
+
One family splits its findings, and only the first list decides anything:
|
|
123
|
+
|
|
124
|
+
- `violations` — the check level that decides the verdict;
|
|
125
|
+
- `signals` — worth a look, fails nothing;
|
|
126
|
+
- `facts` — no findings at all: one measurement object with the graph's numbers (`density`, `ranks`,
|
|
127
|
+
`articulationPoints`, `feedbackArcs`, `largestCycle`) and `checksSkipped`, which is where a reader
|
|
128
|
+
learns which checks never ran for want of a declaration.
|
|
129
|
+
|
|
130
|
+
No code appears in both lists, so a reader who reads only `violations` sees every finding that
|
|
131
|
+
decided the verdict and none that did not.
|
|
132
|
+
|
|
133
|
+
## Reference
|
|
134
|
+
|
|
135
|
+
[references/reading-a-report.md](references/reading-a-report.md) is the same method with the
|
|
136
|
+
worked detail: the shared skeleton field by field, what each family adds, and where the map that
|
|
137
|
+
structures it lives.
|