@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.
Files changed (207) hide show
  1. package/AGENTS.md +663 -0
  2. package/LICENSE +202 -0
  3. package/assurance-modes.yaml +299 -0
  4. package/checklists/clean-room.yaml +325 -0
  5. package/checklists/env-failure-diagnosis.yaml +68 -0
  6. package/checklists/flake-playbook.yaml +68 -0
  7. package/checklists/hazard-review.yaml +144 -0
  8. package/checklists/plan-review.yaml +103 -0
  9. package/dist/bin/tiphys.d.ts +2 -0
  10. package/dist/bin/tiphys.js +92 -0
  11. package/dist/src/adapters/load.d.ts +202 -0
  12. package/dist/src/adapters/load.js +440 -0
  13. package/dist/src/brief.d.ts +32 -0
  14. package/dist/src/brief.js +66 -0
  15. package/dist/src/checklists.d.ts +169 -0
  16. package/dist/src/checklists.js +310 -0
  17. package/dist/src/checks.d.ts +1539 -0
  18. package/dist/src/checks.js +5025 -0
  19. package/dist/src/cli.d.ts +9 -0
  20. package/dist/src/cli.js +68 -0
  21. package/dist/src/commands/brief.d.ts +92 -0
  22. package/dist/src/commands/brief.js +343 -0
  23. package/dist/src/commands/checklist.d.ts +42 -0
  24. package/dist/src/commands/checklist.js +168 -0
  25. package/dist/src/commands/cutover.d.ts +35 -0
  26. package/dist/src/commands/cutover.js +448 -0
  27. package/dist/src/commands/doctor.d.ts +264 -0
  28. package/dist/src/commands/doctor.js +1546 -0
  29. package/dist/src/commands/gates.d.ts +9 -0
  30. package/dist/src/commands/gates.js +360 -0
  31. package/dist/src/commands/init.d.ts +30 -0
  32. package/dist/src/commands/init.js +177 -0
  33. package/dist/src/commands/lock.d.ts +34 -0
  34. package/dist/src/commands/lock.js +340 -0
  35. package/dist/src/commands/mode.d.ts +40 -0
  36. package/dist/src/commands/mode.js +134 -0
  37. package/dist/src/commands/next.d.ts +130 -0
  38. package/dist/src/commands/next.js +597 -0
  39. package/dist/src/commands/plan.d.ts +20 -0
  40. package/dist/src/commands/plan.js +105 -0
  41. package/dist/src/commands/pool.d.ts +1 -0
  42. package/dist/src/commands/pool.js +139 -0
  43. package/dist/src/commands/resume.d.ts +1 -0
  44. package/dist/src/commands/resume.js +88 -0
  45. package/dist/src/commands/spawn.d.ts +1 -0
  46. package/dist/src/commands/spawn.js +195 -0
  47. package/dist/src/commands/status.d.ts +21 -0
  48. package/dist/src/commands/status.js +122 -0
  49. package/dist/src/commands/sync.d.ts +47 -0
  50. package/dist/src/commands/sync.js +341 -0
  51. package/dist/src/commands/teardown.d.ts +1 -0
  52. package/dist/src/commands/teardown.js +87 -0
  53. package/dist/src/commands/tuition.d.ts +21 -0
  54. package/dist/src/commands/tuition.js +218 -0
  55. package/dist/src/commands/validate.d.ts +78 -0
  56. package/dist/src/commands/validate.js +430 -0
  57. package/dist/src/commands/watch.d.ts +1 -0
  58. package/dist/src/commands/watch.js +172 -0
  59. package/dist/src/cutover.d.ts +584 -0
  60. package/dist/src/cutover.js +1444 -0
  61. package/dist/src/exclusion.d.ts +389 -0
  62. package/dist/src/exclusion.js +843 -0
  63. package/dist/src/exec/env.d.ts +278 -0
  64. package/dist/src/exec/env.js +334 -0
  65. package/dist/src/fleet.d.ts +223 -0
  66. package/dist/src/fleet.js +298 -0
  67. package/dist/src/gates/adapters/http-json.d.ts +5 -0
  68. package/dist/src/gates/adapters/http-json.js +283 -0
  69. package/dist/src/gates/adapters/migrations-command.d.ts +1 -0
  70. package/dist/src/gates/adapters/migrations-command.js +373 -0
  71. package/dist/src/gates/citations.d.ts +408 -0
  72. package/dist/src/gates/citations.js +1169 -0
  73. package/dist/src/gates/coverage.d.ts +375 -0
  74. package/dist/src/gates/coverage.js +836 -0
  75. package/dist/src/gates/credentials.d.ts +233 -0
  76. package/dist/src/gates/credentials.js +752 -0
  77. package/dist/src/gates/deploy.d.ts +1 -0
  78. package/dist/src/gates/deploy.js +33 -0
  79. package/dist/src/gates/gate-classes.d.ts +56 -0
  80. package/dist/src/gates/gate-classes.js +633 -0
  81. package/dist/src/gates/manifest.d.ts +99 -0
  82. package/dist/src/gates/manifest.js +208 -0
  83. package/dist/src/gates/merge-preconditions.d.ts +319 -0
  84. package/dist/src/gates/merge-preconditions.js +932 -0
  85. package/dist/src/gates/migrations.d.ts +1 -0
  86. package/dist/src/gates/migrations.js +36 -0
  87. package/dist/src/gates/pin.d.ts +114 -0
  88. package/dist/src/gates/pin.js +154 -0
  89. package/dist/src/gates/red-witness.d.ts +22 -0
  90. package/dist/src/gates/red-witness.js +482 -0
  91. package/dist/src/gates/release.d.ts +283 -0
  92. package/dist/src/gates/release.js +820 -0
  93. package/dist/src/gates/result.d.ts +116 -0
  94. package/dist/src/gates/result.js +91 -0
  95. package/dist/src/gates/run.d.ts +614 -0
  96. package/dist/src/gates/run.js +1614 -0
  97. package/dist/src/gates/schemas/citation-config.schema.json +59 -0
  98. package/dist/src/gates/schemas/coverage-config.schema.json +77 -0
  99. package/dist/src/gates/schemas/gate-manifest.schema.json +125 -0
  100. package/dist/src/gates/schemas/gate-result.schema.json +160 -0
  101. package/dist/src/gates/schemas/phase-declaration.schema.json +87 -0
  102. package/dist/src/gates/schemas/release-record.schema.json +119 -0
  103. package/dist/src/gates/schemas/verifier-config.schema.json +101 -0
  104. package/dist/src/gates/schemas/witness-spec.schema.json +110 -0
  105. package/dist/src/gates/scope.d.ts +131 -0
  106. package/dist/src/gates/scope.js +1018 -0
  107. package/dist/src/gates/suite.d.ts +217 -0
  108. package/dist/src/gates/suite.js +968 -0
  109. package/dist/src/gates/validate.d.ts +121 -0
  110. package/dist/src/gates/validate.js +414 -0
  111. package/dist/src/hooks.d.ts +84 -0
  112. package/dist/src/hooks.js +125 -0
  113. package/dist/src/index.d.ts +31 -0
  114. package/dist/src/index.js +30 -0
  115. package/dist/src/liveness.d.ts +321 -0
  116. package/dist/src/liveness.js +396 -0
  117. package/dist/src/lock.d.ts +256 -0
  118. package/dist/src/lock.js +792 -0
  119. package/dist/src/model-resolution.d.ts +159 -0
  120. package/dist/src/model-resolution.js +307 -0
  121. package/dist/src/modes.d.ts +149 -0
  122. package/dist/src/modes.js +258 -0
  123. package/dist/src/path-identity.d.ts +34 -0
  124. package/dist/src/path-identity.js +48 -0
  125. package/dist/src/plan.d.ts +73 -0
  126. package/dist/src/plan.js +153 -0
  127. package/dist/src/pool.d.ts +326 -0
  128. package/dist/src/pool.js +988 -0
  129. package/dist/src/roles.d.ts +461 -0
  130. package/dist/src/roles.js +776 -0
  131. package/dist/src/spawn.d.ts +482 -0
  132. package/dist/src/spawn.js +1003 -0
  133. package/dist/src/status.d.ts +116 -0
  134. package/dist/src/status.js +148 -0
  135. package/dist/src/task.d.ts +504 -0
  136. package/dist/src/task.js +307 -0
  137. package/dist/src/teardown.d.ts +39 -0
  138. package/dist/src/teardown.js +422 -0
  139. package/dist/src/tuition.d.ts +159 -0
  140. package/dist/src/tuition.js +311 -0
  141. package/dist/src/validate.d.ts +263 -0
  142. package/dist/src/validate.js +742 -0
  143. package/dist/src/version.d.ts +3 -0
  144. package/dist/src/version.js +38 -0
  145. package/dist/src/watcher.d.ts +275 -0
  146. package/dist/src/watcher.js +849 -0
  147. package/dist/src/witness/run.d.ts +299 -0
  148. package/dist/src/witness/run.js +1373 -0
  149. package/dist/src/witness/spec.d.ts +270 -0
  150. package/dist/src/witness/spec.js +475 -0
  151. package/dist/tsconfig.src.tsbuildinfo +1 -0
  152. package/gate-registry.yaml +526 -0
  153. package/gates.manifest.json +257 -0
  154. package/package.json +72 -3
  155. package/role-model-config.yaml +88 -0
  156. package/roles/README.md +128 -0
  157. package/roles/_shared-dispatch-contract.md +87 -0
  158. package/roles/adversarial-plan-reviewer.md +80 -0
  159. package/roles/clean-room-reviewer.md +140 -0
  160. package/roles/implementer.md +463 -0
  161. package/roles/investigator.md +138 -0
  162. package/roles/plan-writer.md +95 -0
  163. package/schemas/README.md +82 -0
  164. package/schemas/assurance-modes.schema.json +264 -0
  165. package/schemas/charter.schema.json +185 -0
  166. package/schemas/checklist.schema.json +114 -0
  167. package/schemas/cutover-state.schema.json +64 -0
  168. package/schemas/decision-record.schema.json +88 -0
  169. package/schemas/executor-record.schema.json +36 -0
  170. package/schemas/final-report.schema.json +90 -0
  171. package/schemas/finding.schema.json +106 -0
  172. package/schemas/gate-registry.schema.json +260 -0
  173. package/schemas/mechanism-index.schema.json +94 -0
  174. package/schemas/model-resolution.schema.json +362 -0
  175. package/schemas/plan.schema.json +300 -0
  176. package/schemas/report.schema.json +579 -0
  177. package/schemas/role-brief.schema.json +105 -0
  178. package/schemas/role-model-config.schema.json +90 -0
  179. package/schemas/status-line.schema.json +40 -0
  180. package/schemas/tuition.schema.json +191 -0
  181. package/schemas/verdict.schema.json +295 -0
  182. package/schemas/work-history.schema.json +183 -0
  183. package/schemas/write-bypass.schema.json +69 -0
  184. package/templates/charter.example.yaml +54 -0
  185. package/templates/decision-record.example.yaml +27 -0
  186. package/templates/final-report.example.yaml +80 -0
  187. package/templates/plan.example.yaml +87 -0
  188. package/templates/report.example.yaml +236 -0
  189. package/templates/warnings.md +74 -0
  190. package/templates/work-history.example.yaml +185 -0
  191. package/tuition/README.md +76 -0
  192. package/tuition/T-001.yaml +48 -0
  193. package/tuition/T-002.yaml +51 -0
  194. package/tuition/T-003.yaml +100 -0
  195. package/tuition/T-004.yaml +52 -0
  196. package/tuition/T-005.yaml +72 -0
  197. package/tuition/T-006.yaml +81 -0
  198. package/tuition/T-007.yaml +56 -0
  199. package/tuition/T-008.yaml +111 -0
  200. package/tuition/T-009.yaml +50 -0
  201. package/tuition/T-015.yaml +36 -0
  202. package/tuition/T-016.yaml +36 -0
  203. package/tuition/T-017.yaml +46 -0
  204. package/tuition/T-018.yaml +84 -0
  205. package/tuition/T-021.yaml +40 -0
  206. package/tuition/T-022.yaml +36 -0
  207. package/tuition/mechanism-index.yaml +256 -0
