dsh-standards 1.2.2 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,79 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1100" height="660" viewBox="0 0 1100 660" role="img" aria-label="dsh-standards dual-channel funnel">
2
+ <defs>
3
+ <filter id="soft" x="-40%" y="-40%" width="180%" height="200%">
4
+ <feDropShadow dx="0" dy="9" stdDeviation="12" flood-color="#1b1735" flood-opacity="0.55"/>
5
+ </filter>
6
+ <pattern id="dots" width="28" height="28" patternUnits="userSpaceOnUse">
7
+ <circle cx="1.3" cy="1.3" r="1.3" fill="#182031"/>
8
+ </pattern>
9
+ <marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
10
+ <path d="M0 0 L10 5 L0 10 z" fill="#8496f5"/>
11
+ </marker>
12
+ </defs>
13
+ <rect width="1100" height="660" fill="#0d1117"/>
14
+ <rect width="1100" height="660" fill="url(#dots)" opacity=".5"/>
15
+ <text x="50" y="58" fill="#f0f3f9" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="32" font-weight="700">dsh-standards</text>
16
+ <text x="50" y="86" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="16">two channels, one report · static never pretends to be runtime</text>
17
+ <rect x="42" y="118" width="292" height="366" rx="20" fill="#121824" stroke="#2a3142"/>
18
+ <text x="62" y="146" fill="#8496f5" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14" font-weight="700">STATIC · DSC-01...13</text>
19
+ <rect x="348" y="118" width="292" height="366" rx="20" fill="#121824" stroke="#2a3142"/>
20
+ <text x="368" y="146" fill="#3fb950" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14" font-weight="700">RUNTIME · L1-L3</text>
21
+
22
+ <rect x="58" y="168" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
23
+ <circle cx="78" cy="199" r="8" fill="#8496f5"/>
24
+ <text x="96" y="194" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">contract</text>
25
+ <text x="96" y="214" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">cordis.patch.yml</text>
26
+ <rect x="58" y="244" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
27
+ <circle cx="78" cy="275" r="8" fill="#8496f5"/>
28
+ <text x="96" y="270" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">manifest</text>
29
+ <text x="96" y="290" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">package.json</text>
30
+ <rect x="58" y="320" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
31
+ <circle cx="78" cy="351" r="8" fill="#8496f5"/>
32
+ <text x="96" y="346" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">layout</text>
33
+ <text x="96" y="366" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">files + imports</text>
34
+ <rect x="58" y="396" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
35
+ <circle cx="78" cy="427" r="8" fill="#8496f5"/>
36
+ <text x="96" y="422" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">docs</text>
37
+ <text x="96" y="442" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">README + topics</text>
38
+ <rect x="364" y="168" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
39
+ <circle cx="384" cy="199" r="8" fill="#3fb950"/>
40
+ <text x="402" y="194" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">install</text>
41
+ <text x="402" y="214" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">cold profile</text>
42
+ <rect x="364" y="244" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
43
+ <circle cx="384" cy="275" r="8" fill="#3fb950"/>
44
+ <text x="402" y="270" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">smoke</text>
45
+ <text x="402" y="290" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">agent step</text>
46
+ <rect x="364" y="320" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
47
+ <circle cx="384" cy="351" r="8" fill="#3fb950"/>
48
+ <text x="402" y="346" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">perf</text>
49
+ <text x="402" y="366" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">p50 / p99</text>
50
+ <rect x="364" y="396" width="260" height="62" rx="13" fill="#161b26" stroke="#2a3142"/>
51
+ <circle cx="384" cy="427" r="8" fill="#3fb950"/>
52
+ <text x="402" y="422" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">evidence</text>
53
+ <text x="402" y="442" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">reproducible</text>
54
+ <path d="M188 484 V504 H672" stroke="#8496f5" stroke-width="2.4" fill="none" marker-end="url(#arr)" opacity=".85"/>
55
+ <path d="M494 484 V496 H672" stroke="#3fb950" stroke-width="2.4" fill="none" marker-end="url(#arr)" opacity=".85"/>
56
+ <rect x="680" y="380" width="176" height="120" rx="18" fill="#161b26" stroke="#8496f5" stroke-width="2.2" filter="url(#soft)"/>
57
+ <text x="700" y="408" fill="#8496f5" font-family="ui-monospace, monospace" font-size="13" font-weight="700">report</text>
58
+ <text x="700" y="436" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="12.5">text</text>
59
+ <text x="700" y="458" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="12.5">json</text>
60
+ <text x="700" y="480" fill="#f0f3f9" font-family="ui-monospace, monospace" font-size="12.5">sarif</text>
61
+ <path d="M856 440 H904" stroke="#8496f5" stroke-width="2.4" fill="none" marker-end="url(#arr)"/>
62
+ <text x="920" y="218" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="13" font-weight="700">EXIT</text>
63
+ <rect x="920" y="240" width="120" height="46" rx="12" fill="#161b26" stroke="#3fb950" stroke-width="1.5"/>
64
+ <text x="938" y="269" fill="#3fb950" font-family="ui-monospace, monospace" font-size="16" font-weight="700">0</text>
65
+ <text x="962" y="269" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">pass</text>
66
+ <rect x="920" y="298" width="120" height="46" rx="12" fill="#161b26" stroke="#d29922" stroke-width="1.5"/>
67
+ <text x="938" y="327" fill="#d29922" font-family="ui-monospace, monospace" font-size="16" font-weight="700">1</text>
68
+ <text x="962" y="327" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">fail</text>
69
+ <rect x="920" y="356" width="120" height="46" rx="12" fill="#161b26" stroke="#d29922" stroke-width="1.5"/>
70
+ <text x="938" y="385" fill="#d29922" font-family="ui-monospace, monospace" font-size="16" font-weight="700">2</text>
71
+ <text x="962" y="385" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">config</text>
72
+ <rect x="920" y="414" width="120" height="46" rx="12" fill="#161b26" stroke="#d29922" stroke-width="1.5"/>
73
+ <text x="938" y="443" fill="#d29922" font-family="ui-monospace, monospace" font-size="16" font-weight="700">3</text>
74
+ <text x="962" y="443" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">runtime</text>
75
+ <text x="680" y="540" fill="#8496f5" font-family="ui-monospace, monospace" font-size="13" font-weight="700">ENTRY / FLOW / BOOST</text>
76
+ <text x="680" y="562" fill="#a8b1c4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">dsh-levels: depth of adoption</text>
77
+
78
+ <text x="50" y="618" fill="#a8b1c4" font-family="ui-monospace, monospace" font-size="12.5">Apache-2.0 + CC-BY-4.0 · PerryLink DSH plugin family</text>
79
+ </svg>
@@ -0,0 +1,79 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1100" height="660" viewBox="0 0 1100 660" role="img" aria-label="dsh-standards dual-channel funnel">
2
+ <defs>
3
+ <filter id="soft" x="-40%" y="-40%" width="180%" height="200%">
4
+ <feDropShadow dx="0" dy="9" stdDeviation="12" flood-color="#1b1735" flood-opacity="0.10"/>
5
+ </filter>
6
+ <pattern id="dots" width="28" height="28" patternUnits="userSpaceOnUse">
7
+ <circle cx="1.3" cy="1.3" r="1.3" fill="#f2f0f8"/>
8
+ </pattern>
9
+ <marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
10
+ <path d="M0 0 L10 5 L0 10 z" fill="#4B67B4"/>
11
+ </marker>
12
+ </defs>
13
+ <rect width="1100" height="660" fill="#ffffff"/>
14
+ <rect width="1100" height="660" fill="url(#dots)" opacity=".5"/>
15
+ <text x="50" y="58" fill="#141419" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="32" font-weight="700">dsh-standards</text>
16
+ <text x="50" y="86" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="16">two channels, one report · static never pretends to be runtime</text>
17
+ <rect x="42" y="118" width="292" height="366" rx="20" fill="#f7f5fc" stroke="#e6e3f0"/>
18
+ <text x="62" y="146" fill="#4B67B4" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14" font-weight="700">STATIC · DSC-01...13</text>
19
+ <rect x="348" y="118" width="292" height="366" rx="20" fill="#f7f5fc" stroke="#e6e3f0"/>
20
+ <text x="368" y="146" fill="#16a34a" font-family="ui-sans-serif, system-ui, sans-serif" font-size="14" font-weight="700">RUNTIME · L1-L3</text>
21
+
22
+ <rect x="58" y="168" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
23
+ <circle cx="78" cy="199" r="8" fill="#4B67B4"/>
24
+ <text x="96" y="194" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">contract</text>
25
+ <text x="96" y="214" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">cordis.patch.yml</text>
26
+ <rect x="58" y="244" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
27
+ <circle cx="78" cy="275" r="8" fill="#4B67B4"/>
28
+ <text x="96" y="270" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">manifest</text>
29
+ <text x="96" y="290" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">package.json</text>
30
+ <rect x="58" y="320" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
31
+ <circle cx="78" cy="351" r="8" fill="#4B67B4"/>
32
+ <text x="96" y="346" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">layout</text>
33
+ <text x="96" y="366" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">files + imports</text>
34
+ <rect x="58" y="396" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
35
+ <circle cx="78" cy="427" r="8" fill="#4B67B4"/>
36
+ <text x="96" y="422" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">docs</text>
37
+ <text x="96" y="442" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">README + topics</text>
38
+ <rect x="364" y="168" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
39
+ <circle cx="384" cy="199" r="8" fill="#16a34a"/>
40
+ <text x="402" y="194" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">install</text>
41
+ <text x="402" y="214" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">cold profile</text>
42
+ <rect x="364" y="244" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
43
+ <circle cx="384" cy="275" r="8" fill="#16a34a"/>
44
+ <text x="402" y="270" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">smoke</text>
45
+ <text x="402" y="290" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">agent step</text>
46
+ <rect x="364" y="320" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
47
+ <circle cx="384" cy="351" r="8" fill="#16a34a"/>
48
+ <text x="402" y="346" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">perf</text>
49
+ <text x="402" y="366" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">p50 / p99</text>
50
+ <rect x="364" y="396" width="260" height="62" rx="13" fill="#ffffff" stroke="#e6e3f0"/>
51
+ <circle cx="384" cy="427" r="8" fill="#16a34a"/>
52
+ <text x="402" y="422" fill="#141419" font-family="ui-monospace, monospace" font-size="13.5" font-weight="700">evidence</text>
53
+ <text x="402" y="442" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">reproducible</text>
54
+ <path d="M188 484 V504 H672" stroke="#4B67B4" stroke-width="2.4" fill="none" marker-end="url(#arr)" opacity=".85"/>
55
+ <path d="M494 484 V496 H672" stroke="#16a34a" stroke-width="2.4" fill="none" marker-end="url(#arr)" opacity=".85"/>
56
+ <rect x="680" y="380" width="176" height="120" rx="18" fill="#ffffff" stroke="#4B67B4" stroke-width="2.2" filter="url(#soft)"/>
57
+ <text x="700" y="408" fill="#4B67B4" font-family="ui-monospace, monospace" font-size="13" font-weight="700">report</text>
58
+ <text x="700" y="436" fill="#141419" font-family="ui-monospace, monospace" font-size="12.5">text</text>
59
+ <text x="700" y="458" fill="#141419" font-family="ui-monospace, monospace" font-size="12.5">json</text>
60
+ <text x="700" y="480" fill="#141419" font-family="ui-monospace, monospace" font-size="12.5">sarif</text>
61
+ <path d="M856 440 H904" stroke="#4B67B4" stroke-width="2.4" fill="none" marker-end="url(#arr)"/>
62
+ <text x="920" y="218" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="13" font-weight="700">EXIT</text>
63
+ <rect x="920" y="240" width="120" height="46" rx="12" fill="#ffffff" stroke="#16a34a" stroke-width="1.5"/>
64
+ <text x="938" y="269" fill="#16a34a" font-family="ui-monospace, monospace" font-size="16" font-weight="700">0</text>
65
+ <text x="962" y="269" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">pass</text>
66
+ <rect x="920" y="298" width="120" height="46" rx="12" fill="#ffffff" stroke="#bc4c00" stroke-width="1.5"/>
67
+ <text x="938" y="327" fill="#bc4c00" font-family="ui-monospace, monospace" font-size="16" font-weight="700">1</text>
68
+ <text x="962" y="327" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">fail</text>
69
+ <rect x="920" y="356" width="120" height="46" rx="12" fill="#ffffff" stroke="#bc4c00" stroke-width="1.5"/>
70
+ <text x="938" y="385" fill="#bc4c00" font-family="ui-monospace, monospace" font-size="16" font-weight="700">2</text>
71
+ <text x="962" y="385" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">config</text>
72
+ <rect x="920" y="414" width="120" height="46" rx="12" fill="#ffffff" stroke="#bc4c00" stroke-width="1.5"/>
73
+ <text x="938" y="443" fill="#bc4c00" font-family="ui-monospace, monospace" font-size="16" font-weight="700">3</text>
74
+ <text x="962" y="443" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12.5">runtime</text>
75
+ <text x="680" y="540" fill="#4B67B4" font-family="ui-monospace, monospace" font-size="13" font-weight="700">ENTRY / FLOW / BOOST</text>
76
+ <text x="680" y="562" fill="#4d5261" font-family="ui-sans-serif, system-ui, sans-serif" font-size="12">dsh-levels: depth of adoption</text>
77
+
78
+ <text x="50" y="618" fill="#4d5261" font-family="ui-monospace, monospace" font-size="12.5">Apache-2.0 + CC-BY-4.0 · PerryLink DSH plugin family</text>
79
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-standards",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "DSH plugin standards and conformance checks: ENTRY/FLOW checks plus BOOST guidance. Non-official; no certification or ranking.",
5
5
  "type": "module",
