@tiphys/kernel 0.0.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.
- package/AGENTS.md +663 -0
- package/LICENSE +202 -0
- package/assurance-modes.yaml +299 -0
- package/checklists/clean-room.yaml +325 -0
- package/checklists/env-failure-diagnosis.yaml +68 -0
- package/checklists/flake-playbook.yaml +68 -0
- package/checklists/hazard-review.yaml +144 -0
- package/checklists/plan-review.yaml +103 -0
- package/dist/bin/tiphys.d.ts +2 -0
- package/dist/bin/tiphys.js +92 -0
- package/dist/src/adapters/load.d.ts +202 -0
- package/dist/src/adapters/load.js +440 -0
- package/dist/src/brief.d.ts +32 -0
- package/dist/src/brief.js +66 -0
- package/dist/src/checklists.d.ts +169 -0
- package/dist/src/checklists.js +310 -0
- package/dist/src/checks.d.ts +1539 -0
- package/dist/src/checks.js +5025 -0
- package/dist/src/cli.d.ts +9 -0
- package/dist/src/cli.js +68 -0
- package/dist/src/commands/brief.d.ts +92 -0
- package/dist/src/commands/brief.js +343 -0
- package/dist/src/commands/checklist.d.ts +42 -0
- package/dist/src/commands/checklist.js +168 -0
- package/dist/src/commands/cutover.d.ts +35 -0
- package/dist/src/commands/cutover.js +448 -0
- package/dist/src/commands/doctor.d.ts +264 -0
- package/dist/src/commands/doctor.js +1546 -0
- package/dist/src/commands/gates.d.ts +9 -0
- package/dist/src/commands/gates.js +360 -0
- package/dist/src/commands/init.d.ts +30 -0
- package/dist/src/commands/init.js +177 -0
- package/dist/src/commands/lock.d.ts +34 -0
- package/dist/src/commands/lock.js +340 -0
- package/dist/src/commands/mode.d.ts +40 -0
- package/dist/src/commands/mode.js +134 -0
- package/dist/src/commands/next.d.ts +130 -0
- package/dist/src/commands/next.js +597 -0
- package/dist/src/commands/plan.d.ts +20 -0
- package/dist/src/commands/plan.js +105 -0
- package/dist/src/commands/pool.d.ts +1 -0
- package/dist/src/commands/pool.js +139 -0
- package/dist/src/commands/resume.d.ts +1 -0
- package/dist/src/commands/resume.js +88 -0
- package/dist/src/commands/spawn.d.ts +1 -0
- package/dist/src/commands/spawn.js +195 -0
- package/dist/src/commands/status.d.ts +21 -0
- package/dist/src/commands/status.js +122 -0
- package/dist/src/commands/sync.d.ts +47 -0
- package/dist/src/commands/sync.js +341 -0
- package/dist/src/commands/teardown.d.ts +1 -0
- package/dist/src/commands/teardown.js +87 -0
- package/dist/src/commands/tuition.d.ts +21 -0
- package/dist/src/commands/tuition.js +218 -0
- package/dist/src/commands/validate.d.ts +78 -0
- package/dist/src/commands/validate.js +430 -0
- package/dist/src/commands/watch.d.ts +1 -0
- package/dist/src/commands/watch.js +172 -0
- package/dist/src/cutover.d.ts +584 -0
- package/dist/src/cutover.js +1444 -0
- package/dist/src/exclusion.d.ts +389 -0
- package/dist/src/exclusion.js +843 -0
- package/dist/src/exec/env.d.ts +278 -0
- package/dist/src/exec/env.js +334 -0
- package/dist/src/fleet.d.ts +223 -0
- package/dist/src/fleet.js +298 -0
- package/dist/src/gates/adapters/http-json.d.ts +5 -0
- package/dist/src/gates/adapters/http-json.js +283 -0
- package/dist/src/gates/adapters/migrations-command.d.ts +1 -0
- package/dist/src/gates/adapters/migrations-command.js +373 -0
- package/dist/src/gates/citations.d.ts +408 -0
- package/dist/src/gates/citations.js +1169 -0
- package/dist/src/gates/coverage.d.ts +375 -0
- package/dist/src/gates/coverage.js +836 -0
- package/dist/src/gates/credentials.d.ts +233 -0
- package/dist/src/gates/credentials.js +752 -0
- package/dist/src/gates/deploy.d.ts +1 -0
- package/dist/src/gates/deploy.js +33 -0
- package/dist/src/gates/gate-classes.d.ts +56 -0
- package/dist/src/gates/gate-classes.js +633 -0
- package/dist/src/gates/manifest.d.ts +99 -0
- package/dist/src/gates/manifest.js +208 -0
- package/dist/src/gates/merge-preconditions.d.ts +319 -0
- package/dist/src/gates/merge-preconditions.js +932 -0
- package/dist/src/gates/migrations.d.ts +1 -0
- package/dist/src/gates/migrations.js +36 -0
- package/dist/src/gates/pin.d.ts +114 -0
- package/dist/src/gates/pin.js +154 -0
- package/dist/src/gates/red-witness.d.ts +22 -0
- package/dist/src/gates/red-witness.js +482 -0
- package/dist/src/gates/release.d.ts +283 -0
- package/dist/src/gates/release.js +820 -0
- package/dist/src/gates/result.d.ts +116 -0
- package/dist/src/gates/result.js +91 -0
- package/dist/src/gates/run.d.ts +614 -0
- package/dist/src/gates/run.js +1614 -0
- package/dist/src/gates/schemas/citation-config.schema.json +59 -0
- package/dist/src/gates/schemas/coverage-config.schema.json +77 -0
- package/dist/src/gates/schemas/gate-manifest.schema.json +125 -0
- package/dist/src/gates/schemas/gate-result.schema.json +160 -0
- package/dist/src/gates/schemas/phase-declaration.schema.json +87 -0
- package/dist/src/gates/schemas/release-record.schema.json +119 -0
- package/dist/src/gates/schemas/verifier-config.schema.json +101 -0
- package/dist/src/gates/schemas/witness-spec.schema.json +110 -0
- package/dist/src/gates/scope.d.ts +131 -0
- package/dist/src/gates/scope.js +1018 -0
- package/dist/src/gates/suite.d.ts +217 -0
- package/dist/src/gates/suite.js +968 -0
- package/dist/src/gates/validate.d.ts +121 -0
- package/dist/src/gates/validate.js +414 -0
- package/dist/src/hooks.d.ts +84 -0
- package/dist/src/hooks.js +125 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.js +30 -0
- package/dist/src/liveness.d.ts +321 -0
- package/dist/src/liveness.js +396 -0
- package/dist/src/lock.d.ts +256 -0
- package/dist/src/lock.js +792 -0
- package/dist/src/model-resolution.d.ts +159 -0
- package/dist/src/model-resolution.js +307 -0
- package/dist/src/modes.d.ts +149 -0
- package/dist/src/modes.js +258 -0
- package/dist/src/path-identity.d.ts +34 -0
- package/dist/src/path-identity.js +48 -0
- package/dist/src/plan.d.ts +73 -0
- package/dist/src/plan.js +153 -0
- package/dist/src/pool.d.ts +326 -0
- package/dist/src/pool.js +988 -0
- package/dist/src/roles.d.ts +461 -0
- package/dist/src/roles.js +776 -0
- package/dist/src/spawn.d.ts +482 -0
- package/dist/src/spawn.js +1003 -0
- package/dist/src/status.d.ts +116 -0
- package/dist/src/status.js +148 -0
- package/dist/src/task.d.ts +504 -0
- package/dist/src/task.js +307 -0
- package/dist/src/teardown.d.ts +39 -0
- package/dist/src/teardown.js +422 -0
- package/dist/src/tuition.d.ts +159 -0
- package/dist/src/tuition.js +311 -0
- package/dist/src/validate.d.ts +263 -0
- package/dist/src/validate.js +742 -0
- package/dist/src/version.d.ts +3 -0
- package/dist/src/version.js +38 -0
- package/dist/src/watcher.d.ts +275 -0
- package/dist/src/watcher.js +849 -0
- package/dist/src/witness/run.d.ts +299 -0
- package/dist/src/witness/run.js +1373 -0
- package/dist/src/witness/spec.d.ts +270 -0
- package/dist/src/witness/spec.js +475 -0
- package/dist/tsconfig.src.tsbuildinfo +1 -0
- package/gate-registry.yaml +526 -0
- package/gates.manifest.json +257 -0
- package/package.json +72 -3
- package/role-model-config.yaml +88 -0
- package/roles/README.md +128 -0
- package/roles/_shared-dispatch-contract.md +87 -0
- package/roles/adversarial-plan-reviewer.md +80 -0
- package/roles/clean-room-reviewer.md +140 -0
- package/roles/implementer.md +463 -0
- package/roles/investigator.md +138 -0
- package/roles/plan-writer.md +95 -0
- package/schemas/README.md +82 -0
- package/schemas/assurance-modes.schema.json +264 -0
- package/schemas/charter.schema.json +185 -0
- package/schemas/checklist.schema.json +114 -0
- package/schemas/cutover-state.schema.json +64 -0
- package/schemas/decision-record.schema.json +88 -0
- package/schemas/executor-record.schema.json +36 -0
- package/schemas/final-report.schema.json +90 -0
- package/schemas/finding.schema.json +106 -0
- package/schemas/gate-registry.schema.json +260 -0
- package/schemas/mechanism-index.schema.json +94 -0
- package/schemas/model-resolution.schema.json +362 -0
- package/schemas/plan.schema.json +300 -0
- package/schemas/report.schema.json +579 -0
- package/schemas/role-brief.schema.json +105 -0
- package/schemas/role-model-config.schema.json +90 -0
- package/schemas/status-line.schema.json +40 -0
- package/schemas/tuition.schema.json +191 -0
- package/schemas/verdict.schema.json +295 -0
- package/schemas/work-history.schema.json +183 -0
- package/schemas/write-bypass.schema.json +69 -0
- package/templates/charter.example.yaml +54 -0
- package/templates/decision-record.example.yaml +27 -0
- package/templates/final-report.example.yaml +80 -0
- package/templates/plan.example.yaml +87 -0
- package/templates/report.example.yaml +236 -0
- package/templates/warnings.md +74 -0
- package/templates/work-history.example.yaml +185 -0
- package/tuition/README.md +76 -0
- package/tuition/T-001.yaml +48 -0
- package/tuition/T-002.yaml +51 -0
- package/tuition/T-003.yaml +100 -0
- package/tuition/T-004.yaml +52 -0
- package/tuition/T-005.yaml +72 -0
- package/tuition/T-006.yaml +81 -0
- package/tuition/T-007.yaml +56 -0
- package/tuition/T-008.yaml +111 -0
- package/tuition/T-009.yaml +50 -0
- package/tuition/T-015.yaml +36 -0
- package/tuition/T-016.yaml +36 -0
- package/tuition/T-017.yaml +46 -0
- package/tuition/T-018.yaml +84 -0
- package/tuition/T-021.yaml +40 -0
- package/tuition/T-022.yaml +36 -0
- package/tuition/mechanism-index.yaml +256 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/charter.schema.json",
|
|
4
|
+
"title": "Tiphys project charter",
|
|
5
|
+
"description": "Blueprint section 7. The charter is what a project realizes the kernel against. A missing required field BLOCKS realization, which is what this document's required list means.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"kind",
|
|
10
|
+
"identity",
|
|
11
|
+
"delivery-mode",
|
|
12
|
+
"assurance-tier",
|
|
13
|
+
"yolo-permissions",
|
|
14
|
+
"irreversible-decisions",
|
|
15
|
+
"product-intent",
|
|
16
|
+
"constraints",
|
|
17
|
+
"escalation-contract",
|
|
18
|
+
"release-verification",
|
|
19
|
+
"retention"
|
|
20
|
+
],
|
|
21
|
+
"properties": {
|
|
22
|
+
"kind": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"const": "charter"
|
|
25
|
+
},
|
|
26
|
+
"identity": {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"additionalProperties": false,
|
|
29
|
+
"required": ["name", "repo", "kernel-version-pin"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"name": { "type": "string", "minLength": 1 },
|
|
32
|
+
"repo": { "type": "string", "minLength": 1 },
|
|
33
|
+
"kernel-version-pin": {
|
|
34
|
+
"$comment": "An exact version, never a range. A range makes the delivery process a moving target.",
|
|
35
|
+
"type": "string",
|
|
36
|
+
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?$"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"delivery-mode": {
|
|
41
|
+
"$comment": "The enum is declared HERE and the mode DEFINITIONS are owned by M3-P3's assurance-modes.yaml. The derived check charter-mode-enum-matches-modes (M3-P3) asserts the two agree, so the duplication cannot drift. M3-P1's placeholder list (full, standard, fast, yolo) was REPLACED by M3-P3 with the three ids blueprint section 8 actually declares; `standard`, `fast` and `yolo` named no mode definition anywhere and a charter could select one and get a delivery mode with no pipeline behind it. CLOSED VOCABULARY AT v0.1.0 (DR-0020): the three values are the tiphys kernel's OWN mode ids and this enum rejects every other value, so a consuming project's charter cannot select a delivery mode of its own name at v0.1.0. Extension is an M4 question, deferred to a real pilot consumer.",
|
|
42
|
+
"type": "string",
|
|
43
|
+
"enum": ["full", "direct-pr", "local-only"]
|
|
44
|
+
},
|
|
45
|
+
"assurance-tier": {
|
|
46
|
+
"$comment": "The SAME vocabulary as delivery-mode and watched by the same check. M3-P1 shipped the identical placeholder enum on both fields, so a check that watched only one would leave the other free to drift, which is the hazard rather than a smaller version of it. CLOSED VOCABULARY AT v0.1.0 (DR-0020): the same closed set as delivery-mode, with the same consequence for a consuming project and the same M4 deferral.",
|
|
47
|
+
"type": "string",
|
|
48
|
+
"enum": ["full", "direct-pr", "local-only"]
|
|
49
|
+
},
|
|
50
|
+
"yolo-permissions": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"additionalProperties": false,
|
|
53
|
+
"required": ["enabled", "scope"],
|
|
54
|
+
"properties": {
|
|
55
|
+
"enabled": { "type": "boolean" },
|
|
56
|
+
"scope": {
|
|
57
|
+
"type": "array",
|
|
58
|
+
"items": { "type": "string", "minLength": 1 }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"irreversible-decisions": {
|
|
63
|
+
"$comment": "Blueprint section 7's named list. Every one of the seven is required, because an irreversible decision left unstated is one the delivery process will improvise.",
|
|
64
|
+
"type": "object",
|
|
65
|
+
"additionalProperties": false,
|
|
66
|
+
"required": [
|
|
67
|
+
"stack",
|
|
68
|
+
"language",
|
|
69
|
+
"framework",
|
|
70
|
+
"core-data-model",
|
|
71
|
+
"tenancy",
|
|
72
|
+
"auth",
|
|
73
|
+
"deployment-topology"
|
|
74
|
+
],
|
|
75
|
+
"properties": {
|
|
76
|
+
"stack": { "type": "string", "minLength": 1 },
|
|
77
|
+
"language": { "type": "string", "minLength": 1 },
|
|
78
|
+
"framework": { "type": "string", "minLength": 1 },
|
|
79
|
+
"core-data-model": { "type": "string", "minLength": 1 },
|
|
80
|
+
"tenancy": { "type": "string", "minLength": 1 },
|
|
81
|
+
"auth": { "type": "string", "minLength": 1 },
|
|
82
|
+
"deployment-topology": { "type": "string", "minLength": 1 }
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"product-intent": {
|
|
86
|
+
"$comment": "One page, authored as a YAML block scalar.",
|
|
87
|
+
"type": "string",
|
|
88
|
+
"minLength": 1
|
|
89
|
+
},
|
|
90
|
+
"constraints": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": { "type": "string", "minLength": 1 }
|
|
93
|
+
},
|
|
94
|
+
"escalation-contract": {
|
|
95
|
+
"$comment": "R-022 and R-090: owner decisions are never pre-empted.",
|
|
96
|
+
"type": "object",
|
|
97
|
+
"additionalProperties": false,
|
|
98
|
+
"required": ["stop-for", "route"],
|
|
99
|
+
"properties": {
|
|
100
|
+
"stop-for": {
|
|
101
|
+
"$comment": "Its DEFAULT entries, shipped in templates/charter.example.yaml, are 'any irreversible choice the charter is silent on' and 'a change from a declared release verification to `none`'. They are defaults rather than schema constants because the charter is the owner's document; the second one is what makes turning verification off an owner decision instead of an implementer's edit (delivery/verification/release-verification-interface.md section 4.1).",
|
|
102
|
+
"type": "array",
|
|
103
|
+
"minItems": 1,
|
|
104
|
+
"items": { "type": "string", "minLength": 1 }
|
|
105
|
+
},
|
|
106
|
+
"route": { "type": "string", "minLength": 1 }
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"release-verification": {
|
|
110
|
+
"$comment": "RESERVED, NOT DESIGNED (DR-0014, D-M3-29). The field's real shape is NOT decided here. delivery/verification/release-verification-interface.md section 8 item 4: 'the charter field is M3's, and M3 should reserve the space rather than design it', settled by the first real project charter at M4's pilot. This schema enumerates no adapters, models no N verifications, expresses no outcome enum, and carries no charter coherence check. The two currently-valid shapes are the oneOf below; any other shape is a rejection, which is the guard that stops a project inventing the field's real shape before M4's pilot decides it.",
|
|
111
|
+
"type": "object",
|
|
112
|
+
"additionalProperties": false,
|
|
113
|
+
"required": ["mode"],
|
|
114
|
+
"properties": {
|
|
115
|
+
"mode": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"enum": ["none", "reserved"]
|
|
118
|
+
},
|
|
119
|
+
"reason": { "type": "string", "minLength": 1 },
|
|
120
|
+
"note": { "type": "string", "minLength": 1 }
|
|
121
|
+
},
|
|
122
|
+
"if": {
|
|
123
|
+
"$comment": "Investigation defence 2: silence is never permission. Disabling verification costs visibility, so mode none REQUIRES a stated reason.",
|
|
124
|
+
"type": "object",
|
|
125
|
+
"required": ["mode"],
|
|
126
|
+
"properties": { "mode": { "const": "none" } }
|
|
127
|
+
},
|
|
128
|
+
"then": {
|
|
129
|
+
"type": "object",
|
|
130
|
+
"required": ["reason"],
|
|
131
|
+
"properties": { "reason": { "type": "string", "minLength": 1 } }
|
|
132
|
+
},
|
|
133
|
+
"oneOf": [
|
|
134
|
+
{
|
|
135
|
+
"type": "object",
|
|
136
|
+
"additionalProperties": false,
|
|
137
|
+
"required": ["mode", "reason"],
|
|
138
|
+
"properties": {
|
|
139
|
+
"mode": { "type": "string", "const": "none" },
|
|
140
|
+
"reason": { "type": "string", "minLength": 1 }
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"type": "object",
|
|
145
|
+
"additionalProperties": false,
|
|
146
|
+
"required": ["mode", "note"],
|
|
147
|
+
"properties": {
|
|
148
|
+
"mode": { "type": "string", "const": "reserved" },
|
|
149
|
+
"note": { "type": "string", "minLength": 1 }
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
},
|
|
154
|
+
"review-families": {
|
|
155
|
+
"$comment": "DR-0038's DECLARATION, and it is a declaration rather than the exception itself (M4-D-28, kernel plan M4 section 4.2.6). DR-0012 condition 1 requires two clean-room reviews produced on different model FAMILIES. A project with one family available can satisfy that only by recording something false, and the shipped check makes it worse: it compares canonicalised STRINGS, so two models of one family compare as distinct and the pair reports decorrelated. This field is where a project states WHICH families its environment actually has. The schema does not encode the exception: single-family is `available.length === 1`, and what that then means is `dual-review-decorrelation`'s business. OPTIONAL, AND ITS ABSENCE IS NOT PERMISSION: an absent `review-families` leaves the cross-family requirement applying unchanged, so a same-family pair stays red (src/gates/release.ts:1037 states the same rule for the sibling case). WHY THE CHARTER AND NOT assurance-modes.yaml: DR-0029's split asks whether a fact is process or predicate, and 'which model families exist in this environment' is a fact about the PROJECT's environment, so it belongs to the project's own declaration; the assurance-mode vocabularies are closed by DR-0020 and bound to a derived check.",
|
|
156
|
+
"type": "object",
|
|
157
|
+
"additionalProperties": false,
|
|
158
|
+
"required": ["available", "reason"],
|
|
159
|
+
"properties": {
|
|
160
|
+
"available": {
|
|
161
|
+
"$comment": "The model families this environment can actually dispatch a clean-room review on. NOT an enum: no closed vocabulary of model families can be kept current, and a stale enum here would refuse a true declaration. The check canonicalises each entry the same way it canonicalises a verdict's `produced-by`, so the two are comparable.",
|
|
162
|
+
"type": "array",
|
|
163
|
+
"minItems": 1,
|
|
164
|
+
"items": { "type": "string", "minLength": 1 }
|
|
165
|
+
},
|
|
166
|
+
"reason": {
|
|
167
|
+
"$comment": "Investigation defence 2, the same rule release-verification mode none is held to: narrowing an owner-reserved merge condition costs a stated reason. A declaration nobody has to justify is the shape DR-0038 exists to replace.",
|
|
168
|
+
"type": "string",
|
|
169
|
+
"minLength": 1
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"retention": {
|
|
174
|
+
"$comment": "Consumed by M3-P8 for R-098.",
|
|
175
|
+
"type": "object",
|
|
176
|
+
"additionalProperties": false,
|
|
177
|
+
"required": ["work-history", "evidence", "tuition"],
|
|
178
|
+
"properties": {
|
|
179
|
+
"work-history": { "type": "string", "minLength": 1 },
|
|
180
|
+
"evidence": { "type": "string", "minLength": 1 },
|
|
181
|
+
"tuition": { "type": "string", "minLength": 1 }
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/checklist.schema.json",
|
|
4
|
+
"title": "Tiphys review checklist",
|
|
5
|
+
"$comment": "R-026b, R-027, R-028a, R-050b, R-053, R-054, R-055, R-056a, R-057b, R-059, R-066, R-093. Kernel plan M3, M3-P7 steps 1 and 5. A CHECKLIST IS A PROBE LIST WITH DECLARED ENTRY POINTS. THE HAZARD THIS DOCUMENT EXISTS AGAINST is the phase's own: a checklist whose probes are present, unique, resolvable and USELESS. This schema reaches four of the seven ways that happens and reaches none of the other three, which is stated here rather than left for a reader to assume. WHAT IT REACHES: a probe with no question, no scope or no evidence policy (required plus minLength); an `applies-to` token that is prose rather than a scope a resolver can group by (pattern); a framing with no entry point or that orders nothing (required plus minItems); a `verifies-gate` that is blank. WHAT IT CANNOT REACH, each with the instrument that does. (1) Whether a probe's TEXT is specific enough to need opening a file: that is a property of prose, it is criterion 3b's registered tests for the five probe sets the plan names, and for the rest it is risk 2 and the suggested-tier note. (2) Whether two probes share an `id`: `uniqueItems` compares WHOLE array items, so two probes differing in any other field are already unique to it; that is the Kind B check `checklist-probe-ids-unique`. (2a) THE SAME THING ONE ARRAY ALONG, missed until fix round 2 because the keyword limitation was recorded for probes and not generalised: two FRAMINGS sharing an id, which is the check `checklist-framing-ids-unique`. (3) Whether a `verifies-gate` names a gate that exists, or whether a probe named by the registry carries the back-reference at all: both are cross-document and are the Kind B check `gate-probes-resolve`, running in both directions.",
|
|
6
|
+
"description": "A review checklist: a list of probes a reviewer answers, plus the framings that decide which probe they answer first.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"required": ["kind", "id", "applies-to", "probes"],
|
|
10
|
+
"properties": {
|
|
11
|
+
"kind": {
|
|
12
|
+
"$comment": "R-016's discriminator, so `tiphys validate --type auto` resolves this document without being told, and M3R-001's rule that a type is registered with the validator in the same step that ships its schema is satisfied in both halves. A per-phase extra probe file (R-054, `checklist resolve --extra`) is ALSO a checklist document and carries this same kind, which is what makes an extra probe set independently validatable instead of a fragment only one command can read.",
|
|
13
|
+
"type": "string",
|
|
14
|
+
"const": "checklist"
|
|
15
|
+
},
|
|
16
|
+
"id": {
|
|
17
|
+
"$comment": "The name `tiphys checklist resolve --checklist <id>` takes, and the basename of the shipped file. A TOKEN rather than free prose, because the resolver looks it up.",
|
|
18
|
+
"type": "string",
|
|
19
|
+
"minLength": 1,
|
|
20
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
21
|
+
},
|
|
22
|
+
"applies-to": {
|
|
23
|
+
"$comment": "What kind of review this whole list is for, in one sentence. Prose, deliberately: this one is read by a human deciding which checklist to run and is never grouped on.",
|
|
24
|
+
"type": "string",
|
|
25
|
+
"minLength": 1,
|
|
26
|
+
"pattern": "\\S"
|
|
27
|
+
},
|
|
28
|
+
"probes": {
|
|
29
|
+
"$comment": "`uniqueItems` is here and it is NOT the id-uniqueness rule. It compares whole items, so it catches a probe pasted twice verbatim and nothing else. Two probes sharing an id and differing in their question are unique to this keyword and are exactly the dangerous instance, which is why criterion 1's rejection is the derived check and not this line.",
|
|
30
|
+
"type": "array",
|
|
31
|
+
"minItems": 1,
|
|
32
|
+
"uniqueItems": true,
|
|
33
|
+
"items": {
|
|
34
|
+
"$ref": "#/$defs/probe"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"framings": {
|
|
38
|
+
"$comment": "T-001's second data point (M3R-004): the M1-P4 dual review found different defects because the two reviewers were given different STARTING QUESTIONS, and T-001's own words are that the checklists should vary the entry point rather than only the reviewer. A framing is therefore data in the artifact rather than a sentence in a dispatch prompt. Optional, because `checklists/flake-playbook.yaml` and `checklists/env-failure-diagnosis.yaml` are single-entry-point procedures and inventing framings for them would be ceremony. `uniqueItems` is here and, exactly as on `probes` above, it is NOT the id-uniqueness rule: it compares whole items, so two framings sharing an id and differing in their entry point are unique to it and are the dangerous instance, since `resolveChecklist` looks a framing up by id and first match wins. That is the derived check `checklist-framing-ids-unique`, added in fix round 2.",
|
|
39
|
+
"type": "array",
|
|
40
|
+
"minItems": 1,
|
|
41
|
+
"uniqueItems": true,
|
|
42
|
+
"items": {
|
|
43
|
+
"$ref": "#/$defs/framing"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"$defs": {
|
|
48
|
+
"probe": {
|
|
49
|
+
"$comment": "One question, its scope, and whether an answer must cite something.",
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": ["id", "probe", "applies-to", "evidence-required"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"id": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"minLength": 1,
|
|
57
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
58
|
+
},
|
|
59
|
+
"probe": {
|
|
60
|
+
"$comment": "THE QUESTION. Prose, and the one field this schema can say least about: `minLength` stops it being empty and nothing here stops it being generic. That gap is the phase's whole hazard class and the instrument is criterion 3b.",
|
|
61
|
+
"type": "string",
|
|
62
|
+
"minLength": 1,
|
|
63
|
+
"pattern": "\\S"
|
|
64
|
+
},
|
|
65
|
+
"applies-to": {
|
|
66
|
+
"$comment": "THE SCOPE TOKEN, and it is a token rather than prose because the resolver GROUPS ON IT. A framing's `orders-probes` names scopes, so this field is what makes `--framing` reorder the list rather than decorate it. A probe whose scope does not apply is still answerable ('not applicable, no destructive command in the diff'), so this is a grouping key and never a filter that silently drops a probe.",
|
|
67
|
+
"type": "string",
|
|
68
|
+
"minLength": 1,
|
|
69
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
70
|
+
},
|
|
71
|
+
"evidence-required": {
|
|
72
|
+
"$comment": "R-054's second failure mode: an extra probe merged in without this field. A boolean rather than an optional flag, so a probe cannot be silently opinion-only. True means the answer must cite a path, a line, a captured command or an exit code.",
|
|
73
|
+
"type": "boolean"
|
|
74
|
+
},
|
|
75
|
+
"verifies-gate": {
|
|
76
|
+
"$comment": "NEW at revision 3, criterion 3c. The id of the `gate-registry.yaml` entry whose `verified-by: clean-room-checklist` names this probe. OPTIONAL because most probes verify no gate, and it is what makes the checklist-to-registry direction computable at all: without a back-reference there is nothing to resolve and an orphaned probe stays invisible by construction. That every registry-named probe MUST carry it is an `if`/`then` across two documents, which no keyword here reaches; it is enforced by `gate-probes-resolve`.",
|
|
77
|
+
"type": "string",
|
|
78
|
+
"minLength": 1,
|
|
79
|
+
"pattern": "\\S"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"framing": {
|
|
84
|
+
"$comment": "One declared entry point into the same probe list.",
|
|
85
|
+
"type": "object",
|
|
86
|
+
"additionalProperties": false,
|
|
87
|
+
"required": ["id", "entry-point", "orders-probes"],
|
|
88
|
+
"properties": {
|
|
89
|
+
"id": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"minLength": 1,
|
|
92
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
93
|
+
},
|
|
94
|
+
"entry-point": {
|
|
95
|
+
"$comment": "The starting question this framing hands the reviewer, printed at the head of the resolved list. T-001's two real examples are walking the acceptance criteria as a contract, and starting from where this can destroy something or claim a guarantee it does not have.",
|
|
96
|
+
"type": "string",
|
|
97
|
+
"minLength": 1,
|
|
98
|
+
"pattern": "\\S"
|
|
99
|
+
},
|
|
100
|
+
"orders-probes": {
|
|
101
|
+
"$comment": "The probe SCOPES, in the order this framing wants them, each naming an `applies-to` token. Probes in a named scope lead, scope by scope, and inside one scope the FILE ORDER decides; every probe in no named scope follows in file order. Ordering by scope rather than by probe id is what makes criterion 4d falsifiable: `CLAUDE.md` says the reviewer's FIRST check is item 3, and with a scope list the first resolved probe is the first `fix-round` probe IN THE FILE, so moving it later changes the answer. A framing that listed probe ids instead would pin the head no matter where the probe sat, which is the hazard class's 'ordering expressed as a comment rather than as position' wearing a schema's clothes.",
|
|
102
|
+
"type": "array",
|
|
103
|
+
"minItems": 1,
|
|
104
|
+
"uniqueItems": true,
|
|
105
|
+
"items": {
|
|
106
|
+
"type": "string",
|
|
107
|
+
"minLength": 1,
|
|
108
|
+
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/cutover-state.schema.json",
|
|
4
|
+
"title": "Cutover state",
|
|
5
|
+
"description": "The fleet's cutover.json: the five freeze switches and what each of them records. Kernel plan M4, M4-P25 acceptance criterion 4.",
|
|
6
|
+
"$comment": "THE WIRE NAMES ARE camelCase AND THAT IS ESTABLISHED, NOT CHOSEN HERE. The M4 plan section spells the fields flipped-at, flipped-by, reason and restore-to; the document M4-P26 already writes and reads spells them flippedAt, flippedBy, reason and restoreTo (src/cutover.ts:98 declares the interface and src/cutover.ts:152 validates it). A schema that pinned the kebab spelling would refuse every document the shipped writer produces, so this pins what the document uses and the plan's spelling is read as prose naming the four fields rather than as their serialised keys.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"required": ["switches"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"switches": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"description": "One record per switch. The five names are a CLOSED list: a sixth name is a plan revision, not a document edit, because every rollback trigger enumerates them.",
|
|
13
|
+
"required": [
|
|
14
|
+
"planning-and-scope",
|
|
15
|
+
"review-and-arbitration",
|
|
16
|
+
"credentials-and-refs",
|
|
17
|
+
"salvage-and-recovery",
|
|
18
|
+
"closeout"
|
|
19
|
+
],
|
|
20
|
+
"properties": {
|
|
21
|
+
"planning-and-scope": { "$ref": "#/$defs/switchRecord" },
|
|
22
|
+
"review-and-arbitration": { "$ref": "#/$defs/switchRecord" },
|
|
23
|
+
"credentials-and-refs": { "$ref": "#/$defs/switchRecord" },
|
|
24
|
+
"salvage-and-recovery": { "$ref": "#/$defs/switchRecord" },
|
|
25
|
+
"closeout": { "$ref": "#/$defs/switchRecord" }
|
|
26
|
+
},
|
|
27
|
+
"additionalProperties": false
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": true,
|
|
31
|
+
"$defs": {
|
|
32
|
+
"switchRecord": {
|
|
33
|
+
"$comment": "additionalProperties is TRUE here and at the document level, against the schemas/README.md preference for false at every object level, and the deviation is deliberate rather than an omission. M4-P26 shipped a rollback that CARRIES document keys it does not own, at both levels, and registered that behaviour as a guarded test (test/cutover.test.ts:974). Closing either level would make the shipped writer refuse its own preserved keys, so this document is open by decision and the closed half is the switch NAME list one level up, which is the vocabulary that actually has to be closed.",
|
|
34
|
+
"type": "object",
|
|
35
|
+
"required": ["state", "flippedAt", "flippedBy", "reason", "restoreTo"],
|
|
36
|
+
"properties": {
|
|
37
|
+
"state": {
|
|
38
|
+
"description": "Which process holds the authority this switch governs.",
|
|
39
|
+
"enum": ["current", "kernel"]
|
|
40
|
+
},
|
|
41
|
+
"flippedAt": {
|
|
42
|
+
"description": "When the switch was last written, as an ISO 8601 instant.",
|
|
43
|
+
"type": "string",
|
|
44
|
+
"minLength": 1
|
|
45
|
+
},
|
|
46
|
+
"flippedBy": {
|
|
47
|
+
"description": "Who or what performed the write.",
|
|
48
|
+
"type": "string",
|
|
49
|
+
"minLength": 1
|
|
50
|
+
},
|
|
51
|
+
"reason": {
|
|
52
|
+
"description": "Why the switch was written.",
|
|
53
|
+
"type": "string",
|
|
54
|
+
"minLength": 1
|
|
55
|
+
},
|
|
56
|
+
"restoreTo": {
|
|
57
|
+
"description": "The value the switch held BEFORE the write. It is what makes rollback a matter of reading a recorded value rather than reconstructing an intent, and a record without it cannot be rolled back at all.",
|
|
58
|
+
"enum": ["current", "kernel"]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"additionalProperties": true
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/decision-record.schema.json",
|
|
4
|
+
"title": "Tiphys decision record",
|
|
5
|
+
"description": "Blueprint section 7's field list, plus the fields R-063 and R-090 need in order to be checkable rather than habitual. An OPEN QUESTION is a record with status open (D-7), so there is one register and never two.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": [
|
|
9
|
+
"kind",
|
|
10
|
+
"id",
|
|
11
|
+
"project",
|
|
12
|
+
"task",
|
|
13
|
+
"question",
|
|
14
|
+
"options",
|
|
15
|
+
"reversibility",
|
|
16
|
+
"vetoable",
|
|
17
|
+
"revert-cost",
|
|
18
|
+
"status",
|
|
19
|
+
"decided",
|
|
20
|
+
"date"
|
|
21
|
+
],
|
|
22
|
+
"properties": {
|
|
23
|
+
"kind": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"const": "decision-record"
|
|
26
|
+
},
|
|
27
|
+
"id": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"pattern": "^DR-[0-9]{4}$"
|
|
30
|
+
},
|
|
31
|
+
"project": { "type": "string", "minLength": 1 },
|
|
32
|
+
"task": { "type": "string", "minLength": 1 },
|
|
33
|
+
"question": { "type": "string", "minLength": 1 },
|
|
34
|
+
"options": {
|
|
35
|
+
"type": "array",
|
|
36
|
+
"minItems": 1,
|
|
37
|
+
"items": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"additionalProperties": false,
|
|
40
|
+
"required": ["label", "consequence"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"label": { "type": "string", "minLength": 1 },
|
|
43
|
+
"consequence": { "type": "string", "minLength": 1 }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"reversibility": {
|
|
48
|
+
"$comment": "R-063. Exactly three values, so the cost of being wrong is stated rather than implied.",
|
|
49
|
+
"type": "string",
|
|
50
|
+
"enum": ["reversible", "costly", "irreversible"]
|
|
51
|
+
},
|
|
52
|
+
"vetoable": {
|
|
53
|
+
"$comment": "R-090: a forced owner-adjacent call is decided, FLAGGED VETOABLE, and made trivially revertible. This field and revert-cost are what turn that sentence from a habit into a required field.",
|
|
54
|
+
"type": "boolean"
|
|
55
|
+
},
|
|
56
|
+
"revert-cost": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"minLength": 1
|
|
59
|
+
},
|
|
60
|
+
"status": {
|
|
61
|
+
"$comment": "D-7: an open question is a record with status open.",
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": ["open", "deferred", "decided"]
|
|
64
|
+
},
|
|
65
|
+
"decided": {
|
|
66
|
+
"$comment": "The answer in the decider's own terms. Empty while the record is open or deferred; a record with status decided and an empty decided field is a record that claims an answer it does not carry, which is the Kind A pair the if/then below enforces.",
|
|
67
|
+
"type": "string"
|
|
68
|
+
},
|
|
69
|
+
"date": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
|
|
72
|
+
},
|
|
73
|
+
"evidence": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "string", "minLength": 1 }
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"if": {
|
|
79
|
+
"type": "object",
|
|
80
|
+
"required": ["status"],
|
|
81
|
+
"properties": { "status": { "const": "decided" } }
|
|
82
|
+
},
|
|
83
|
+
"then": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"required": ["decided"],
|
|
86
|
+
"properties": { "decided": { "type": "string", "minLength": 1 } }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/executor-record.schema.json",
|
|
4
|
+
"title": "Tiphys executor launch record",
|
|
5
|
+
"description": "tasks/<id>/executor.json, the record an ExecutorAdapter writes at launch (DR-0006 for the format, PR-207 for the shape, M4-P3 for the contract). Until M4-P3 this document was written by the kernel and validated by nothing, which is the state delivery/plan/m4-intake.md:272 names. It is written BEFORE the payload starts, which is what makes a failure to write it provably a launch failure and therefore safe to roll back.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["adapter", "launchedAt"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"adapter": {
|
|
11
|
+
"$comment": "The adapter that wrote this record, by its own `name`. REQUIRED: a launch record that does not say what launched it cannot be attributed, and attribution is the whole reason an operator opens this file.",
|
|
12
|
+
"type": "string",
|
|
13
|
+
"minLength": 1
|
|
14
|
+
},
|
|
15
|
+
"launchedAt": {
|
|
16
|
+
"$comment": "RFC 3339 UTC, the same spelling every other Tiphys record uses, so two records from two machines sort. Written from `new Date().toISOString()`.",
|
|
17
|
+
"type": "string",
|
|
18
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
|
|
19
|
+
},
|
|
20
|
+
"deadline": {
|
|
21
|
+
"$comment": "PR-207. The absolute instant by which the task must have completed, present ONLY when --deadline was passed. Recorded as an instant rather than as raw seconds so the watcher compares it against the clock directly instead of re-deriving it from launchedAt.",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$"
|
|
24
|
+
},
|
|
25
|
+
"requestedTier": {
|
|
26
|
+
"$comment": "M4-P3 criterion 6. THE DECLARED TIER THE REQUEST CARRIED, VERBATIM, AND NEVER A MODEL NAME. Whatever role-model-config.yaml declares crosses the seam unaltered; the tier-to-model mapping lives in the plugin and never in src/, which is what keeps a harness that is not the one named possible at all (delivery/plan/m4-intake.md:377). The schema does not enum this value, because the vocabulary belongs to the plugin and an enum here would be that mapping's first half.",
|
|
27
|
+
"type": "string",
|
|
28
|
+
"minLength": 1
|
|
29
|
+
},
|
|
30
|
+
"requestedRole": {
|
|
31
|
+
"$comment": "M4-P3 criterion 6. The role the request carried, verbatim. Not enumerated here for the same reason requestedTier is not: roles/ is a shipped directory and the role-to-brief mapping is the plugin's.",
|
|
32
|
+
"type": "string",
|
|
33
|
+
"minLength": 1
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://tiphys.dev/schemas/final-report.schema.json",
|
|
4
|
+
"title": "Tiphys final report",
|
|
5
|
+
"$comment": "R-089a. Kernel plan M3, M3-P4 step 2. THE FINAL REPORT IS A PROJECTION, NOT A SUMMARY, and that property is load-bearing beyond this phase. Every field here is DERIVED from records that already exist (findings, verdicts, decisions, work histories), which is the same relation M3-P8's mechanism index has to the tuition feed. That relation is what makes a dense read layer possible on top of a verbose archive: the projections are consumed at every dispatch and must stay dense, while the raw entries are read only in dispute. M3 BUILDS NO COMPACTOR AND THIS SCHEMA PROPOSES NONE; what it does is make the distinction structural, so a later compaction is a question about which layer a file is in rather than a judgement about which files look like filler. SILENCE AND EMPTINESS ARE DISTINGUISHABLE: each of the four enumerable sections is a two-branch oneOf, so `none: true` carries NO entries key at all and `none: false` carries at least one entry. That closes BOTH directions of the relation rather than one: an empty list without a marker is a rejection, and a `none: true` marker sitting on top of real entries is also a rejection. THE PARITY BETWEEN `inputs[]` AND `input-findings[]` IS NOT HERE: cross-array completeness is not a keyword property (M3R-002), so it is the derived check `final-report-finding-parity` in src/checks.ts, and it is checked a second time by the M2-P6 coverage checker's finding-to-outcome parity mode because the artifact should be self-checking AND the independent checker is the one the pipeline runs.",
|
|
6
|
+
"description": "One document per delivery. Every input finding mapped to an outcome, plus the decisions owed, the owner verifications outstanding, the infrastructure left behind, and anything done out of band.",
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"required": [
|
|
10
|
+
"kind",
|
|
11
|
+
"subject",
|
|
12
|
+
"inputs",
|
|
13
|
+
"input-findings",
|
|
14
|
+
"decisions-owed",
|
|
15
|
+
"owner-verification",
|
|
16
|
+
"infrastructure-left",
|
|
17
|
+
"out-of-band"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"kind": {
|
|
21
|
+
"description": "The artifact type, so `tiphys validate --type auto` resolves this document without being told.",
|
|
22
|
+
"type": "string",
|
|
23
|
+
"const": "final-report"
|
|
24
|
+
},
|
|
25
|
+
"subject": {
|
|
26
|
+
"description": "What this report is the final report OF.",
|
|
27
|
+
"type": "string",
|
|
28
|
+
"minLength": 1,
|
|
29
|
+
"pattern": "\\S"
|
|
30
|
+
},
|
|
31
|
+
"inputs": {
|
|
32
|
+
"$comment": "The finding ids this delivery took in. Kept SEPARATE from `input-findings[]` on purpose: a table that is its own inventory cannot be incomplete, which is the circularity scripts/check-clause-map.mjs's header names one level up. The derived check compares the two.",
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
35
|
+
"uniqueItems": true
|
|
36
|
+
},
|
|
37
|
+
"input-findings": {
|
|
38
|
+
"$comment": "R-089a's table. Every id in `inputs[]` lands in exactly one row here with a non-empty outcome.",
|
|
39
|
+
"type": "array",
|
|
40
|
+
"items": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"additionalProperties": false,
|
|
43
|
+
"required": ["id", "outcome"],
|
|
44
|
+
"properties": {
|
|
45
|
+
"id": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
46
|
+
"outcome": { "type": "string", "minLength": 1, "pattern": "\\S" }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"decisions-owed": { "$ref": "#/$defs/enumerableSection" },
|
|
51
|
+
"owner-verification": { "$ref": "#/$defs/enumerableSection" },
|
|
52
|
+
"infrastructure-left": { "$ref": "#/$defs/enumerableSection" },
|
|
53
|
+
"out-of-band": { "$ref": "#/$defs/enumerableSection" }
|
|
54
|
+
},
|
|
55
|
+
"$defs": {
|
|
56
|
+
"enumerableSection": {
|
|
57
|
+
"$comment": "ALLOWED TO BE EMPTY ONLY WITH AN EXPLICIT MARKER, so silence and emptiness are distinguishable (plan step 2). The two branches are exclusive by construction: branch 1 permits `none: true` AND NOTHING ELSE, so a marker sitting on top of real entries is a rejection; branch 2 requires `none: false` with at least one entry, so an empty list hiding behind a false marker is a rejection too. Both directions, rather than the one the requirement's letter names. RESIDUE, ADDED IN M3-P4 FIX ROUND 2 BY THE CR-002 ENUMERATION: this is the same mechanism CR-002 named one document over. The branch is picked by A VALUE THE AUTHOR WRITES, and branch 1 owes NOTHING, so an author with three real decisions owed writes `none: true` and the schema is satisfied. What the two branches close is INTERNAL CONTRADICTION (a marker over entries, entries with no marker); what neither reaches is a marker over a truth outside the document. Nothing in this schema could reach it, because there is no second record here to compare against; the derived check `final-report-finding-parity` is what that comparison looks like where a second record exists, and `decisions-owed` has none.",
|
|
58
|
+
"oneOf": [
|
|
59
|
+
{
|
|
60
|
+
"type": "object",
|
|
61
|
+
"additionalProperties": false,
|
|
62
|
+
"required": ["none"],
|
|
63
|
+
"properties": { "none": { "type": "boolean", "const": true } }
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "object",
|
|
67
|
+
"additionalProperties": false,
|
|
68
|
+
"required": ["none", "entries"],
|
|
69
|
+
"properties": {
|
|
70
|
+
"none": { "type": "boolean", "const": false },
|
|
71
|
+
"entries": {
|
|
72
|
+
"type": "array",
|
|
73
|
+
"minItems": 1,
|
|
74
|
+
"items": {
|
|
75
|
+
"type": "object",
|
|
76
|
+
"additionalProperties": false,
|
|
77
|
+
"required": ["statement"],
|
|
78
|
+
"properties": {
|
|
79
|
+
"id": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
80
|
+
"statement": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
81
|
+
"owner": { "type": "string", "minLength": 1, "pattern": "\\S" }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|