@@ -0,0 +1,295 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://tiphys.dev/schemas/verdict.schema.json",
4
+ "title": "Tiphys clean-room review verdict",
5
+ "$comment": "R-053, R-057b, R-060, T-001, T-007. Kernel plan M3, M3-P7 steps 6 and 6a. THE OUTPUT OF A CLEAN-ROOM REVIEW, and the document that decides what a review is ALLOWED TO SAY. THE HAZARD THIS DOCUMENT EXISTS AGAINST is the phase's own last item: a verdict that admits APPROVE alongside an unaddressed hazard class. WHAT IT REACHES. (1) APPROVE beside a finding the review itself ranked high or critical, which is a review saying yes while recording a reason to say no, and is how a fix round gets skipped; the root `if`/`then` inverts it into the form the closed vocabulary can carry (schemas/README.md has no `not`): a set CONTAINING such a finding must carry the FIX-ROUND-NEEDED verdict. Stated deliberately WIDER than criterion 4(a), which names `high` alone: `critical` outranks it, and a rule that stopped at `high` would let the worse finding through. (2) A finding with no `concrete-fix`, on EVERY finding rather than on high ones, because a low finding with no proposed edit is a remark. (3) A verdict with no `produced-by` or no `framing`: DR-0012 condition 1 compares two reviews of one head on family AND entry point, and neither comparison is reachable from inside one document, so what is bought here is that neither field can be absent. (4) T-007's `review-contract`, and `hazard-classes-addressed[]` required exactly when the contract is `hazard`, through the `oneOf`. WHAT IT CANNOT REACH, each with its instrument. (a) Whether `criteria[]` covers every acceptance criterion of the phase: that is a comparison against a DIFFERENT document and is the Kind B check `verdict-criteria-complete`. (b) Same for `deviations-judged[]` against the work history's `deviations[]` (M3R-005), check `verdict-deviations-judged`. (c) Same for `hazard-classes-addressed[]` against the plan phase's `hazard-classes[]`, check `verdict-hazard-classes-addressed`. (d) Whether a `cleared-because` statement is true, or whether `met: true` was earned; those are the reviewer's judgement and no keyword reaches them. (e) ADDED IN FIX ROUND 2, and it is INTRA-document rather than cross-document, which is why it was missed: whether `hazard-classes-addressed[].finding` names a finding this document actually declares. It is the check `verdict-finding-references-resolve`, and what it protects is rule (1) above, which reads `findings[]` alone and is therefore blind to a finding recorded one field away.",
6
+ "description": "A clean-room review verdict: the decision, the findings behind it, and the three completeness arrays that say what the review actually walked.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "kind",
11
+ "phase",
12
+ "head",
13
+ "verdict",
14
+ "produced-by",
15
+ "framing",
16
+ "review-contract",
17
+ "findings",
18
+ "criteria",
19
+ "deviations-judged"
20
+ ],
21
+ "properties": {
22
+ "kind": {
23
+ "$comment": "R-016's discriminator, so `tiphys validate --type auto` resolves this document without being told (M3R-001).",
24
+ "type": "string",
25
+ "const": "verdict"
26
+ },
27
+ "phase": {
28
+ "$comment": "The plan phase this review is OF. Not decoration: it is the join key all three Kind B checks use to select the phase in `plan.yaml` and to confirm `work-history.yaml` is the right one. A verdict that named no phase would make every cross-document completeness rule unimplementable, which is the same reason the checklist probe carries `verifies-gate`.",
29
+ "type": "string",
30
+ "minLength": 1,
31
+ "pattern": "\\S"
32
+ },
33
+ "head": {
34
+ "$comment": "M4-P10, discharging DR-0012 condition 1's head clause (delivery/decisions/DR-0012-delegated-merge-authority.md:22): two independent clean-room reviews exist FOR THE CURRENT HEAD. WHY IT IS REQUIRED RATHER THAN OPTIONAL, decided here because the plan left the choice open and the migration cost is not zero. Before this field the only thing scoping a set of verdicts to one head was the DIRECTORY the operator pointed the gate at, a convention recorded as a declared reading in delivery/work-history/m3-p9.md and enforced by nothing. An OPTIONAL head leaves that convention in place for every document that omits it, which is the whole existing population, so the gate would keep grouping by directory and the clause would stay asserted by a human while reading as checked. Required is the only spelling that removes the convention. WHY FORTY LOWERCASE HEX AND NOT AN ABBREVIATION. A short sha and a full sha are two spellings of ONE fact, and no canonical form reconciles them: nothing here can know that a seven-character value is a prefix of a forty-character sibling without resolving both against a repository this schema is never given. Two spellings of one head would then form two groups of one, which is the fail-open direction, because a group of one is never compared to anything. The pattern refuses the abbreviation at the document boundary instead. Case is refused here and ALSO folded downstream by the derived check's `establishField`, so the two layers agree rather than one relying on the other. WHAT IT DOES NOT BUY, stated rather than left to be found. Nothing here checks that the value names a commit that exists, or that it is the commit the reviewer actually read; the field makes the CLAIM explicit and comparable between two documents, it does not make it true. And a verdict cannot carry the sha of the commit that CONTAINS it, because committing the verdict changes the tree and therefore the sha. `head` names the commit that was REVIEWED, which is an ancestor of the commit carrying the verdict.",
35
+ "type": "string",
36
+ "pattern": "^[0-9a-f]{40}$"
37
+ },
38
+ "verdict": {
39
+ "$comment": "R-060's closed vocabulary, exactly two values. A third value such as 'approve with comments' is the shape that lets a fix round be skipped by wording, so the enum is the whole point of the field.",
40
+ "type": "string",
41
+ "enum": ["APPROVE", "FIX-ROUND-NEEDED"]
42
+ },
43
+ "produced-by": {
44
+ "$comment": "T-001: record in the review header which model family produced it. DR-0012 condition 1 requires the two clean-room reviews of one head to differ here, and that comparison is between two documents.",
45
+ "type": "string",
46
+ "minLength": 1,
47
+ "pattern": "\\S"
48
+ },
49
+ "framing": {
50
+ "$comment": "Step 6: which entry point this review was given, naming a `framings[].id` of the checklist it ran. T-001's second lesson is that decorrelation comes from the STARTING QUESTION rather than only from the reviewer, so a verdict that does not record its framing cannot be checked for decorrelation at all.",
51
+ "type": "string",
52
+ "minLength": 1,
53
+ "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
54
+ },
55
+ "review-contract": {
56
+ "$comment": "T-007, step 6a. Which of the two review CONTRACTS produced this verdict, mirroring the field the role brief carries (M3-P6). `scripts/check-dual-review.mjs` can then check contract distinctness alongside model-family and framing distinctness, which is T-007's point: the phase that met fifteen of fifteen criteria and live-locked every supervision command was caught by a reviewer that differed in its BRIEF, not in its model.",
57
+ "type": "string",
58
+ "enum": ["criteria", "hazard"]
59
+ },
60
+ "findings": {
61
+ "type": "array",
62
+ "items": {
63
+ "$ref": "#/$defs/finding"
64
+ }
65
+ },
66
+ "criteria": {
67
+ "$comment": "R-053: each acceptance criterion quoted, with file:line evidence and a met-or-not-met verdict. One entry per criterion; that it is EVERY criterion is Kind B.",
68
+ "type": "array",
69
+ "minItems": 1,
70
+ "items": {
71
+ "$ref": "#/$defs/criterionWalk"
72
+ }
73
+ },
74
+ "deviations-judged": {
75
+ "$comment": "R-057b, and M3R-005 is why it is an ARRAY rather than a probe question. 'Each declared deviation judged against the plan's intent by the reviewer, never assumed by the implementer' has exactly the same completeness shape as criteria coverage, and revision 0 had left it as a bare probe, so a reviewer could silently skip judging one of three declared deviations and every criterion still passed. Empty is legitimate: a phase can declare no deviation.",
76
+ "type": "array",
77
+ "items": {
78
+ "$ref": "#/$defs/deviationJudgement"
79
+ }
80
+ },
81
+ "hazard-classes-addressed": {
82
+ "$comment": "T-007, step 6a. Required exactly when `review-contract` is `hazard`, by the `oneOf` below. One entry per class declared by the referenced plan phase; that it is EVERY class is Kind B, check `verdict-hazard-classes-addressed`, which has the shape `verdict-criteria-complete` has for criteria and for the same reason.",
83
+ "type": "array",
84
+ "minItems": 1,
85
+ "items": {
86
+ "$ref": "#/$defs/hazardClassAddressed"
87
+ }
88
+ }
89
+ },
90
+ "if": {
91
+ "$comment": "WIDENED TO `medium` BY M4-P10, AND THAT WIDENING IS THE POINT OF THE FIELD LIST BELOW. As shipped by M3-P7 this enum read [high, critical] while DR-0012 condition 2 (delivery/decisions/DR-0012-delegated-merge-authority.md:23) bars an unresolved finding at high OR MEDIUM. So a verdict reading APPROVE beside a finding the review itself ranked `medium` validated at exit 0, and the merge precondition the schema exists to carry was one severity wider than the schema. `low` is deliberately still mergeable, which is what that same line of DR-0012 says. THE DANGEROUS INSTANCE, criterion 4(a), inverted into the closed vocabulary's reach. The rule wanted is APPROVE implies no high finding, and the direct spelling needs `not`, which schemas/README.md does not permit. `contains` matches the NON-empty case, which is the polarity that works here: a set that CONTAINS a finding the review itself ranked high or critical is a set whose verdict must be FIX-ROUND-NEEDED. `type: array` is restated inside because ajv 8.20.0 under `strict: true` refuses `contains` in a subschema that has not declared its type at the same level.",
92
+ "properties": {
93
+ "findings": {
94
+ "type": "array",
95
+ "contains": {
96
+ "type": "object",
97
+ "required": ["severity"],
98
+ "properties": {
99
+ "severity": {
100
+ "type": "string",
101
+ "enum": ["medium", "high", "critical"]
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ },
108
+ "then": {
109
+ "$comment": "So APPROVE beside a medium, high or critical finding fails HERE, naming the verdict field (widened from high by M4-P10). Restated in `properties` at this level because a bare `enum` under a name ajv cannot see declared is a compilation error under strictTypes.",
110
+ "properties": {
111
+ "verdict": {
112
+ "type": "string",
113
+ "enum": ["FIX-ROUND-NEEDED"]
114
+ }
115
+ }
116
+ },
117
+ "oneOf": [
118
+ {
119
+ "$comment": "Branch A, the criteria contract. `hazard-classes-addressed` is not required, and criterion 4e asserts a `criteria` verdict is unaffected by the hazard completeness check as well, so the rule applies exactly where the contract applies and nowhere else.",
120
+ "properties": {
121
+ "review-contract": {
122
+ "type": "string",
123
+ "const": "criteria"
124
+ }
125
+ }
126
+ },
127
+ {
128
+ "$comment": "Branch B, the hazard contract (T-007). `review-contract` and `hazard-classes-addressed` are BOTH restated in a sibling `properties` here, which is not redundancy: measured against ajv 8.20.0 under this validator's `strict: true`, a `required` naming a property not declared in `properties` at the same level fails COMPILATION under strictRequired. The two branches are discriminated by a `const` on one field, so exactly one can ever match and `oneOf` is an exclusive choice rather than an ambiguity.",
129
+ "required": ["hazard-classes-addressed"],
130
+ "properties": {
131
+ "review-contract": {
132
+ "type": "string",
133
+ "const": "hazard"
134
+ },
135
+ "hazard-classes-addressed": {
136
+ "type": "array",
137
+ "minItems": 1
138
+ }
139
+ }
140
+ }
141
+ ],
142
+ "$defs": {
143
+ "finding": {
144
+ "$comment": "R-060: severity-ranked, a concrete fix each. Ranked low < medium < high < critical, the same four names schemas/finding.schema.json and schemas/plan.schema.json use, so the kernel carries one severity vocabulary rather than three.",
145
+ "type": "object",
146
+ "additionalProperties": false,
147
+ "required": ["id", "severity", "evidence", "concrete-fix"],
148
+ "properties": {
149
+ "id": {
150
+ "$comment": "The stable id the arbitration and the fix round cite. CLAUDE.md owns the scheme (CR-nnn for a clean-room finding on a PR); this schema does not pick one.",
151
+ "type": "string",
152
+ "minLength": 1,
153
+ "pattern": "\\S"
154
+ },
155
+ "severity": {
156
+ "type": "string",
157
+ "enum": ["low", "medium", "high", "critical"]
158
+ },
159
+ "evidence": {
160
+ "$comment": "Evidence beats assertion: exit codes, counts, paths with line numbers, captured output. `minItems: 1` because a finding with no evidence is an opinion, and this repository treats a claim with no verifiable artifact behind it as unknown.",
161
+ "type": "array",
162
+ "minItems": 1,
163
+ "items": {
164
+ "type": "string",
165
+ "minLength": 1,
166
+ "pattern": "\\S"
167
+ }
168
+ },
169
+ "concrete-fix": {
170
+ "$comment": "Criterion 4(b) names a FIX-ROUND-NEEDED finding with no concrete fix as the dangerous instance. Required on EVERY finding regardless of verdict or severity, which is deliberately stronger: a review made of remarks is the empty review with extra steps. DR-0027 sharpens what a fix should say, since a finding that cannot name the shipped behaviour at risk has found nothing worth a round.",
171
+ "type": "string",
172
+ "minLength": 1,
173
+ "pattern": "\\S"
174
+ },
175
+ "analysis": {
176
+ "$comment": "The argument behind one finding, which is not enumerable and therefore lives inside a field rather than becoming structure (section 1.5). Optional, non-empty when present.",
177
+ "type": "string",
178
+ "minLength": 1,
179
+ "pattern": "\\S"
180
+ }
181
+ }
182
+ },
183
+ "criterionWalk": {
184
+ "$comment": "R-053, one acceptance criterion walked.",
185
+ "type": "object",
186
+ "additionalProperties": false,
187
+ "required": ["id", "quote", "evidence", "met"],
188
+ "properties": {
189
+ "id": {
190
+ "$comment": "The `acceptance[].id` of the criterion in the referenced plan phase. This is the join key `verdict-criteria-complete` compares; a walk keyed only by its quoted text could not be compared to anything without matching prose.",
191
+ "type": "string",
192
+ "minLength": 1,
193
+ "pattern": "\\S"
194
+ },
195
+ "quote": {
196
+ "$comment": "R-053 says QUOTED, so the reviewer has read the criterion rather than the id. The schema cannot check that the quote matches the plan's text; it can require that something was quoted.",
197
+ "type": "string",
198
+ "minLength": 1,
199
+ "pattern": "\\S"
200
+ },
201
+ "evidence": {
202
+ "type": "array",
203
+ "minItems": 1,
204
+ "items": {
205
+ "type": "string",
206
+ "minLength": 1,
207
+ "pattern": "\\S"
208
+ }
209
+ },
210
+ "met": {
211
+ "type": "boolean"
212
+ }
213
+ }
214
+ },
215
+ "deviationJudgement": {
216
+ "$comment": "R-057b, one declared deviation judged.",
217
+ "type": "object",
218
+ "additionalProperties": false,
219
+ "required": ["deviation", "serves-plan-intent", "reasoning"],
220
+ "properties": {
221
+ "deviation": {
222
+ "$comment": "The work history's `deviations[].plan-clause`, verbatim. The join key `verdict-deviations-judged` compares.",
223
+ "type": "string",
224
+ "minLength": 1,
225
+ "pattern": "\\S"
226
+ },
227
+ "serves-plan-intent": {
228
+ "$comment": "The REVIEWER's judgement, which is the half R-057b insists is never the implementer's. A boolean, so a deviation cannot be waved through in prose that reads as approval without being one.",
229
+ "type": "boolean"
230
+ },
231
+ "reasoning": {
232
+ "type": "string",
233
+ "minLength": 1,
234
+ "pattern": "\\S"
235
+ }
236
+ }
237
+ },
238
+ "hazardClassAddressed": {
239
+ "$comment": "T-007, step 6a: one declared hazard class, probed, and either a finding it produced or a statement clearing it.",
240
+ "type": "object",
241
+ "additionalProperties": false,
242
+ "required": ["class-id", "probed"],
243
+ "properties": {
244
+ "class-id": {
245
+ "$comment": "The `hazard-classes[].id` of the referenced plan phase, the join key `verdict-hazard-classes-addressed` compares.",
246
+ "type": "string",
247
+ "minLength": 1,
248
+ "pattern": "\\S"
249
+ },
250
+ "probed": {
251
+ "$comment": "What the reviewer actually DID against this class. The hazard checklist's canonical probes each name a construction rather than asking a bare question (a real mkfifo, a forced concurrency, a killed process mid-write, a destroy on a branch carrying committed unpushed work), and this is where that construction is recorded.",
252
+ "type": "string",
253
+ "minLength": 1,
254
+ "pattern": "\\S"
255
+ },
256
+ "finding": {
257
+ "$comment": "The `findings[].id` this class produced, when it produced one. THE ONLY INTRA-DOCUMENT ID REFERENCE IN ANY SHIPPED SCHEMA, and resolving it is the Kind B check `verdict-finding-references-resolve` rather than a keyword: matching one array's entry against another array's ids is not a keyword property under any DR-0013 option. It is not decoration. The escalation rule at the root of this document reads `findings[]` and nothing else, so a class recorded as having produced a finding that never reaches `findings[]` is an APPROVE the rule cannot see past; measured before the check, that document validated at exit 0.",
258
+ "type": "string",
259
+ "minLength": 1,
260
+ "pattern": "\\S"
261
+ },
262
+ "cleared-because": {
263
+ "$comment": "The statement clearing the class, when the probe produced no finding. Step 6a asks for EITHER a finding reference OR this, and the `oneOf` below is that either.",
264
+ "type": "string",
265
+ "minLength": 1,
266
+ "pattern": "\\S"
267
+ }
268
+ },
269
+ "oneOf": [
270
+ {
271
+ "$comment": "Branch A: the class produced a finding. `finding` is restated in a sibling `properties` for the strictRequired reason recorded on the root `oneOf`.",
272
+ "required": ["finding"],
273
+ "properties": {
274
+ "finding": {
275
+ "type": "string",
276
+ "minLength": 1,
277
+ "pattern": "\\S"
278
+ }
279
+ }
280
+ },
281
+ {
282
+ "$comment": "Branch B: the class was cleared and the reviewer says why. An entry carrying BOTH matches both branches and is therefore invalid, which is deliberate: a class both cleared and found is a contradiction and the reader cannot tell which the review meant.",
283
+ "required": ["cleared-because"],
284
+ "properties": {
285
+ "cleared-because": {
286
+ "type": "string",
287
+ "minLength": 1,
288
+ "pattern": "\\S"
289
+ }
290
+ }
291
+ }
292
+ ]
293
+ }
294
+ }
295
+ }
@@ -0,0 +1,183 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://tiphys.dev/schemas/work-history.schema.json",
4
+ "title": "Tiphys work history",
5
+ "$comment": "R-035, R-052a, R-083a. Kernel plan M3, M3-P4 step 3. THE WORK HISTORY IS THE ARTIFACT A LATER REVIEWER TRUSTS and the one CLAUDE.md says must never be softened, which is why `claims[]`, `fix-round[]` and `gate-evidence[]` are the REPORT SCHEMA'S OWN DEFINITIONS reached by $ref into report.schema.json rather than restated here. A shared definition is not a convenience: two independently-drifting copies of the honesty contract is the drift hole M3-P2 closes for gates and M3-P3 closes for mode ids, and a registered test asserts that both documents resolve to the SAME definition object rather than to two equal ones. THE SHARING IS OF KEYWORDS ONLY, AND THAT WAS ONCE A HOLE: a derived check is registered per artifact TYPE and reads a type-specific KEY, so a Kind B rule written against a shared `$def` does not follow the `$ref` here (M3-P4 round-1 finding CR-001). Every shared `$def` in report.schema.json now states whether a derived check guards it, the one that is guarded declares this type in `alsoTypes`, and test/report-contract.test.ts derives the relation from the schemas so a stale claim reddens rather than reassures. HOW THE $ref RESOLVES: the reference is RELATIVE, so it resolves against this document's $id to https://tiphys.dev/schemas/report.schema.json and matches that document's own $id. Nothing is fetched. `src/commands/validate.ts` declares report.schema.json as this type's COMPANION and registers it with the same compiler before this document is compiled, which is a named, in-directory, shipped-schema registration and not the remote loading DR-0013 clause 4 withholds. R-083a's ACCUMULATION HALF is `environment-warnings[]`; its template half is templates/warnings.md.",
6
+ "description": "One document per phase branch. The prompt verbatim, what was touched, what was decided and why, what was verified before any code was written, every deviation, the gate evidence, the claims made and how each was settled, and the environment warnings the phase accumulated.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "kind",
11
+ "phase",
12
+ "prompt",
13
+ "files-touched",
14
+ "per-step-commits",
15
+ "key-decisions",
16
+ "verification-first",
17
+ "deviations",
18
+ "gate-evidence",
19
+ "claims",
20
+ "environment-warnings"
21
+ ],
22
+ "properties": {
23
+ "kind": {
24
+ "description": "The artifact type, so `tiphys validate --type auto` resolves this document without being told.",
25
+ "type": "string",
26
+ "const": "work-history"
27
+ },
28
+ "phase": {
29
+ "type": "string",
30
+ "minLength": 1,
31
+ "pattern": "\\S"
32
+ },
33
+ "prompt": {
34
+ "$comment": "R-052a: VERBATIM. A block scalar, and the schema cannot tell verbatim from paraphrased; what it can do is refuse an empty or whitespace-only one.",
35
+ "type": "string",
36
+ "minLength": 1,
37
+ "pattern": "\\S"
38
+ },
39
+ "files-touched": {
40
+ "type": "array",
41
+ "items": { "type": "string", "minLength": 1, "pattern": "\\S" }
42
+ },
43
+ "per-step-commits": {
44
+ "type": "array",
45
+ "items": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "required": ["sha", "subject"],
49
+ "properties": {
50
+ "sha": { "type": "string", "pattern": "^[0-9a-f]{7,40}$" },
51
+ "subject": { "type": "string", "minLength": 1, "pattern": "\\S" }
52
+ }
53
+ }
54
+ },
55
+ "key-decisions": {
56
+ "$comment": "R-052a: the WHY that is invisible in the diff. `why` is required, so a decision cannot be recorded as a bare fact.",
57
+ "type": "array",
58
+ "items": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["decision", "why"],
62
+ "properties": {
63
+ "decision": { "type": "string", "minLength": 1, "pattern": "\\S" },
64
+ "why": { "type": "string", "minLength": 1, "pattern": "\\S" }
65
+ }
66
+ }
67
+ },
68
+ "verification-first": {
69
+ "$comment": "R-035, D-M3-03. Findings written BEFORE any code, recorded verbatim. `contradicts-plan` is a REQUIRED boolean, so the question is answered rather than skipped, and a `true` drags a `stopped-and-reported` reference with it: the whole point of R-035 is that a finding contradicting the plan is escalated rather than implemented around, and a record that says it contradicted the plan while naming no escalation is the shape that rule exists to forbid. RESIDUE, STATED HERE BECAUSE THE FIX ROUND 2 ENUMERATION FOUND IT AND NOTHING ELSE ON THIS BRANCH RECORDS IT: this is CR-002's mechanism in boolean form. The `if` keys off A VALUE THE AUTHOR CHOOSES, and the `false` branch owed NOTHING, so a finding that DOES contradict the plan and is recorded as `contradicts-plan: false` escaped the escalation reference entirely. FIX ROUND 2 WROTE HERE THAT NO KEYWORD AND NO DERIVED CHECK COULD REACH IT, on the ground that deciding whether a finding contradicts the plan is a reading of two documents in prose. THAT SENTENCE WAS FALSE AND IS CORRECTED RATHER THAN QUIETLY DELETED, because it is the exact shape this whole schema exists to refuse: the round-2 delta verifier refuted it by CONSTRUCTION (finding DV-002), and the reason it was wrong is that the second document is not outside this one at all, since `finding` is prose carried in the same object. The `false` branch of `$defs/verificationFirst`'s `oneOf` now narrows that prose; see its own comment for the token list and for what it still does not reach. The required boolean makes the question unskippable and the pattern prices the most obvious lies, and NEITHER makes the answer true; M3-P7's clean-room checklist is where that is checked.",
70
+ "type": "array",
71
+ "items": { "$ref": "#/$defs/verificationFirst" }
72
+ },
73
+ "deviations": {
74
+ "$comment": "R-057a, the same shape the report carries.",
75
+ "type": "array",
76
+ "items": {
77
+ "type": "object",
78
+ "additionalProperties": false,
79
+ "required": ["plan-clause", "why"],
80
+ "properties": {
81
+ "plan-clause": { "type": "string", "minLength": 1, "pattern": "\\S" },
82
+ "why": { "type": "string", "minLength": 1, "pattern": "\\S" }
83
+ }
84
+ }
85
+ },
86
+ "gate-evidence": {
87
+ "$comment": "R-049, R-086. THE REPORT SCHEMA'S gate-results DEFINITION, by $ref, not a copy of it. THE KEY IS DIFFERENT HERE (`gate-evidence`, not `gate-results`) AND THAT DIFFERENCE IS LOAD-BEARING: the derived check `report-parity-arithmetic` guards this definition, and a check registered for one type reading one hard-coded key was blind on this document even though the keywords were shared, so a work history claiming 9999 tests discovered and 1 passed validated while the identical counts in a report did not (M3-P4 round-1 finding CR-001). src/checks.ts now enumerates the key per type in `GATE_RESULT_SITES` and the check declares `alsoTypes: [work-history]`.",
88
+ "type": "array",
89
+ "items": { "$ref": "report.schema.json#/$defs/gateResult" }
90
+ },
91
+ "claims": {
92
+ "$comment": "T-006, D-M3-30. THE REPORT SCHEMA'S claims DEFINITION, by $ref, not a copy of it.",
93
+ "type": "array",
94
+ "items": { "$ref": "report.schema.json#/$defs/claim" }
95
+ },
96
+ "fix-round": {
97
+ "$comment": "CLAUDE.md's fix-round contract, D-M3-30. THE REPORT SCHEMA'S fix-round DEFINITION, by $ref, not a copy of it. An ARRAY here and a single object in the report, because a phase branch carries many rounds and one report answers one of them; the ELEMENT is the same definition in both. Optional, because a phase with no fix round has none to record.",
98
+ "type": "array",
99
+ "items": { "$ref": "report.schema.json#/$defs/fixRound" }
100
+ },
101
+ "environment-warnings": {
102
+ "$comment": "R-083a's ACCUMULATION HALF. Its template half is templates/warnings.md, which src/brief.ts appends verbatim to every brief. A warning recorded here without evidence is still a warning, so `evidence` is optional and `warning` is not; making evidence mandatory would price an honest note out of the record, which is this phase's own worst hazard one size down.",
103
+ "type": "array",
104
+ "items": {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "required": ["warning"],
108
+ "properties": {
109
+ "warning": { "type": "string", "minLength": 1, "pattern": "\\S" },
110
+ "evidence": { "type": "string", "minLength": 1, "pattern": "\\S" }
111
+ }
112
+ }
113
+ }
114
+ },
115
+ "$defs": {
116
+ "verificationFirst": {
117
+ "type": "object",
118
+ "additionalProperties": false,
119
+ "required": ["finding", "contradicts-plan"],
120
+ "properties": {
121
+ "finding": {
122
+ "$comment": "Recorded VERBATIM (R-035).",
123
+ "type": "string",
124
+ "minLength": 1,
125
+ "pattern": "\\S"
126
+ },
127
+ "contradicts-plan": { "type": "boolean" },
128
+ "stopped-and-reported": {
129
+ "type": "string",
130
+ "minLength": 1,
131
+ "pattern": "\\S"
132
+ },
133
+ "plan-language-note": {
134
+ "$comment": "M3-P4 FIX ROUND 4, FINDING DV3-002. Declared here as well as in the branch that requires it, because this object sets `additionalProperties: false` and a field absent from THIS block is refused before any branch is reached. A DECLARED RESIDUE, MEASURED RATHER THAN ASSUMED: the third `oneOf` branch below is the only one that REQUIRES this field, and the first branch (`contradicts-plan: true`) sets no `additionalProperties`, so a `true` record carrying this note validates and nothing refuses it. Making that a rejection means giving branch 1 an `additionalProperties: false` and restating every property of this object inside it, which is a change to the branch each `contradicts-plan: true` witness names; it was not worth that, and it is written down here instead of being left for a reader to find.",
135
+ "type": "string",
136
+ "minLength": 1,
137
+ "pattern": "\\S"
138
+ }
139
+ },
140
+ "if": {
141
+ "$comment": "Kind A, both sides on the SAME object, so the escalation cannot be satisfied by a reference recorded elsewhere in the document.",
142
+ "type": "object",
143
+ "required": ["contradicts-plan"],
144
+ "properties": { "contradicts-plan": { "const": true } }
145
+ },
146
+ "then": {
147
+ "type": "object",
148
+ "required": ["stopped-and-reported"],
149
+ "properties": {
150
+ "stopped-and-reported": { "type": "string", "minLength": 1, "pattern": "\\S" }
151
+ }
152
+ },
153
+ "oneOf": [
154
+ {
155
+ "$comment": "THE `contradicts-plan: true` BRANCH, which adds nothing: the escalation obligation is the `if`/`then` above and is deliberately left there rather than moved, so every witness registered against it keeps naming the keyword that does the work. This branch exists to make the two branches disjoint. Its own `required` is what makes an ABSENT `contradicts-plan` fall to the branch below instead of matching both, which is why the two branches are not symmetric.",
156
+ "type": "object",
157
+ "required": ["contradicts-plan"],
158
+ "properties": { "contradicts-plan": { "const": true } }
159
+ },
160
+ {
161
+ "$comment": "M3-P4 FIX ROUND 3, FINDING DV-002. Round 2 wrote that this site was `Unreachable by keyword or check` and the round-2 delta verifier REFUTED THAT BY BUILDING THE THING, using this phase's own remedy one definition over. The correction matters more than the fix: the argument round 2 gave for the whole class was that each open site `compares a document to something that is not in any document`, and that is FALSE HERE. `finding` is prose recorded verbatim (R-035) and it is IN THIS DOCUMENT, so the branch is content-discriminated in exactly the sense this phase's own converse table defines, and the negative-lookahead `pattern` that narrowed `#/$defs/claim`'s `open-question` statement narrows it too. WHAT IT REFUSES: a finding whose own prose names a divergence FROM THE PLAN while the boolean beside it says there is none, by eight tokens (`contradict* the plan`, `contrary to the plan`, `conflict* with the plan`, `diverg* from the plan`, `deviat* from the plan`, `at odds with the plan`, `inconsistent with the plan`, `the plan is wrong`), each written case-insensitively for the same reason as report.schema.json's `$defs/universalQuantifier`. EVERY TOKEN NAMES THE PLAN, and that is the whole design: a bare `contradicts` would refuse `the two schema comments contradict each other`, and `the plan requires` would refuse `the plan requires a deviations section and the M2 schemas already model one`, both of which are honest findings that do not contradict anything. Pricing those out is this phase's own worst hazard and the reason the token list is narrow rather than long. THE SENTENCE THAT USED TO STAND HERE, `EVERY TOKEN NAMES THE PLAN, AND THAT IS THE WHOLE DESIGN`, WAS THE ROUND-3 DEFECT AND IS CORRECTED RATHER THAN DELETED: naming the plan is what an ASSERTION of divergence and a DENIAL of one have in common, so the tokens caught both, and the denial is the plainest sentence a `contradicts-plan: false` record carries. Round 4 derived four of them against the shipped template and recorded their exit codes in delivery/work-history/m3-p4.md (finding DV3-002); `This does not contradict the plan; I checked section 2.3 first` is the first. R-035 records the finding VERBATIM, so rewording it was never available and the record was unwritable rather than merely awkward. THE BRANCH BELOW IS THE REPAIR: prose carrying a token is still writable, with the author declaring in `plan-language-note` why the sentence is not the assertion the token looks like. A LIST OF PERMITTED NEGATIONS WAS CONSIDERED AND REFUSED, because English negates, quotes and hedges these eight tokens in open-endedly many ways and any such list would be the same underived universal one level up, which is the mechanism the round-3 arbitration ruled on. RESIDUE, STATED RATHER THAN LEFT TO BE FOUND: neutral prose over a real contradiction still passes, exactly as `$defs/universalQuantifier` still passes an unlisted universal; `the plans` in the plural escapes the word boundary; a token split across a line break escapes the literal space, which is a residue this pattern SHARES with the two shipped patterns in report.schema.json rather than one it introduces; and nothing here can tell a true `plan-language-note` from a false one. The pattern narrows the escape; it does not seal it, and I did not find a way to make the marker TRUE by schema alone here. What checks the answer against the world is M3-P7's clean-room checklist.",
162
+ "type": "object",
163
+ "properties": {
164
+ "contradicts-plan": { "const": false },
165
+ "finding": {
166
+ "type": "string",
167
+ "pattern": "^(?:(?!\\b([Cc][Oo][Nn][Tt][Rr][Aa][Dd][Ii][Cc][Tt][A-Za-z]* [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Cc][Oo][Nn][Tt][Rr][Aa][Rr][Yy] [Tt][Oo] [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Cc][Oo][Nn][Ff][Ll][Ii][Cc][Tt][A-Za-z]* [Ww][Ii][Tt][Hh] [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Dd][Ii][Vv][Ee][Rr][Gg][A-Za-z]* [Ff][Rr][Oo][Mm] [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Dd][Ee][Vv][Ii][Aa][Tt][A-Za-z]* [Ff][Rr][Oo][Mm] [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Aa][Tt] [Oo][Dd][Dd][Ss] [Ww][Ii][Tt][Hh] [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Ii][Nn][Cc][Oo][Nn][Ss][Ii][Ss][Tt][Ee][Nn][Tt] [Ww][Ii][Tt][Hh] [Tt][Hh][Ee] [Pp][Ll][Aa][Nn]|[Tt][Hh][Ee] [Pp][Ll][Aa][Nn] [Ii][Ss] [Ww][Rr][Oo][Nn][Gg])\\b)[\\s\\S])*$"
168
+ }
169
+ }
170
+ },
171
+ {
172
+ "$comment": "M3-P4 FIX ROUND 4, FINDING DV3-002. THE `contradicts-plan: false` RECORD WHOSE VERBATIM PROSE CARRIES ONE OF THE EIGHT TOKENS, WITH THE AUTHOR SAYING WHY IT IS NOT THE ASSERTION THE TOKEN LOOKS LIKE. The sibling branch above is unchanged and stays the cheap path: prose free of the tokens owes nothing. WHAT THIS BRANCH COSTS: one short string, where the sibling alone cost the author the record. CARRYING `plan-language-note` WITH TOKEN-FREE PROSE IS A REJECTION, by the exactly-one rule of `oneOf`, which is the same discipline `schemas/final-report.schema.json`'s `$defs/enumerableSection` applies to `none: true` over real entries: an exception marker declared where the exception does not apply is a misdeclaration. WHAT IT DOES NOT REACH, measured rather than argued: the note is prose, so the round wrote the assertion `This contradicts the plan section 2.3` beside the note `I say it does not` and measured exit 0, which is in delivery/work-history/m3-p4.md with the rest. This raises the price of the lie from zero to a sentence a reviewer reads; it does not detect the lie, and M3-P7's clean-room checklist is where it is detected.",
173
+ "type": "object",
174
+ "required": ["contradicts-plan", "plan-language-note"],
175
+ "properties": {
176
+ "contradicts-plan": { "const": false },
177
+ "plan-language-note": { "type": "string", "minLength": 1, "pattern": "\\S" }
178
+ }
179
+ }
180
+ ]
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://tiphys.dev/schemas/write-bypass.schema.json",
4
+ "title": "Tiphys write-bypass declaration",
5
+ "$comment": "Kernel plan M4, M4-P9 (delivery/plan/kernel-plan-m4.md:1501), discharging M4-D-26. THE DOCUMENT IS THE CURRENT STATE AND IS REWRITTEN IN PLACE; the append-only evidence log beside it is a separate file that NO DECISION EVER READS, which is constraint C-1 made structural rather than promised. Reading the bypass state from the tail of that log is exactly what C-1 forbids, and a schema cannot forbid it, so the split is enforced by the decision function having no log parameter at all (plugin/src/hooks/project-write-block.ts). WHAT THIS DOCUMENT DOES REACH is the hazard the plan names first: a bypass with no expiry, so that the first infrastructure hotfix disables the project-write block permanently. `expiresAt` is REQUIRED and is an ABSOLUTE INSTANT, never a duration, so a bypass that never expires is unrepresentable rather than discouraged. WHAT IT CANNOT REACH, each with its instrument: (a) whether the expiry is in the future, which is a comparison against a clock and belongs to the reader (decideWrite takes `now` as a parameter for exactly that reason); (b) whether the listed paths lie inside the declared project, which compares sibling fields and is Kind B; (c) whether the declaration was written by an orchestrator rather than by an agent, which no document can establish about itself.",
6
+ "description": "What the orchestrator writes to <fleet>/write-bypass.json to permit a named, time-boxed set of working-tree writes in one project clone that the project-write block would otherwise refuse. A bypass is a FIRST-CLASS DECLARED ACT: it names the project, lists the paths explicitly, gives a reason, and expires at an instant it states.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": [
10
+ "kind",
11
+ "contractVersion",
12
+ "project",
13
+ "paths",
14
+ "reason",
15
+ "expiresAt",
16
+ "declaredBy",
17
+ "declaredAt"
18
+ ],
19
+ "properties": {
20
+ "kind": {
21
+ "$comment": "The artifact type, so `tiphys validate --type auto` resolves this document without being told, and so the ONE row in src/commands/validate.ts's TYPE_TABLE serves the `--type` table and the auto resolver at once (M3R-001).",
22
+ "type": "string",
23
+ "const": "write-bypass"
24
+ },
25
+ "contractVersion": {
26
+ "$comment": "A closed set rather than a minimum, for the reason every other shipped schema records: the authoring vocabulary has no `minimum` keyword.",
27
+ "type": "string",
28
+ "enum": ["1"]
29
+ },
30
+ "project": {
31
+ "$comment": "The ABSOLUTE path of the one project working tree this declaration is about. One declaration, one project: a bypass covering several projects at once is the shape that quietly becomes permanent, because the reason that justified it for the first stops being read for the rest.",
32
+ "type": "string",
33
+ "minLength": 1,
34
+ "pattern": "^/"
35
+ },
36
+ "paths": {
37
+ "$comment": "THE EXPLICIT PATH LIST, and `minItems: 1` is what makes it explicit. An empty list would be a declaration that names a project and permits nothing, which reads as an off switch waiting for an edit. Each entry is absolute; the reader additionally requires each to lie inside `project`, which is a sibling-field comparison no keyword here reaches.",
38
+ "type": "array",
39
+ "minItems": 1,
40
+ "items": {
41
+ "type": "string",
42
+ "minLength": 1,
43
+ "pattern": "^/"
44
+ }
45
+ },
46
+ "reason": {
47
+ "$comment": "Why the hotfix could not go through the ordinary pipeline. Required because a bypass with no stated reason is indistinguishable, a week later, from a block that was simply switched off.",
48
+ "type": "string",
49
+ "minLength": 1,
50
+ "pattern": "\\S"
51
+ },
52
+ "expiresAt": {
53
+ "$comment": "THE ABSOLUTE EXPIRY INSTANT, and it is the single most load-bearing field in this document. The plan's hazard class opens with 'a bypass with no expiry, so the first hotfix disables the block permanently'; making this required is how that state stops being representable. It is an instant and never a duration, because a duration has to be added to something and the thing it would be added to is a clock this document has no way to read.",
54
+ "type": "string",
55
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]+)?Z$"
56
+ },
57
+ "declaredBy": {
58
+ "$comment": "Who declared it, verbatim. A bypass is an act by a role, and the evidence log records the writes it permitted; this is the only field that says who is answerable for them.",
59
+ "type": "string",
60
+ "minLength": 1,
61
+ "pattern": "\\S"
62
+ },
63
+ "declaredAt": {
64
+ "$comment": "When it was declared. Paired with `expiresAt` it gives the window a reviewer reads, and it is what every refusal names when the declaration did not apply.",
65
+ "type": "string",
66
+ "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}([.][0-9]+)?Z$"
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,54 @@
1
+ # A minimal Tiphys project charter that validates against
2
+ # schemas/charter.schema.json. Kernel plan M3, M3-P1 step 7.
3
+ kind: charter
4
+ identity:
5
+ name: example-service
6
+ repo: git@github.com:example/example-service.git
7
+ kernel-version-pin: 0.1.0
8
+ # The mode ids are assurance-modes.yaml's, and the charter schema's enum is
9
+ # held equal to them by the derived check charter-mode-enum-matches-modes.
10
+ # This template said `standard` until M3-P3, which is a value no mode
11
+ # definition has ever carried.
12
+ delivery-mode: full
13
+ assurance-tier: full
14
+ yolo-permissions:
15
+ enabled: false
16
+ scope: []
17
+ irreversible-decisions:
18
+ stack: Node 26, TypeScript, Postgres 16
19
+ language: TypeScript
20
+ framework: Fastify
21
+ core-data-model: >-
22
+ One tenant per organization; every row carries tenant_id and every query
23
+ is scoped by it.
24
+ tenancy: shared database, row-level tenant scoping
25
+ auth: OIDC through the organization's identity provider, no local passwords
26
+ deployment-topology: single region, one managed container service
27
+ product-intent: |
28
+ A service that ingests supplier catalogues, normalizes them, and exposes one
29
+ search endpoint. Success is that a buyer finds the right part in one query.
30
+ Not in scope: pricing, ordering, or anything that writes to a supplier.
31
+ constraints:
32
+ - No customer data leaves the region.
33
+ - The search endpoint answers in under 300ms at the 95th percentile.
34
+ escalation-contract:
35
+ # The two DEFAULT stop-for entries. The second one is what makes turning
36
+ # verification off an owner decision instead of an implementer's edit
37
+ # (delivery/verification/release-verification-interface.md section 4.1).
38
+ # This is a default that is SHIPPED, not a rule anyone is proved to obey.
39
+ stop-for:
40
+ - any irreversible choice the charter is silent on
41
+ - a change from a declared release verification to `none`
42
+ route: >-
43
+ The orchestrator raises a decision record and notifies the owner
44
+ asynchronously; work on the affected phase stops.
45
+ release-verification:
46
+ # RESERVED, NOT DESIGNED (DR-0014, D-M3-29). See the schema's $comment.
47
+ mode: reserved
48
+ note: >-
49
+ The real shape of this field is settled by the first real project charter
50
+ at M4's pilot. Until then a project declares reserved and says why.
51
+ retention:
52
+ work-history: delivery/work-history/
53
+ evidence: delivery/evidence/
54
+ tuition: delivery/tuition/