6
6
  "main": "40-checker/src/index.mjs",
package/spec/README.md CHANGED
@@ -16,6 +16,7 @@ Machine-readable:
16
16
  - [reference-suite.json](reference-suite.json) — versioned samples, anchors, change rules.
17
17
  - [remediation.json](remediation.json) — 68-key advice table for the additive `advice[]` report field (docs anchors + severity hints).
18
18
  - [schemas/evidence.schema.json](schemas/evidence.schema.json) — `dsh-levels/1` record.
19
+ - [schemas/advice.schema.json](schemas/advice.schema.json) — `dsh-advice/1` entry array: the additive `advice[]` field of a `dsh-conformance/1` report (13 required fields; `why`/`fix`/`docsUrl` may be null; `evidence` ≤ 10; `gate`/`severity` ∈ {FAIL,WARN}).
19
20
  - [flow-evidence.schema.json](flow-evidence.schema.json) — `dsh-flow-evidence/2` FLOW chain (J1–J8 checks, subject/host binding, `evidenceHash`). v1 and bare `{Jx:{status}}` rows are deprecated and never count as a pass.
20
21
  - [schemas/attestation.schema.json](schemas/attestation.schema.json) — `dsh-attestation/1` quality record.
21
22
  - [schemas/report.schema.json](schemas/report.schema.json) — `dsh-report/1` inspection report (no grade).
