kotonoha 0.4.0 → 0.4.2

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +47 -1
  2. package/README-ja.md +82 -4
  3. package/README.md +123 -6
  4. package/bin/kotonoha.js +4 -1
  5. package/package.json +8 -3
  6. package/skills/japanese-prose/scripts/invariants.py +24 -6
  7. package/skills/obsidian-bases/SKILL.md +140 -0
  8. package/skills/obsidian-bases/assets/templates/cards.base +8 -0
  9. package/skills/obsidian-bases/assets/templates/kanban.base +7 -0
  10. package/skills/obsidian-bases/assets/templates/list.base +8 -0
  11. package/skills/obsidian-bases/assets/templates/table.base +10 -0
  12. package/skills/obsidian-bases/references/execution-contract.json +246 -0
  13. package/skills/obsidian-bases/references/workflow.md +155 -0
  14. package/skills/obsidian-bases/scripts/check.cjs +690 -0
  15. package/skills/obsidian-bases/scripts/package-lock.json +104 -0
  16. package/skills/obsidian-bases/scripts/package.json +18 -0
  17. package/skills/obsidian-bases/scripts/verify.cjs +454 -0
  18. package/skills/obsidian-canvas/SKILL.md +134 -0
  19. package/skills/obsidian-canvas/assets/templates/comparison.canvas +11 -0
  20. package/skills/obsidian-canvas/assets/templates/mind-map.canvas +11 -0
  21. package/skills/obsidian-canvas/assets/templates/note-map.canvas +10 -0
  22. package/skills/obsidian-canvas/assets/templates/workflow.canvas +11 -0
  23. package/skills/obsidian-canvas/references/execution-contract.json +404 -0
  24. package/skills/obsidian-canvas/references/workflow.md +187 -0
  25. package/skills/obsidian-canvas/scripts/canvas.py +1479 -0
  26. package/skills/obsidian-canvas/scripts/canvas.py.lock +143 -0
  27. package/skills/obsidian-canvas/scripts/test_canvas.py +2047 -0
  28. package/skills/obsidian-canvas/scripts/test_canvas.py.lock +143 -0
  29. package/skills/obsidian-vault/SKILL.md +162 -0
  30. package/skills/obsidian-vault/references/execution-contract.json +479 -0
  31. package/skills/obsidian-vault/references/workflow.md +206 -0
  32. package/skills/obsidian-vault/scripts/test_vault.py +569 -0
  33. package/skills/obsidian-vault/scripts/test_vault.py.lock +143 -0
  34. package/skills/obsidian-vault/scripts/vault.py +1363 -0
  35. package/skills/obsidian-vault/scripts/vault.py.lock +143 -0
  36. package/skills/tech-writer/SKILL.md +26 -7
  37. package/skills/tech-writer/assets/templates/obsidian.md +37 -0
  38. package/skills/tech-writer/references/doctypes/obsidian.md +106 -0
