@runbooks/schema 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.md +22 -0
- package/dist/agent-skills.test.d.ts +1 -0
- package/dist/agent-skills.test.js +71 -0
- package/dist/capabilities.d.ts +40 -0
- package/dist/capabilities.js +211 -0
- package/dist/capabilities.test.d.ts +1 -0
- package/dist/capabilities.test.js +119 -0
- package/dist/content-classes.test.d.ts +1 -0
- package/dist/content-classes.test.js +77 -0
- package/dist/generate.cli.d.ts +2 -0
- package/dist/generate.cli.js +27 -0
- package/dist/generate.d.ts +54 -0
- package/dist/generate.js +133 -0
- package/dist/generate.test.d.ts +1 -0
- package/dist/generate.test.js +85 -0
- package/dist/generated.d.ts +101 -0
- package/dist/generated.js +9 -0
- package/dist/generated.ts +82 -0
- package/dist/hash.d.ts +36 -0
- package/dist/hash.js +102 -0
- package/dist/hash.test.d.ts +1 -0
- package/dist/hash.test.js +54 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +61 -0
- package/dist/index.test.d.ts +1 -0
- package/dist/index.test.js +236 -0
- package/dist/interpolation.d.ts +11 -0
- package/dist/interpolation.js +34 -0
- package/dist/node.d.ts +41 -0
- package/dist/node.js +111 -0
- package/dist/p1.test.d.ts +1 -0
- package/dist/p1.test.js +87 -0
- package/dist/run-report.test.d.ts +1 -0
- package/dist/run-report.test.js +145 -0
- package/dist/served.d.ts +36 -0
- package/dist/served.js +128 -0
- package/dist/stats.d.ts +17 -0
- package/dist/stats.js +23 -0
- package/dist/stats.test.d.ts +1 -0
- package/dist/stats.test.js +32 -0
- package/dist/validate.d.ts +16 -0
- package/dist/validate.js +46 -0
- package/dist/validate.test.d.ts +1 -0
- package/dist/validate.test.js +61 -0
- package/dist/vocabularies.test.d.ts +1 -0
- package/dist/vocabularies.test.js +77 -0
- package/package.json +50 -0
- package/spec/v1/schema/attestation.json +62 -0
- package/spec/v1/schema/p0.json +383 -0
- package/spec/v1/schema/p1.json +408 -0
- package/spec/v1/schema/record.json +908 -0
- package/spec/v1/schema/run-report-envelope.json +25 -0
- package/spec/v1/schema/run-report.json +121 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://runbooks.directory/spec/v1/schema/attestation.json",
|
|
4
|
+
"title": "Runbook attestation v1",
|
|
5
|
+
"description": "A signed claim about a run of a specific version of a specific document (RUNBOOK.md 8). T3 exists so that trust can rise above what the catalog can check statically without the catalog owning a runner, which means a third party has to be able to issue a claim we can verify. The subject binds to content_hash rather than to a name: a rename cannot move an attestation and an edit cannot inherit one. The signable bytes are defined in spec/v1/attestations.md and must be byte-identical across implementations.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["attestation_schema", "predicate_type", "subject", "predicate", "signatures"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"attestation_schema": { "const": "runbook-attestation/v1" },
|
|
11
|
+
"predicate_type": { "const": "https://runbooks.directory/attestation/run/v1" },
|
|
12
|
+
"subject": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"required": ["runbook", "semver", "content_hash"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"runbook": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"pattern": "^(std|[a-z][a-z0-9-]{0,30}[a-z0-9]|github:[A-Za-z0-9][A-Za-z0-9-]{0,38}|domain:[a-z0-9.-]+)/[a-z0-9]+(-[a-z0-9]+)*$"
|
|
20
|
+
},
|
|
21
|
+
"semver": { "type": "string", "pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" },
|
|
22
|
+
"content_hash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"predicate": {
|
|
26
|
+
"type": "object",
|
|
27
|
+
"additionalProperties": false,
|
|
28
|
+
"required": ["issuer", "env_class", "outcome", "runtime_profile", "issued_at"],
|
|
29
|
+
"properties": {
|
|
30
|
+
"issuer": {
|
|
31
|
+
"type": "string",
|
|
32
|
+
"format": "uri",
|
|
33
|
+
"description": "An identity a verifier can look up, not a display name. Its origin is where the key set is found."
|
|
34
|
+
},
|
|
35
|
+
"env_class": { "enum": ["local", "ci", "staging", "prod"] },
|
|
36
|
+
"outcome": { "enum": ["success", "failed", "aborted", "partial"] },
|
|
37
|
+
"runtime_profile": { "enum": ["R0", "R1", "R2"] },
|
|
38
|
+
"issued_at": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"format": "date",
|
|
41
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
|
|
42
|
+
"description": "A date, not a timestamp: §14's reasoning applies to anything that leaves a machine."
|
|
43
|
+
},
|
|
44
|
+
"report_hash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"signatures": {
|
|
48
|
+
"type": "array",
|
|
49
|
+
"minItems": 1,
|
|
50
|
+
"description": "A statement with no signature is a draft, not an attestation.",
|
|
51
|
+
"items": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"additionalProperties": false,
|
|
54
|
+
"required": ["key_id", "sig"],
|
|
55
|
+
"properties": {
|
|
56
|
+
"key_id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$" },
|
|
57
|
+
"sig": { "type": "string", "pattern": "^[A-Za-z0-9+/]{86}==$", "description": "base64 of 64 Ed25519 bytes." }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://runbooks.directory/spec/v1/schema/p0.json",
|
|
4
|
+
"title": "Runbook, profile P0",
|
|
5
|
+
"description": "Frontmatter for a P0 (prose) runbook. A superset of Agent Skills: `name` and `description` keep their Agent Skills meaning at the top level, and everything this specification adds lives under the single `runbook` key. See docs/decisions/Q2-frontmatter-namespacing.md.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"name",
|
|
9
|
+
"description",
|
|
10
|
+
"runbook"
|
|
11
|
+
],
|
|
12
|
+
"additionalProperties": true,
|
|
13
|
+
"properties": {
|
|
14
|
+
"name": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
|
|
17
|
+
"maxLength": 64,
|
|
18
|
+
"description": "Agent Skills field. ASCII slug, never reused (\u00a79)."
|
|
19
|
+
},
|
|
20
|
+
"description": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"minLength": 16,
|
|
23
|
+
"maxLength": 1024,
|
|
24
|
+
"description": "Agent Skills field. What the procedure does and when to reach for it."
|
|
25
|
+
},
|
|
26
|
+
"runbook": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"required": [
|
|
30
|
+
"schema_version",
|
|
31
|
+
"profile",
|
|
32
|
+
"domain",
|
|
33
|
+
"targets",
|
|
34
|
+
"trigger",
|
|
35
|
+
"execution",
|
|
36
|
+
"risk",
|
|
37
|
+
"capabilities",
|
|
38
|
+
"publisher",
|
|
39
|
+
"lang",
|
|
40
|
+
"license",
|
|
41
|
+
"source"
|
|
42
|
+
],
|
|
43
|
+
"properties": {
|
|
44
|
+
"schema_version": {
|
|
45
|
+
"const": "v1"
|
|
46
|
+
},
|
|
47
|
+
"id": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"pattern": "^rb_[0-9A-HJKMNP-TV-Z]{26}$",
|
|
50
|
+
"description": "ULID assigned by the catalog. Immutable, survives renames (\u00a79). Absent in an authored document."
|
|
51
|
+
},
|
|
52
|
+
"semver": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-[0-9A-Za-z.-]+)?$",
|
|
55
|
+
"description": "The version this snapshot is. Assigned by the catalog alongside `id` and `content_hash`; absent in an authored document, present in everything the catalog serves."
|
|
56
|
+
},
|
|
57
|
+
"content_hash": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"pattern": "^sha256:[0-9a-f]{64}$",
|
|
60
|
+
"description": "What this version is (RUNBOOK.md 9). Agent pins point at it and attestations bind to it. Computed over the document with this field and x-layout excluded, so it cannot be part of what it hashes."
|
|
61
|
+
},
|
|
62
|
+
"profile": {
|
|
63
|
+
"enum": [
|
|
64
|
+
"P0",
|
|
65
|
+
"P1",
|
|
66
|
+
"P2"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"min_runtime_profile": {
|
|
70
|
+
"enum": [
|
|
71
|
+
"R0",
|
|
72
|
+
"R1",
|
|
73
|
+
"R2"
|
|
74
|
+
],
|
|
75
|
+
"description": "Lowest client runtime profile permitted to follow this runbook (\u00a713.3). A client refuses a document whose minimum exceeds what it enforces."
|
|
76
|
+
},
|
|
77
|
+
"domain": {
|
|
78
|
+
"enum": [
|
|
79
|
+
"incident-response",
|
|
80
|
+
"data-pipelines",
|
|
81
|
+
"llm-ops",
|
|
82
|
+
"agent-workflows",
|
|
83
|
+
"cloud-infra",
|
|
84
|
+
"databases",
|
|
85
|
+
"ci-cd",
|
|
86
|
+
"security"
|
|
87
|
+
],
|
|
88
|
+
"description": "Closed list, changed only by RFC (\u00a74). Navigation and URLs, not classification."
|
|
89
|
+
},
|
|
90
|
+
"targets": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"minItems": 1,
|
|
93
|
+
"uniqueItems": true,
|
|
94
|
+
"items": {
|
|
95
|
+
"type": "string",
|
|
96
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"trigger": {
|
|
100
|
+
"enum": [
|
|
101
|
+
"alert",
|
|
102
|
+
"symptom",
|
|
103
|
+
"scheduled",
|
|
104
|
+
"manual",
|
|
105
|
+
"agent-invoked"
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
"execution": {
|
|
109
|
+
"enum": [
|
|
110
|
+
"human-only",
|
|
111
|
+
"human-with-agent",
|
|
112
|
+
"agent-autonomous"
|
|
113
|
+
]
|
|
114
|
+
},
|
|
115
|
+
"risk": {
|
|
116
|
+
"enum": [
|
|
117
|
+
"read-only",
|
|
118
|
+
"reversible-write",
|
|
119
|
+
"destructive",
|
|
120
|
+
"irreversible"
|
|
121
|
+
]
|
|
122
|
+
},
|
|
123
|
+
"blast_radius": {
|
|
124
|
+
"enum": [
|
|
125
|
+
"resource",
|
|
126
|
+
"service",
|
|
127
|
+
"cluster",
|
|
128
|
+
"tenant",
|
|
129
|
+
"global"
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"duration": {
|
|
133
|
+
"enum": [
|
|
134
|
+
"<5m",
|
|
135
|
+
"5-30m",
|
|
136
|
+
">30m"
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
"capabilities": {
|
|
140
|
+
"type": "array",
|
|
141
|
+
"uniqueItems": true,
|
|
142
|
+
"description": "A privilege request, not a description (\u00a72). A client MUST check it against its own allowlist before execution (\u00a712).",
|
|
143
|
+
"items": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"pattern": "^(mcp:[a-z0-9][a-z0-9-]*|cli:[a-z0-9][a-z0-9._-]*|iam:[a-z0-9-]+:[A-Za-z0-9*]+)$"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"applies_to": {
|
|
149
|
+
"type": "object",
|
|
150
|
+
"additionalProperties": {
|
|
151
|
+
"type": "string"
|
|
152
|
+
},
|
|
153
|
+
"description": "Version ranges per target, e.g. {\"postgres\": \">=14 <17\"}."
|
|
154
|
+
},
|
|
155
|
+
"publisher": {
|
|
156
|
+
"type": "string",
|
|
157
|
+
"pattern": "^(std|[a-z0-9][a-z0-9-]{0,38}|github:[A-Za-z0-9][A-Za-z0-9-]{0,38}|domain:[a-z0-9.-]+\\.[a-z]{2,})$",
|
|
158
|
+
"description": "Namespace (\u00a77). Claimed, not granted, except `std` which is ours."
|
|
159
|
+
},
|
|
160
|
+
"lang": {
|
|
161
|
+
"type": "string",
|
|
162
|
+
"pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$",
|
|
163
|
+
"default": "en"
|
|
164
|
+
},
|
|
165
|
+
"title_en": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"maxLength": 200
|
|
168
|
+
},
|
|
169
|
+
"summary_en": {
|
|
170
|
+
"type": "string",
|
|
171
|
+
"maxLength": 1024
|
|
172
|
+
},
|
|
173
|
+
"translation_of": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"pattern": "^rb_[0-9A-HJKMNP-TV-Z]{26}$"
|
|
176
|
+
},
|
|
177
|
+
"derived_from": {
|
|
178
|
+
"type": "string",
|
|
179
|
+
"pattern": "^rb_[0-9A-HJKMNP-TV-Z]{26}$",
|
|
180
|
+
"description": "The catalog record this was adapted from, when the original is itself in the catalog. Attribution for an adaptation is its source (RUNBOOK.md 10.2), which every record carries; this is the edge that lets a reader see both and keeps deduplication from counting one procedure twice. Requiring it of an adaptation whose original is not in the catalog would be requiring a link to nothing."
|
|
181
|
+
},
|
|
182
|
+
"content_class": {
|
|
183
|
+
"enum": [
|
|
184
|
+
"ingested",
|
|
185
|
+
"adapted",
|
|
186
|
+
"submitted",
|
|
187
|
+
"curated"
|
|
188
|
+
],
|
|
189
|
+
"description": "How this record got here (RUNBOOK.md 15). `adapted` means the procedure derives from somebody else's document under a licence that allows it, whether a machine segmented it or a person rewrote it by hand. It is the one class with a rule of its own: it does not publish without a human confirming the step segmentation and the risk labelling, because an unreviewed machine adaptation is what that rule is guarding against. Its attribution is `source`, which is mandatory for every record."
|
|
190
|
+
},
|
|
191
|
+
"license": {
|
|
192
|
+
"type": "string",
|
|
193
|
+
"minLength": 2,
|
|
194
|
+
"description": "SPDX identifier. Mandatory: an undetectable licence means the record is not ingested at all (\u00a710.2)."
|
|
195
|
+
},
|
|
196
|
+
"keywords": {
|
|
197
|
+
"type": "array",
|
|
198
|
+
"uniqueItems": true,
|
|
199
|
+
"items": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"maxLength": 40
|
|
202
|
+
},
|
|
203
|
+
"description": "The pressure valve for anything that is not a facet: uncontrolled, unguaranteed, not filterable (\u00a74)."
|
|
204
|
+
},
|
|
205
|
+
"inputs": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"description": "Declared parameters. Interpolation may reference only these, and a missing required input aborts a run rather than interpolating empty (\u00a75).",
|
|
208
|
+
"additionalProperties": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"additionalProperties": false,
|
|
211
|
+
"required": [
|
|
212
|
+
"type"
|
|
213
|
+
],
|
|
214
|
+
"properties": {
|
|
215
|
+
"type": {
|
|
216
|
+
"enum": [
|
|
217
|
+
"string",
|
|
218
|
+
"number",
|
|
219
|
+
"boolean"
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
"required": {
|
|
223
|
+
"type": "boolean",
|
|
224
|
+
"default": false
|
|
225
|
+
},
|
|
226
|
+
"default": {},
|
|
227
|
+
"description": {
|
|
228
|
+
"type": "string",
|
|
229
|
+
"maxLength": 200
|
|
230
|
+
},
|
|
231
|
+
"secret": {
|
|
232
|
+
"type": "boolean",
|
|
233
|
+
"default": false,
|
|
234
|
+
"description": "The value is a credential and is redacted wherever the run is shown to a human - an approval request above all (RUNBOOK.md 13, NG3). An approval channel is somewhere a secret should never arrive."
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
"steps": {
|
|
240
|
+
"type": "array",
|
|
241
|
+
"description": "Permitted but unconstrained at P0, which is prose. P1 requires it and constrains every item (spec/v1/schema/p1.json). It is declared here so that each profile is a strict superset of the one below: a P1 document must also be a valid P0 document, or every facet, hub and search filter would need a second code path."
|
|
242
|
+
},
|
|
243
|
+
"source": {
|
|
244
|
+
"type": "object",
|
|
245
|
+
"additionalProperties": false,
|
|
246
|
+
"required": [
|
|
247
|
+
"url",
|
|
248
|
+
"fetched_at",
|
|
249
|
+
"upstream_state"
|
|
250
|
+
],
|
|
251
|
+
"description": "Provenance. A record without it does not validate (\u00a710).",
|
|
252
|
+
"properties": {
|
|
253
|
+
"url": {
|
|
254
|
+
"type": "string",
|
|
255
|
+
"format": "uri"
|
|
256
|
+
},
|
|
257
|
+
"commit": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"pattern": "^[0-9a-f]{7,40}$"
|
|
260
|
+
},
|
|
261
|
+
"fetched_at": {
|
|
262
|
+
"type": "string",
|
|
263
|
+
"format": "date"
|
|
264
|
+
},
|
|
265
|
+
"upstream_state": {
|
|
266
|
+
"enum": [
|
|
267
|
+
"current",
|
|
268
|
+
"changed",
|
|
269
|
+
"gone"
|
|
270
|
+
]
|
|
271
|
+
},
|
|
272
|
+
"upstream_hash": {
|
|
273
|
+
"type": "string",
|
|
274
|
+
"pattern": "^sha256:[0-9a-f]{64}$",
|
|
275
|
+
"description": "The hash of the upstream document as it was when this record was made. What a reindex compares against: without it, 'has upstream changed' can only be answered by re-deriving the record, and a derivation that differs for our own reasons would read as the source having moved. Never part of content_hash \u2014 noticing that a source moved is not a new version of this record."
|
|
276
|
+
},
|
|
277
|
+
"checked_at": {
|
|
278
|
+
"type": "string",
|
|
279
|
+
"format": "date",
|
|
280
|
+
"description": "When the upstream was last looked at, which is not when the record was made. A marker with no date is a claim about the present made at an unknown time."
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
"trust": {
|
|
285
|
+
"not": {},
|
|
286
|
+
"description": "Forbidden. Trust is computed from evidence plus a clock and is never asserted by a record (RUNBOOK.md 8). A document that declares its own trust is invalid, not merely ignored."
|
|
287
|
+
},
|
|
288
|
+
"attestations": {
|
|
289
|
+
"not": {},
|
|
290
|
+
"description": "Forbidden. Attestations are issued and verified, never self-declared (RUNBOOK.md 8). They reach a record through the catalog, not through its frontmatter."
|
|
291
|
+
},
|
|
292
|
+
"profile_verified": {
|
|
293
|
+
"not": {},
|
|
294
|
+
"description": "Forbidden. There is no self-certification of any kind. See RUNBOOK.md 19 on why there is no score."
|
|
295
|
+
},
|
|
296
|
+
"relations": {
|
|
297
|
+
"type": "array",
|
|
298
|
+
"description": "Edges to other records (\u00a722). A relation is authored: unlike an attestation, it is the author saying how this procedure stands to another, and only they can say it. Every reference must resolve to a record this catalog holds, or the record does not publish.",
|
|
299
|
+
"items": {
|
|
300
|
+
"type": "object",
|
|
301
|
+
"additionalProperties": false,
|
|
302
|
+
"required": [
|
|
303
|
+
"kind",
|
|
304
|
+
"ref"
|
|
305
|
+
],
|
|
306
|
+
"properties": {
|
|
307
|
+
"kind": {
|
|
308
|
+
"enum": [
|
|
309
|
+
"requires",
|
|
310
|
+
"rollback_of",
|
|
311
|
+
"escalates_to",
|
|
312
|
+
"part_of"
|
|
313
|
+
],
|
|
314
|
+
"description": "requires: this cannot run until that one has. rollback_of: this undoes that one. escalates_to: when this hands off, it hands off to that one. part_of: this is a step of that larger procedure (\u00a718.6's decomposition)."
|
|
315
|
+
},
|
|
316
|
+
"ref": {
|
|
317
|
+
"type": "string",
|
|
318
|
+
"pattern": "^[a-z0-9][a-z0-9-]{0,38}/[a-z0-9][a-z0-9-]{0,63}(@[0-9]+\\.[0-9]+\\.[0-9]+)?$",
|
|
319
|
+
"description": "publisher/slug, optionally pinned with @semver. `requires` and `rollback_of` must pin, because they assert what another record does and that is only true of a version. `part_of` and `escalates_to` must not, because they are structural and a pinned structure rots."
|
|
320
|
+
},
|
|
321
|
+
"why": {
|
|
322
|
+
"type": "string",
|
|
323
|
+
"maxLength": 280,
|
|
324
|
+
"description": "One sentence for a reader. Optional, and the only free text in a relation."
|
|
325
|
+
},
|
|
326
|
+
"step": {
|
|
327
|
+
"type": "string",
|
|
328
|
+
"pattern": "^[a-z][a-z0-9_-]{0,31}$",
|
|
329
|
+
"description": "`part_of` only: the step of the parent this record expands (\u00a718.6). Without it a decomposition is a claim of membership with no place in the parent's procedure, and a reader cannot tell which of twelve steps this is the detail of."
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
"trust_evidence": {
|
|
335
|
+
"not": {},
|
|
336
|
+
"description": "Forbidden. The evidence for a trust level is what the catalog concluded while computing it (RUNBOOK.md 8, 18.5), so it arrives with the level and never from the document. Submit the record; the level and its evidence are added on the way out, and both are in schema/record.json."
|
|
337
|
+
},
|
|
338
|
+
"signature": {
|
|
339
|
+
"not": {},
|
|
340
|
+
"description": "Forbidden. A signature field in a served record is what checking the publisher's key concluded (RUNBOOK.md 8), not a claim the document makes about itself: a record that carried its own verdict would be asserting the one thing verification exists to decide. Sign the record with the publishing key instead."
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"allOf": [
|
|
344
|
+
{
|
|
345
|
+
"description": "Non-English content must carry an English title and summary, or clustering splits one topic into language clusters (RUNBOOK.md 16). ajv strict mode requires each conditional branch to define the properties it names.",
|
|
346
|
+
"if": {
|
|
347
|
+
"properties": {
|
|
348
|
+
"lang": {
|
|
349
|
+
"type": "string",
|
|
350
|
+
"not": {
|
|
351
|
+
"const": "en"
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"required": [
|
|
356
|
+
"lang"
|
|
357
|
+
]
|
|
358
|
+
},
|
|
359
|
+
"then": {
|
|
360
|
+
"properties": {
|
|
361
|
+
"title_en": {
|
|
362
|
+
"type": "string",
|
|
363
|
+
"maxLength": 200
|
|
364
|
+
},
|
|
365
|
+
"summary_en": {
|
|
366
|
+
"type": "string",
|
|
367
|
+
"maxLength": 1024
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
"required": [
|
|
371
|
+
"title_en",
|
|
372
|
+
"summary_en"
|
|
373
|
+
]
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
]
|
|
377
|
+
},
|
|
378
|
+
"body": {
|
|
379
|
+
"type": "string",
|
|
380
|
+
"description": "The markdown body of the SKILL.md this record came from, carried so it participates in content_hash. Changing the prose of a procedure is a change to the procedure."
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|