@@ -26,4 +27,5 @@ Rules:
26
27
 
27
28
  - Levels depend on `common` only; do not import each other.
28
29
  - A level is not a certification, badge, grade, or score.
30
+ - CI attribution (`producer.runUrl`/`repository`/`commit`) is read from the runner environment and is self-declared: **CI 归属 ≠ 证明**. It never upgrades `claims.claimLevel`, and `level-audit` reports it only as `attestation: ci | self-declared`.
29
31
  - `dsh-standard` is an alias; `dsh-standards` is canonical.
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "producer": {
31
31
  "type": "object",
32
- "description": "Who collected the evidence. `kind: sandbox` is the producer-side equivalent of `claims.claimLevel: sandbox-attested` and is one of the two ways a document may be reported as FLOW runtime.",
32
+ "description": "Who collected the evidence. `kind: sandbox` is the producer-side equivalent of `claims.claimLevel: sandbox-attested` and is one of the two ways a document may be reported as FLOW runtime. `provider`/`runId`/`repository`/`commit`/`runUrl` are copied from the runner environment (GITHUB_*) and are self-declared: CI attribution is not proof that the commands ran.",
33
33
  "additionalProperties": false,
34
34
  "required": ["command", "at"],
35
35
  "properties": {
@@ -48,7 +48,11 @@
48
48
  },
49
49
  "runner": { "type": "string" },
50
50
  "actor": { "type": "string" },
51
- "runUrl": { "type": "string" }
51
+ "runUrl": { "type": "string", "description": "CI run URL. Self-declared, display-only." },
52
+ "provider": { "type": "string", "description": "CI provider id (for example github-actions). Self-declared." },
53
+ "runId": { "type": "string", "description": "CI run id (GITHUB_RUN_ID). Self-declared." },
54
+ "repository": { "type": "string", "description": "CI repository (GITHUB_REPOSITORY). Self-declared." },
55
+ "commit": { "type": "string", "pattern": "^[0-9a-f]{40}$", "description": "CI commit (GITHUB_SHA). Self-declared." }
52
56
  }
