dsh-model-everything 0.1.0 → 0.2.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.
@@ -9,22 +9,20 @@ For an unverified design, failure is only a matter of time. Complex code becomes
9
9
 
10
10
  ## When This Skill Applies
11
11
 
12
- **This is the entry point.** If you have any thought of checking whether something about the code is actually true — however small, however informal the claim — load this skill. It owns the doctrine (enumerate the claims, verify each against the code, cite `file:line`, read `verdict` and never `ok`) and the executable verification for behaviour. When the task lands in a neighbouring domain, its routing table below hands it over rather than stretching the doctrine to cover it.
12
+ **This is the entry point.** Load this skill whenever you need to check whether something about the code is true, however small the claim looks. It owns the doctrine: enumerate the claims, verify each against the code, cite `file:line`, read `verdict`. It also owns the executable verification for behaviour. A neighbouring domain goes to its own skill through the routing table below.
13
13
 
14
14
  | The task involves… | What it does |
15
15
  |---|---|
16
- | Any claim about code you want to check — a design doc, spec, plan, review comment, README, commit message, refactor proposal, or a "this is safe / this always holds / this can't deadlock" assertion | Enumerate the verifiable claims (Phase 1), verify each against the codebase with `file:line` evidence (Phase 2), classify the gaps (Phase 3) |
17
- | A state machine or protocol — ≥3 states, guards, ACK/NACK/retry, lock/unlock, start/stop ordering | Build an executable model: S1-S8 structural checks, A1-A14 adversarial probes |
18
- | A quantitative or temporal guarantee — worst-case path cost ≤ budget, "≥90% of runs reach SAFE", "must leave within 2 ticks" | A12 budget, A13 probabilistic reachability, A14 deadlines, each with a counterexample path |
19
- | A handshake or power-up sequencing across two or more components | `model_compose_verify`: C1 composition deadlock, C2 rendezvous that never fires |
20
- | A refactoring that changes state topology or guard conditions | BEFORE/AFTER models compared for behavioral preservation, invariant continuity and deadlock regression (D1-D4) |
21
- | Explicit request to prove code correct, formally verify a module, or check a migration for breakage | Route by domain — the table under [Routing to the Sibling Skills](#routing-to-the-sibling-skills) — and keep the doctrine |
22
- | An architecture or dependency question about a component/package/class diagram | `model-everything-structure`: parse the diagram into a dependency graph and judge every edge against the dependency matrix |
23
- | Whether a design keeps its own declarations — a layering, a responsibility boundary, an interface wider than its callers, a subtype that cannot replace its base | `model-everything-design`: `model_design_review` decides the declared contracts (`DES1`-`DES11`) and reports the graph's shape |
16
+ | Any claim about code: design doc, spec, plan, review comment, README, commit message, refactor proposal, "this is safe", "this always holds", "this can't deadlock" | Enumerate the verifiable claims (Phase 1), verify each with `file:line` evidence (Phase 2), classify the gaps (Phase 3) |
17
+ | A state machine or protocol with three or more states, guards, ACK/NACK/retry, lock/unlock, or start/stop ordering | Build an executable model. Run the S1-S8 structural checks and the A1-A14 adversarial probes |
18
+ | A quantitative or temporal guarantee: worst-case cost within a budget, "90% of runs reach SAFE", "must leave within 2 ticks" | A12 budget, A13 probabilistic reachability, A14 deadlines. Each returns a counterexample path |
19
+ | A handshake or power-up sequence across two or more components | `model_compose_verify`: C1 composition deadlock, C2 rendezvous that never fires |
20
+ | A refactoring that changes state topology or guards | Compare BEFORE and AFTER models for behaviour preservation, invariant continuity and deadlock regression (D1-D4) |
21
+ | An explicit request to prove code correct, verify a module, or check a migration for breakage | Route by domain through [Routing to the Sibling Skills](#routing-to-the-sibling-skills). Keep the doctrine |
22
+ | An architecture or dependency question about a component, package or class diagram | `model-everything-structure`: parse it into a dependency graph, judge every edge against the dependency matrix |
23
+ | Whether a design keeps its own declarations: layering, a responsibility boundary, an interface wider than its callers, a subtype that cannot replace its base | `model-everything-design`: `model_design_review` decides the declared contracts (`DES1`-`DES11`) and reports the graph's shape |
24
24
 
25
- **Catalog budget**: DSH renders only the frontmatter `description`, and truncates it at 500 characters (`dsh-tool-skill`, `DEFAULT_CATALOG_DESCRIPTION_MAX_LENGTH`). Every description in this plugin is written to fit that budget, and the triggers that do not fit live in this table. `tests/skills/run.mjs` fails when any skill's catalog line would be cut, or would lose one of its use-case triggers.
26
-
27
- <HARD-GATE>
25
+ **Catalog budget**: DSH renders only the frontmatter `description` and truncates it at 500 characters. Every description here fits. Triggers that do not fit live in this table.
28
26
 
29
27
  ## Verification Depth (Plan-Mode Gate)
30
28
 
@@ -182,53 +180,23 @@ not a bound on the search.
182
180
 
183
181
  ### Native dsh Tools
184
182
 
185
- | Tool | Covers |
186
- |------|--------|
187
- | `model_verify` | S1-S8 structural + A1-A14 adversarial, including A12 budget / worst-case path cost, A13 probabilistic reachability over a DTMC, and A14 discrete-tick deadlines. `beforeModel` + `stateMapping` add the D1-D4 before/after regression. |
188
- | `model_datamodel_verify` | Data models and schema migrations: DS/DA checks plus the DD1-DD4 data regression. See the `model-everything-datamodel` skill. |
189
- | `model_compose_verify` | Two or more machines checked together (rendezvous handshake semantics): C1 composition deadlock, C2 rendezvous never fires. When `shared` and `accesses` declare a location both machines touch, it also decides the sharing: C3 a declaration that names nothing, C4 an unordered write, C5 a read-modify-write pair the model does not make atomic (the lost update). |
190
- | `model_interleaving_scan` | Mines claims about how work is executed: threads, synchronization, async, interrupts, shared state. Every finding carries a `family`; async terms (async, await, promise, event loop, callback, and their Chinese counterparts) are in the vocabulary, and an absolute async claim such as "non-blocking" is an error like "thread-safe" is. It routes each claim to the tool that decides it - and for a shared location two machines both update, that tool is `model_compose_verify` (C5), not an external analyzer. It proves nothing itself, and it refuses text it can mine nothing from (`CONCURRENCY_NO_CLAIM`) rather than calling it clean. |
191
- | `model_export` | Emits external-checker input from a verified model: UPPAAL, TLA+, PRISM, SPIN. |
192
- | `uml_render` | model → Mermaid/PlantUML source, for any family the notation can draw; a view it cannot draw is refused with the reason. |
193
- | `uml_parse` | diagram text → the model of the family it declares, so a hand-drawn diagram can be checked. |
194
- | `uml_review` | audit the modelling: structural defects, documentation gaps and the render-and-read-back fidelity check. |
195
- | `uml_explain_labels` | print the label and comment contract the parser accepts, for one notation. |
196
- | `uml_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 `model-everything-structure` skill. |
197
- | `model_design_review` | Reviews a design: the shape of its dependency graph, and the contracts the design declares about itself. Violations of a declaration decide the verdict; structural facts are reported as signals and never do. A check with nothing to hold the design to is `skip`, not `pass`. The design domain belongs to the `model-everything-design` skill. |
198
- | `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. |
199
-
200
- These tools are the engine: every capability this plugin claims is one of the tools above. What is not on that list is out of scope, and the skills name where it is answered instead.
201
-
202
- ### Reading a Report: `ok` Is Not a Verdict
183
+ Twelve tools: `model_verify`, `model_compose_verify`, `model_datamodel_verify`, `model_design_review`, `model_interleaving_scan`, `model_export`, `report_diff`, `uml_render`, `uml_parse`, `uml_review`, `uml_explain_labels`, `uml_structure_verify`. Each tool's description states what it decides and what it does not. Read the description before calling it, and read the report's `verdict` afterwards.
203
184
 
204
- Every tool report carries the same outcome contract. **`ok` says a report was produced; `verdict` says how the review went.** A report may be `ok: true` and still be a failed review — gating on `ok` is how a failing verification gets read as a passing one.
185
+ A model is the largest argument these tools take. When it is long, or you have edited it more than once, write it to a file and pass `modelPath` instead of inlining it: a streamed argument that long is where invalid JSON comes from, and the file accepts any formatting.
205
186
 
206
- | Field | Meaning |
207
- |-------|---------|
208
- | `schema` | The versioned report contract (`model-everything/verify/v1`, `model-everything/uml/review/v1`, …). Branch on this instead of sniffing fields. |
209
- | `ran` | The tool executed and produced this report. `false` only when the tool refused the request before running (see `errorCode`/`error`). |
210
- | `verdict` | `pass` \| `pass_with_findings` \| `fail`. **This is the outcome you act on.** |
211
- | `verdictReason` | Why, e.g. `2 error finding(s) (first: S2_NO_TRANSITIONS)` or `no error findings; 3 warning finding(s)`. |
212
- | `findings[]` | `{code, severity, message, detail?, evidence?, path?}`. Any `severity: "error"` forces `verdict: "fail"`. |
213
- | `hashSpec` | Which published model-hash specification `modelHash` follows — see `references/hash-spec.md`. |
214
- | `hashes` | Every hash the report carries, in one place (a model hash, a diagram hash, before/after hashes). |
215
- | `nextSteps[]` | What to do next, derived from the findings; never empty, and identical for two runs over the same input. |
216
- | `metadataKeys[]` | Paths of the `_`-prefixed annotation keys the schema ignored, e.g. `["_source", "_verified", "states[0]._note"]` (present only when the input carried any). |
217
- | `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. |
187
+ These tools carry every capability this plugin claims. Anything outside them is out of scope, and the skills name where that claim is answered instead.
218
188
 
219
- 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 `report_diff`.
189
+ ### Reading a Report: `ok` Is Not a Verdict
220
190
 
221
- Turn the verdict into an answer, never into a summary of `ok`:
191
+ **`ok` records that a report was produced. `verdict` records how the review went.** A report can carry `ok: true` and still be a failed review. Gate on `verdict`.
222
192
 
223
- - `verdict: "pass"` — no error and no warning finding. Safe to report as verified, still with the scope the model covered.
224
- - `verdict: "pass_with_findings"` — verification ran clean, but warnings exist (e.g. `S5` implicit-ignore events, `UML012_NO_TERMINAL`). Report the pass **and** the warnings; do not silently upgrade it to "no issues".
225
- - `verdict: "fail"` — an error-severity finding exists, or the input was rejected (`MODEL_INVALID`). Say plainly that the claim is **not** verified, quote the counterexample path the finding carries, and only then propose a correction. Never describe a `fail` as "the tool ran successfully".
193
+ - `pass`: no error and no warning. Report the result as verified, together with the scope the model covered.
194
+ - `pass_with_findings`: verification ran clean and warnings exist. Report the pass and the warnings. Do not restate it as "no issues".
195
+ - `fail`: an error finding exists, or the engine rejected the input (`MODEL_INVALID`). State that the claim is not verified, quote the counterexample path, then propose a correction. Do not describe a `fail` as a successful run.
226
196
 
227
- 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.
197
+ `summary.truncated: true` and any code ending in `_UNDECIDED` both mean the search stopped before deciding. Name the invariant that went undecided and report the property as undecided.
228
198
 
229
- `summary.truncated: true`, or a finding whose code ends in `_UNDECIDED`, means the search
230
- stopped before deciding. That is **not** a pass: name the invariant that went undecided,
231
- and say the property is undecided rather than reading the silence as success.
199
+ A tool prints a readable body. Passing checks stay in the `CHECKS` inventory line, and a fact that several checks report appears once. Only error findings inline their evidence. When the body truncates a check, pass `check: "<id>"` to print that check in full. `reportView: "full"` returns the whole report as compact JSON. Use it only to hand the report to `report_diff`; it costs the most tokens of any request you can make.
232
200
 
233
201
  ### Writing the Answer: Name the Finding, Not Its Code
234
202
 
@@ -315,24 +283,24 @@ Run these FIRST. They establish basic well-formedness before adversarial probing
315
283
 
316
284
  ### Phase 2b: Adversarial Probes
317
285
 
318
- Run these SECOND. Each probe actively tries to BREAK the model. If any probe succeeds (finds a violation), the plan has a behavior gap.
286
+ Run these second. Each probe tries to break the model, and a probe that finds a violation proves a behaviour gap.
319
287
 
320
- | # | Attack | Method | Target Claim |
288
+ | # | Attack | Method | Claim it refutes |
321
289
  |:--:|--------|--------|-------------|
322
- | A1 | **Unexpected event** | For each state S, inject every event E where no transition is defined for (S, E). Log whether the model silently ignores or crashes. | "All events are handled in all states" |
323
- | A2 | **Race interleaving** | For every pair of concurrent events (E1, E2), simulate arrival in both orders: E1-then-E2 vs E2-then-E1. Flag if terminal state differs. | "Behavior is independent of event ordering" |
324
- | A3 | **Order permutation** | For N independent events, permute arrival order. Flag if different permutations produce different final states or violate invariants. | "Outcome is order-independent" |
325
- | A4 | **Pair symmetry** | Match every `start/stop`, `lock/unlock`, `alloc/free` pair. Flag if any state allows a path where a pair is unbalanced (start without stop, lock without unlock). State `onEntry`/`onExit` actions are treated as implicit acquire/release. | "Resources are always released" |
326
- | A5 | **Boundary blast** | Probe counters at 0, 1, max-1, max, max+1. Probe timestamps at 0, tick_wraparound. Flag overflow, underflow, or undefined behavior. | "Handles all counter/timer values" |
327
- | A6 | **Resource injection** | Simulate `malloc→NULL`, `queue→full`, `semaphore→timeout` at each state that calls them. Flag if any state has no recovery path. | "Graceful degradation under resource pressure" |
328
- | A7 | **Counter-example witness** | For any invariant that fails, find the event sequence that violates it and output the exact path. Breadth-first searches (state predicates, sequence, atomicity, budget) yield the shortest witness; the leads-to walk and the probability bound report the witness they found without claiming minimality. | "This invariant holds" → refuted by a concrete path |
329
- | A8 | **Idempotent replay** | For each event declared in `idempotentEvents`, apply it twice from every reachable state. Flag if the second application changes state or is not replayable. | "This event is safe to retry/replay" |
330
- | A9 | **Leads-to** | From a declared source state, every path must eventually reach the target state, or reach one member of a declared target set. | "This state always progresses to completion" |
331
- | A10 | **Sequence order** | Events declared in a sequence must occur in the specified order. | "backup before modify before commit" |
332
- | A11 | **Atomicity** | Once an atomic event starts, the machine must commit or roll back before leaving the scope or terminating. | "all-or-nothing transaction" |
333
- | A12 | **Budget (worst-case path cost)** | With `cost` on transitions (absent = 1) and a `budget` invariant, every reachable path must stay within budget; reports the shortest over-budget counterexample and flags reachable positive-cost cycles as unbounded. | "Worst-case path cost ≤ budget" |
334
- | A13 | **Probability reachability (DTMC)** | With `weight` on transitions (absent = 1) and a `probability` invariant, P(ever hitting the target) must satisfy the bound; solved by value iteration over the absorbing chain. | "≥ 90% of runs reach SAFE" |
335
- | A14 | **Deadline (discrete tick clock)** | State `maxTicks` plus top-level `tickEvents`: a tick step may not keep a state resident past its deadline; reports the over-residency path. | "must leave within 2 ticks" |
290
+ | A1 | **Unexpected event** | Inject every event E into every state S that has no transition for (S, E). Record whether the model ignores it or crashes. | "All events are handled in all states" |
291
+ | A2 | **Race interleaving** | Deliver every pair of concurrent events in both orders. Report a differing terminal state. | "Behaviour is independent of ordering" |
292
+ | A3 | **Order permutation** | Permute N independent events. Report differing final states or broken invariants. | "Outcome is order-independent" |
293
+ | A4 | **Pair symmetry** | Match every `start/stop`, `lock/unlock`, `alloc/free` pair. Report a path where a pair is unbalanced. `onEntry` and `onExit` count as acquire and release. | "Resources are always released" |
294
+ | A5 | **Boundary blast** | Probe counters at 0, 1, max-1, max and max+1, and timestamps at 0 and wraparound. Report overflow, underflow or undefined behaviour. | "Handles all counter and timer values" |
295
+ | A6 | **Resource injection** | Simulate `malloc` returning NULL, a full queue and a semaphore timeout at each state that calls them. Report a state with no recovery path. | "Degrades gracefully under resource pressure" |
296
+ | A7 | **Counter-example witness** | For a failing invariant, emit the exact violating sequence. The breadth-first searches (state, sequence, atomicity, budget) return the shortest witness. Leads-to and probability return the witness they found without claiming minimality. | "This invariant holds" |
297
+ | A8 | **Idempotent replay** | Apply each `idempotentEvents` entry twice from every reachable state. Report a second application that changes state. | "This event is safe to replay" |
298
+ | A9 | **Leads-to** | From a declared source state, every path must reach the target state or a member of the declared target set. | "Always progresses to completion" |
299
+ | A10 | **Sequence order** | Declared events must occur in the declared order. | "backup before modify before commit" |
300
+ | A11 | **Atomicity** | An atomic event must commit or roll back before the scope is left or the machine terminates. | "all-or-nothing" |
301
+ | A12 | **Budget** | With `cost` per transition (absent means 1) and a `budget` invariant, every reachable path must stay within budget. The probe returns the shortest over-budget path and reports reachable positive-cost cycles as unbounded. | "Worst case fits the budget" |
302
+ | A13 | **Probability reachability** | With `weight` per transition (absent means 1) and a `probability` invariant, P(ever hitting the target) must meet the bound, by value iteration over the absorbing chain. | "90% of runs reach SAFE" |
303
+ | A14 | **Deadline** | State `maxTicks` plus top-level `tickEvents`. A tick step must not keep a state resident past its deadline. The probe returns the over-residency path. | "Must leave within 2 ticks" |
336
304
 
337
305
  ### Integration Back to Phase 3
338
306
 
@@ -469,14 +437,14 @@ If you catch yourself thinking any of these, stop:
469
437
 
470
438
  ## Rules
471
439
 
472
- 1. Never trust a document's claim without codebase verification.
473
- 2. Be honest about mechanism boundaries — if the language standard can't do it, say so.
474
- 3. Cite evidence with specific file:line references.
475
- 4. Don't fix during review — point the way, let implementation happen after approval.
476
- 5. **For behavioral claims: verify with code, not reasoning.** If a plan says "always", "never", or "guaranteed", generate and run a model. One counter-example is enough to refute a universal claim.
477
- 6. **Confirm the model before running it** — unless the user has already told you to proceed without confirmation in this session. Extraction errors are the dominant failure mode of formal verification. In auto mode, substitute evidence-cited extraction + round-trip validation and mark the report `UNCONFIRMED`.
478
- 7. **Don't verify what the code already checks.** If the existing codebase has compile-time assertions, static analysis, or runtime checks for a property, cite those — don't re-verify in a model.
479
- 8. **Hand a neighbouring domain to its own skill.** A diagram is a model, not evidence: modelling or auditing one belongs to `model-everything-uml`. A concurrency claim is mined and routed, never proven here: that is `model-everything-interleaving`. Schema, data invariants and migrations are `model-everything-datamodel`. This skill keeps the doctrine and the behavioural checks.
480
- 9. **Say what this does not prove.** For dimensions this toolbox does not verify — hard real time (deadlines, periods), preemptive concurrency, hybrid-control stability, probabilistic reliability, execution-cost budgets — route to the dedicated tool named in `references/gap-routing-guide.md`. `model_verify` reports carry the same routing as informational `coverageNotes` on matching models.
481
- 10. **A declared range is a property, not a bound, and a capped search is not a pass.** `inc`/`dec` are never clamped to `min`/`max`; only a guard that pins the value bounds it. When a report is `truncated` or a check is `_UNDECIDED`, say the property is undecided and narrow the model — never report it as verified.
482
- 11. **Write-site analysis is out of scope, and stays there.** "Only the ISR writes this flag", "one owner per register" — this toolbox verifies models and diagrams, not *who writes what in the source*. That claim needs a source-side AST/rule check or a static analyzer; this plugin's contribution is to flag the claim as unverified and route it (`model_interleaving_scan` does exactly that). Do not imply the diagram or the model settled it.
440
+ 1. Verify a document's claim against the code before you trust it.
441
+ 2. State mechanism boundaries plainly. When the language standard cannot do the thing, say so.
442
+ 3. Cite evidence as `file:line`.
443
+ 4. Point the way during review. Implementation happens after approval.
444
+ 5. Verify behavioural claims by running code. A plan that says "always", "never" or "guaranteed" gets a model, and one counterexample refutes a universal claim.
445
+ 6. Confirm the model before you run it, unless this session already told you to proceed. Extraction errors are the dominant failure mode of formal verification. In auto mode, extract with cited evidence, validate the round trip, and mark the report `UNCONFIRMED`.
446
+ 7. Cite the existing check instead of re-verifying it. Compile-time assertions, static analysis and runtime checks already settle that property.
447
+ 8. Hand a neighbouring domain to its own skill. A diagram is a model, and auditing one belongs to `model-everything-uml`. A concurrency claim is mined and routed by `model-everything-interleaving`. Schema, data invariants and migrations belong to `model-everything-datamodel`. This skill keeps the doctrine and the behavioural checks.
448
+ 9. Say what this does not prove. Hard real time, preemptive concurrency, hybrid-control stability, probabilistic reliability and execution-cost budgets go to the tool named in `references/gap-routing-guide.md`. `model_verify` reports carry the same routing as `coverageNotes`.
449
+ 10. A declared range is a property, not a bound. `inc` and `dec` are never clamped; only a guard pins the value. A `truncated` report or an `_UNDECIDED` check means the property is undecided. Report it that way.
450
+ 11. Write-site analysis is out of scope. "Only the ISR writes this flag" is a question about source code. `model_interleaving_scan` routes it. Neither the model nor the diagram settles it.
@@ -1,60 +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」一节。
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」一节。
@@ -1,137 +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.
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.