@@ -0,0 +1,479 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$ref": "#/$defs/Request",
4
+ "title": "kotonoha Obsidian execution contract",
5
+ "x-contract-version": 1,
6
+ "x-commands": {
7
+ "inspect": {
8
+ "required": ["--request"],
9
+ "optional": [],
10
+ "result": "InspectResult",
11
+ "vault_write": false
12
+ },
13
+ "read": {
14
+ "required": ["--request", "--path"],
15
+ "optional": [],
16
+ "result": "ReadResult",
17
+ "vault_write": false
18
+ },
19
+ "plan": {
20
+ "required": ["--request", "--candidate"],
21
+ "optional": ["--review"],
22
+ "result": "PlanResult",
23
+ "context_schema": "PlanRequest",
24
+ "preconditions": [
25
+ "intent is create or proofread; write_target is an authorized .md path",
26
+ "proofread requires a non-null base_sha256 matching the original source used for candidate generation and the current target bytes",
27
+ "unchanged proofread returns no_changes before requiring semantic review; it never creates an applyable Plan"
28
+ ],
29
+ "vault_write": false
30
+ },
31
+ "apply": {
32
+ "required": ["--request", "--plan", "--approve-plan-sha256"],
33
+ "optional": [],
34
+ "result": "ApplyResult",
35
+ "vault_write": true
36
+ }
37
+ },
38
+ "x-exit-codes": {
39
+ "0": "completed",
40
+ "1": "input_or_runtime_failure",
41
+ "2": "authorization_conflict_or_gate_block",
42
+ "3": "partial",
43
+ "4": "missing_capability_or_dependency"
44
+ },
45
+ "x-exit-policy": [
46
+ {"priority": 1, "condition": "current_invocation_commit_outcome_uncertain", "status": "failed", "exit_code": 1, "write_status_allowed": ["unknown"]},
47
+ {"priority": 2, "condition": "control_input_or_precommit_runtime_error", "status": "failed", "exit_code": 1, "write_status_allowed": ["unsaved", "not_requested"]},
48
+ {"priority": 3, "condition": "operation_authorization_conflict_or_gate_denial", "status": "not_performed", "exit_code": 2, "write_status_allowed": ["unsaved", "not_requested"]},
49
+ {"priority": 4, "condition": "missing_dependency_or_capability", "status": "not_performed", "exit_code": 4, "write_status_allowed": ["unsaved", "not_requested"]},
50
+ {"priority": 5, "condition": "link_limitation_or_unprocessed_input", "status": "partial", "exit_code": 3, "write_status_allowed": ["unsaved", "not_requested"]},
51
+ {"priority": 6, "condition": "complete", "status": "completed", "exit_code": 0, "write_status_allowed": ["unsaved", "not_requested", "saved"]}
52
+ ],
53
+ "x-reason-context": [
54
+ {"command": "inspect", "reasons": ["excluded_management_directory", "excluded_example", "external_url"], "effect": "informational_only; does not reduce coverage or status"},
55
+ {"command": "inspect", "reasons": ["read_failed"], "effect": "partial, exit 3, reads_complete false; no definitive absence or uniqueness in the affected necessary domain"},
56
+ {"command": "inspect", "reasons": ["target_parse_incomplete"], "effect": "partial, exit 3; a single parse-failed candidate is indeterminate with or without a heading fragment"},
57
+ {"command": "inspect", "reasons": ["source_parse_incomplete"], "effect": "partial, exit 3, parses_complete false; no confirmed links from that source; unsupported YAML additionally emits a separate unsupported_format Issue"},
58
+ {"command": "read", "reasons": ["read_failed"], "effect": "failed, exit 1, not_requested; includes missing authorized target"},
59
+ {"command": "apply", "reasons": ["commit_outcome_uncertain"], "effect": "current attempt committed or may have committed: failed/1/unknown; prior attempt uncertain with no current write: not_performed/2/unsaved"},
60
+ {"command": "apply", "reasons": ["already_applied"], "effect": "completed/0/saved, changed false, verified true; no current write"},
61
+ {"command": "apply", "reasons": ["target_exists"], "effect": "not_performed/2/unsaved; includes preexisting stage_target"},
62
+ {"command": "*", "reasons": ["consent_missing"], "effect": "not_performed/2; deny all Vault content processing without model_context, and plan/apply workspace artifacts without workspace_copies"}
63
+ ],
64
+ "$defs": {
65
+ "Nonempty": {"type": "string", "minLength": 1},
66
+ "Hash": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
67
+ "NullableHash": {"oneOf": [{"$ref": "#/$defs/Hash"}, {"type": "null"}]},
68
+ "NullableString": {"type": ["string", "null"], "minLength": 1},
69
+ "Paths": {
70
+ "type": "array",
71
+ "items": {"$ref": "#/$defs/Nonempty"},
72
+ "uniqueItems": true
73
+ },
74
+ "OperationState": {"enum": ["scoped", "proposed", "validated", "approved", "saved", "blocked"]},
75
+ "LinkClassification": {"enum": ["resolved", "unresolved", "ambiguous", "indeterminate"]},
76
+ "Reason": {
77
+ "enum": [
78
+ "note_found", "heading_found", "note_missing", "heading_missing",
79
+ "multiple_notes", "multiple_headings", "scope_incomplete", "outside_scope",
80
+ "unsupported_syntax", "unsupported_heading", "invalid_encoding",
81
+ "excluded_example", "external_url", "excluded_management_directory",
82
+ "invalid_request", "invalid_path", "symlink_not_followed", "read_failed",
83
+ "unsupported_format", "limit_reached", "dependency_missing",
84
+ "capability_missing", "consent_missing", "candidate_changed",
85
+ "request_changed", "implementation_changed", "gate_blocked",
86
+ "semantic_review_required", "plan_not_approved", "target_exists",
87
+ "target_changed", "parent_changed", "write_failed_before_commit",
88
+ "commit_outcome_uncertain", "already_applied", "saved", "no_changes",
89
+ "runtime_error", "source_parse_incomplete", "target_parse_incomplete"
90
+ ]
91
+ },
92
+ "Scope": {
93
+ "type": "object",
94
+ "additionalProperties": false,
95
+ "required": ["kind", "path"],
96
+ "properties": {
97
+ "kind": {"enum": ["file", "directory"]},
98
+ "path": {"$ref": "#/$defs/Nonempty"}
99
+ }
100
+ },
101
+ "Request": {
102
+ "type": "object",
103
+ "additionalProperties": false,
104
+ "required": [
105
+ "schema_version", "vault_root", "read_scopes", "purpose", "intent",
106
+ "write_target", "base_sha256", "deliverable", "declared_rules", "protected_terms",
107
+ "workspace", "consent", "limits"
108
+ ],
109
+ "properties": {
110
+ "schema_version": {"const": 1},
111
+ "vault_root": {"$ref": "#/$defs/Nonempty"},
112
+ "read_scopes": {
113
+ "type": "array",
114
+ "minItems": 1,
115
+ "uniqueItems": true,
116
+ "items": {"$ref": "#/$defs/Scope"}
117
+ },
118
+ "purpose": {"$ref": "#/$defs/Nonempty"},
119
+ "intent": {"enum": ["conventions", "related", "links", "create", "proofread"]},
120
+ "write_target": {"$ref": "#/$defs/NullableString"},
121
+ "base_sha256": {"$ref": "#/$defs/NullableHash"},
122
+ "deliverable": {"enum": ["note", "template", null]},
123
+ "declared_rules": {"$ref": "#/$defs/Paths"},
124
+ "protected_terms": {"$ref": "#/$defs/Paths"},
125
+ "workspace": {"$ref": "#/$defs/NullableString"},
126
+ "consent": {
127
+ "type": "object",
128
+ "additionalProperties": false,
129
+ "required": ["model_context", "workspace_copies"],
130
+ "properties": {
131
+ "model_context": {"type": "boolean"},
132
+ "workspace_copies": {"type": "boolean"}
133
+ }
134
+ },
135
+ "limits": {
136
+ "type": "object",
137
+ "additionalProperties": false,
138
+ "required": ["max_files", "max_file_bytes", "max_total_bytes"],
139
+ "properties": {
140
+ "max_files": {"type": ["integer", "null"], "minimum": 1},
141
+ "max_file_bytes": {"type": ["integer", "null"], "minimum": 1},
142
+ "max_total_bytes": {"type": ["integer", "null"], "minimum": 1}
143
+ }
144
+ }
145
+ }
146
+ },
147
+ "PlanRequest": {
148
+ "description": "Contextual safety preconditions for plan, checked after Request syntax validation. Rejection is not_performed/2, not a malformed JSON error. Request itself also serves read before a base hash exists.",
149
+ "allOf": [
150
+ {"$ref": "#/$defs/Request"},
151
+ {
152
+ "properties": {
153
+ "intent": {"enum": ["create", "proofread"]},
154
+ "write_target": {"$ref": "#/$defs/Nonempty"},
155
+ "workspace": {"$ref": "#/$defs/Nonempty"}
156
+ },
157
+ "if": {"properties": {"intent": {"const": "proofread"}}},
158
+ "then": {"properties": {"base_sha256": {"$ref": "#/$defs/Hash"}, "deliverable": {"type": "null"}}},
159
+ "else": {"properties": {"base_sha256": {"type": "null"}, "deliverable": {"enum": ["note", "template"]}}}
160
+ }
161
+ ]
162
+ },
163
+ "Issue": {
164
+ "type": "object",
165
+ "additionalProperties": false,
166
+ "required": ["code", "path", "message"],
167
+ "properties": {
168
+ "code": {"$ref": "#/$defs/Reason"},
169
+ "path": {"$ref": "#/$defs/NullableString"},
170
+ "message": {"$ref": "#/$defs/Nonempty"}
171
+ }
172
+ },
173
+ "Link": {
174
+ "type": "object",
175
+ "additionalProperties": false,
176
+ "required": [
177
+ "source_path", "block_start_line", "occurrence", "raw",
178
+ "classification", "reason", "candidates"
179
+ ],
180
+ "properties": {
181
+ "source_path": {"$ref": "#/$defs/Nonempty"},
182
+ "block_start_line": {"type": "integer", "minimum": 1},
183
+ "occurrence": {"type": "integer", "minimum": 1},
184
+ "raw": {"$ref": "#/$defs/Nonempty"},
185
+ "classification": {"$ref": "#/$defs/LinkClassification"},
186
+ "reason": {"$ref": "#/$defs/Reason"},
187
+ "candidates": {"$ref": "#/$defs/Paths"}
188
+ }
189
+ },
190
+ "Observation": {
191
+ "type": "object",
192
+ "additionalProperties": false,
193
+ "required": ["kind", "value", "paths", "count", "label"],
194
+ "properties": {
195
+ "kind": {"enum": ["name", "folder", "property_name", "property_type", "tag"]},
196
+ "value": {"$ref": "#/$defs/Nonempty"},
197
+ "paths": {"$ref": "#/$defs/Paths"},
198
+ "count": {"type": "integer", "minimum": 1},
199
+ "label": {"const": "observation"}
200
+ }
201
+ },
202
+ "Note": {
203
+ "type": "object",
204
+ "additionalProperties": false,
205
+ "required": ["path", "sha256", "bytes", "heading_texts"],
206
+ "properties": {
207
+ "path": {"$ref": "#/$defs/Nonempty"},
208
+ "sha256": {"$ref": "#/$defs/Hash"},
209
+ "bytes": {"type": "integer", "minimum": 0},
210
+ "heading_texts": {"type": "array", "items": {"type": "string"}}
211
+ }
212
+ },
213
+ "InspectResult": {
214
+ "type": "object",
215
+ "additionalProperties": false,
216
+ "required": ["notes", "observations", "declarations", "links", "external_url_count"],
217
+ "properties": {
218
+ "notes": {"type": "array", "items": {"$ref": "#/$defs/Note"}},
219
+ "observations": {"type": "array", "items": {"$ref": "#/$defs/Observation"}},
220
+ "declarations": {"type": "array", "items": {"$ref": "#/$defs/Note"}},
221
+ "links": {"type": "array", "items": {"$ref": "#/$defs/Link"}},
222
+ "external_url_count": {"type": "integer", "minimum": 0}
223
+ }
224
+ },
225
+ "ReadResult": {
226
+ "type": "object",
227
+ "additionalProperties": false,
228
+ "required": ["path", "sha256", "bytes", "content"],
229
+ "properties": {
230
+ "path": {"$ref": "#/$defs/Nonempty"},
231
+ "sha256": {"$ref": "#/$defs/Hash"},
232
+ "bytes": {"type": "integer", "minimum": 0},
233
+ "content": {"type": "string"}
234
+ }
235
+ },
236
+ "PlanResult": {
237
+ "type": "object",
238
+ "additionalProperties": false,
239
+ "required": ["plan_path", "plan_sha256", "operation_id", "gate_status", "no_changes"],
240
+ "properties": {
241
+ "plan_path": {"$ref": "#/$defs/NullableString"},
242
+ "plan_sha256": {"$ref": "#/$defs/NullableHash"},
243
+ "operation_id": {"$ref": "#/$defs/NullableHash"},
244
+ "gate_status": {"enum": ["passed", "blocked", "review_required", "not_applicable"]},
245
+ "no_changes": {"type": "boolean"}
246
+ },
247
+ "allOf": [
248
+ {
249
+ "if": {"properties": {"no_changes": {"const": true}}},
250
+ "then": {"properties": {"plan_path": {"type": "null"}, "plan_sha256": {"type": "null"}, "operation_id": {"type": "null"}, "gate_status": {"const": "passed"}}},
251
+ "else": {"properties": {"plan_path": {"$ref": "#/$defs/Nonempty"}, "plan_sha256": {"$ref": "#/$defs/Hash"}, "operation_id": {"$ref": "#/$defs/Hash"}}}
252
+ }
253
+ ]
254
+ },
255
+ "ApplyResult": {
256
+ "type": "object",
257
+ "additionalProperties": false,
258
+ "required": ["target", "after_sha256", "operation_id", "changed", "verified"],
259
+ "properties": {
260
+ "target": {"$ref": "#/$defs/Nonempty"},
261
+ "after_sha256": {"$ref": "#/$defs/NullableHash"},
262
+ "operation_id": {"$ref": "#/$defs/Hash"},
263
+ "changed": {"type": ["boolean", "null"]},
264
+ "verified": {"type": "boolean"}
265
+ }
266
+ },
267
+ "Coverage": {
268
+ "type": "object",
269
+ "additionalProperties": false,
270
+ "required": ["whole_vault", "enumeration_complete", "reads_complete", "parses_complete", "processed", "unprocessed"],
271
+ "properties": {
272
+ "whole_vault": {"type": "boolean"},
273
+ "enumeration_complete": {"type": "boolean"},
274
+ "reads_complete": {"type": "boolean"},
275
+ "parses_complete": {"type": "boolean"},
276
+ "processed": {"$ref": "#/$defs/Paths"},
277
+ "unprocessed": {"$ref": "#/$defs/Paths"}
278
+ }
279
+ },
280
+ "Report": {
281
+ "type": "object",
282
+ "additionalProperties": false,
283
+ "required": [
284
+ "schema_version", "command", "status", "exit_code", "write_status",
285
+ "operation_state", "request_sha256", "coverage", "issues", "data"
286
+ ],
287
+ "properties": {
288
+ "schema_version": {"const": 1},
289
+ "command": {"enum": ["inspect", "read", "plan", "apply"]},
290
+ "status": {"enum": ["completed", "partial", "not_performed", "failed"]},
291
+ "exit_code": {"type": "integer", "minimum": 0, "maximum": 4},
292
+ "write_status": {"enum": ["not_requested", "unsaved", "saved", "unknown"]},
293
+ "operation_state": {"$ref": "#/$defs/OperationState"},
294
+ "request_sha256": {"$ref": "#/$defs/NullableHash"},
295
+ "coverage": {"$ref": "#/$defs/Coverage"},
296
+ "issues": {"type": "array", "items": {"$ref": "#/$defs/Issue"}},
297
+ "data": {
298
+ "oneOf": [
299
+ {"type": "null"},
300
+ {"$ref": "#/$defs/InspectResult"},
301
+ {"$ref": "#/$defs/ReadResult"},
302
+ {"$ref": "#/$defs/PlanResult"},
303
+ {"$ref": "#/$defs/ApplyResult"}
304
+ ]
305
+ }
306
+ },
307
+ "allOf": [
308
+ {
309
+ "if": {"properties": {"command": {"const": "inspect"}}},
310
+ "then": {"properties": {"data": {"oneOf": [{"type": "null"}, {"$ref": "#/$defs/InspectResult"}]}}}
311
+ },
312
+ {
313
+ "if": {"properties": {"command": {"const": "read"}}},
314
+ "then": {"properties": {"data": {"oneOf": [{"type": "null"}, {"$ref": "#/$defs/ReadResult"}]}}}
315
+ },
316
+ {
317
+ "if": {"properties": {"command": {"const": "plan"}}},
318
+ "then": {"properties": {"data": {"oneOf": [{"type": "null"}, {"$ref": "#/$defs/PlanResult"}]}}}
319
+ },
320
+ {
321
+ "if": {"properties": {"command": {"const": "apply"}}},
322
+ "then": {"properties": {"data": {"oneOf": [{"type": "null"}, {"$ref": "#/$defs/ApplyResult"}]}}}
323
+ },
324
+ {
325
+ "if": {"properties": {"status": {"const": "completed"}}},
326
+ "then": {"properties": {"data": {"not": {"type": "null"}}, "exit_code": {"const": 0}}}
327
+ },
328
+ {
329
+ "if": {"properties": {"status": {"const": "failed"}}},
330
+ "then": {"properties": {"exit_code": {"const": 1}}}
331
+ },
332
+ {
333
+ "if": {"properties": {"status": {"const": "partial"}}},
334
+ "then": {"properties": {"exit_code": {"const": 3}}}
335
+ },
336
+ {
337
+ "if": {"properties": {"status": {"const": "not_performed"}}},
338
+ "then": {"properties": {"exit_code": {"enum": [2, 4]}, "write_status": {"enum": ["unsaved", "not_requested"]}}}
339
+ },
340
+ {
341
+ "if": {"properties": {"write_status": {"enum": ["saved", "unknown"]}}},
342
+ "then": {"properties": {"command": {"const": "apply"}}}
343
+ },
344
+ {
345
+ "if": {"properties": {"write_status": {"const": "saved"}}},
346
+ "then": {"properties": {"status": {"const": "completed"}, "operation_state": {"const": "saved"}}}
347
+ },
348
+ {
349
+ "if": {"properties": {"write_status": {"const": "unknown"}}},
350
+ "then": {"properties": {"status": {"const": "failed"}}}
351
+ },
352
+ {
353
+ "if": {"properties": {"command": {"enum": ["inspect", "read"]}}},
354
+ "then": {"properties": {"write_status": {"const": "not_requested"}}}
355
+ },
356
+ {
357
+ "if": {"properties": {"command": {"const": "plan"}}},
358
+ "then": {"properties": {"write_status": {"const": "unsaved"}}}
359
+ },
360
+ {
361
+ "if": {"properties": {"command": {"const": "plan"}, "status": {"const": "completed"}}},
362
+ "then": {
363
+ "properties": {"data": {"properties": {"gate_status": {"enum": ["passed", "not_applicable"]}}}},
364
+ "allOf": [{
365
+ "if": {"properties": {"data": {"properties": {"no_changes": {"const": true}}}}},
366
+ "then": {"properties": {"operation_state": {"const": "scoped"}}},
367
+ "else": {"properties": {"operation_state": {"const": "validated"}}}
368
+ }]
369
+ }
370
+ },
371
+ {
372
+ "if": {"properties": {"status": {"const": "completed"}, "command": {"const": "apply"}}},
373
+ "then": {
374
+ "properties": {
375
+ "write_status": {"const": "saved"},
376
+ "operation_state": {"const": "saved"},
377
+ "data": {
378
+ "properties": {
379
+ "verified": {"const": true},
380
+ "changed": {"type": "boolean"},
381
+ "after_sha256": {"$ref": "#/$defs/Hash"}
382
+ }
383
+ }
384
+ }
385
+ }
386
+ }
387
+ ]
388
+ },
389
+ "Plan": {
390
+ "type": "object",
391
+ "additionalProperties": false,
392
+ "required": [
393
+ "schema_version", "operation_id", "request_sha256", "contract_sha256",
394
+ "implementation_sha256", "vault_identity", "target", "stage_target", "kind",
395
+ "before_sha256", "after_sha256", "diff_sha256", "review_sha256", "state",
396
+ "artifacts", "protected_terms"
397
+ ],
398
+ "properties": {
399
+ "schema_version": {"const": 1},
400
+ "operation_id": {"$ref": "#/$defs/Hash"},
401
+ "request_sha256": {"$ref": "#/$defs/Hash"},
402
+ "contract_sha256": {"$ref": "#/$defs/Hash"},
403
+ "implementation_sha256": {"$ref": "#/$defs/Hash"},
404
+ "vault_identity": {
405
+ "type": "object",
406
+ "additionalProperties": false,
407
+ "required": ["device", "inode"],
408
+ "properties": {
409
+ "device": {"type": "integer", "minimum": 0},
410
+ "inode": {"type": "integer", "minimum": 0}
411
+ }
412
+ },
413
+ "target": {"$ref": "#/$defs/Nonempty"},
414
+ "stage_target": {"$ref": "#/$defs/Nonempty"},
415
+ "kind": {"enum": ["create", "edit"]},
416
+ "before_sha256": {"$ref": "#/$defs/NullableHash"},
417
+ "after_sha256": {"$ref": "#/$defs/Hash"},
418
+ "diff_sha256": {"$ref": "#/$defs/Hash"},
419
+ "review_sha256": {"$ref": "#/$defs/NullableHash"},
420
+ "state": {"enum": ["proposed", "validated"]},
421
+ "artifacts": {
422
+ "type": "object",
423
+ "additionalProperties": false,
424
+ "required": ["before", "candidate", "diff", "review"],
425
+ "properties": {
426
+ "before": {"$ref": "#/$defs/NullableString"},
427
+ "candidate": {"$ref": "#/$defs/Nonempty"},
428
+ "diff": {"$ref": "#/$defs/Nonempty"},
429
+ "review": {"$ref": "#/$defs/NullableString"}
430
+ }
431
+ },
432
+ "protected_terms": {"$ref": "#/$defs/Paths"}
433
+ },
434
+ "allOf": [
435
+ {
436
+ "if": {"properties": {"kind": {"const": "create"}}},
437
+ "then": {
438
+ "properties": {
439
+ "before_sha256": {"type": "null"},
440
+ "artifacts": {"properties": {"before": {"type": "null"}}}
441
+ }
442
+ }
443
+ },
444
+ {
445
+ "if": {"properties": {"kind": {"const": "edit"}}},
446
+ "then": {
447
+ "properties": {
448
+ "before_sha256": {"$ref": "#/$defs/Hash"},
449
+ "artifacts": {"properties": {"before": {"$ref": "#/$defs/Nonempty"}}}
450
+ }
451
+ }
452
+ },
453
+ {
454
+ "if": {"properties": {"kind": {"const": "edit"}, "state": {"const": "validated"}}},
455
+ "then": {
456
+ "properties": {
457
+ "review_sha256": {"$ref": "#/$defs/Hash"},
458
+ "artifacts": {"properties": {"review": {"$ref": "#/$defs/Nonempty"}}}
459
+ }
460
+ }
461
+ }
462
+ ]
463
+ },
464
+ "Receipt": {
465
+ "type": "object",
466
+ "additionalProperties": false,
467
+ "required": ["schema_version", "operation_id", "plan_sha256", "request_sha256", "target", "after_sha256", "verified"],
468
+ "properties": {
469
+ "schema_version": {"const": 1},
470
+ "operation_id": {"$ref": "#/$defs/Hash"},
471
+ "plan_sha256": {"$ref": "#/$defs/Hash"},
472
+ "request_sha256": {"$ref": "#/$defs/Hash"},
473
+ "target": {"$ref": "#/$defs/Nonempty"},
474
+ "after_sha256": {"$ref": "#/$defs/Hash"},
475
+ "verified": {"const": true}
476
+ }
477
+ }
478
+ }
479
+ }