53
57
  },
54
58
  "subject": {
@@ -0,0 +1,92 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/PerryLink/dsh-standards/spec/schemas/advice.schema.json",
4
+ "title": "DSH advice entry array (dsh-advice/1)",
5
+ "description": "The additive `advice[]` field of a dsh-conformance/1 report. One entry per (check, key) finding; advice never changes the verdict. 13 fields are required; `ruleMissing` is an optional diagnostic emitted when spec/remediation.json has no rule for a key. `version` is the producing package version, not this schema version.",
6
+ "type": "array",
7
+ "items": {
8
+ "type": "object",
9
+ "additionalProperties": false,
10
+ "required": [
11
+ "key",
12
+ "gate",
13
+ "severity",
14
+ "title",
15
+ "why",
16
+ "fix",
17
+ "docsUrl",
18
+ "source",
19
+ "version",
20
+ "evidence",
21
+ "reason",
22
+ "occurrences",
23
+ "advisory"
24
+ ],
25
+ "properties": {
26
+ "key": {
27
+ "type": "string",
28
+ "minLength": 1,
29
+ "description": "Clause or gate key the advice is attached to (for example C-2.2)."
30
+ },
31
+ "gate": {
32
+ "enum": ["FAIL", "WARN"],
33
+ "description": "Result of the owning check after report adjustments."
34
+ },
35
+ "severity": {
36
+ "enum": ["FAIL", "WARN"],
37
+ "description": "Rendered severity; follows `gate` in dsh-advice/1."
38
+ },
39
+ "title": {
40
+ "type": "string",
41
+ "minLength": 1,
42
+ "description": "Short human title; falls back to the key when the rule table has no title."
43
+ },
44
+ "why": {
45
+ "type": ["string", "null"],
46
+ "description": "Why the finding matters; null when the rule table has no explanation."
47
+ },
48
+ "fix": {
49
+ "type": ["string", "null"],
50
+ "description": "Concrete remediation; null when the rule table has no fix."
51
+ },
52
+ "docsUrl": {
53
+ "type": ["string", "null"],
54
+ "format": "uri",
55
+ "description": "Release-pinned documentation URL; null when the rule has no docs anchor."
56
+ },
57
+ "source": {
58
+ "type": "string",
59
+ "minLength": 1,
60
+ "description": "Check id that produced the finding (DSC-xx)."
61
+ },
62
+ "version": {
63
+ "type": "string",
64
+ "minLength": 1,
65
+ "description": "Version of the producing package (dsh-standards)."
66
+ },
67
+ "evidence": {
68
+ "type": "array",
69
+ "maxItems": 10,
70
+ "items": { "type": "string" },
71
+ "description": "Up to 10 deduplicated evidence references."
72
+ },
73
+ "reason": {
74
+ "type": "string",
75
+ "description": "Diagnostic reason(s); may be empty. Not used for the verdict."
76
+ },
77
+ "occurrences": {
78
+ "type": "integer",
79
+ "minimum": 1,
80
+ "description": "How many duplicate details were merged into this entry."
81
+ },
82
+ "advisory": {
83
+ "type": "boolean",
84
+ "description": "True when the owning check is advisory and never moves the verdict."
85
+ },
86
+ "ruleMissing": {
87
+ "type": "boolean",
88
+ "description": "Optional diagnostic: spec/remediation.json has no rule for `key`."
89
+ }
90
+ }
91
+ }
92
+ }