@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,138 @@
1
+ ---
2
+ role: investigator
3
+ lifetime: One mystery
4
+ sees:
5
+ - The codebase
6
+ - The symptom, in the words it was reported in
7
+ never:
8
+ - Fixes anything
9
+ - Rewrites the plan
10
+ - Declares a cause it did not reproduce without saying so
11
+ mandated-reading:
12
+ - roles/_shared-dispatch-contract.md
13
+ - schemas/report.schema.json
14
+ verifiers:
15
+ - citations
16
+ outputs:
17
+ - report
18
+ model-tier: strongest
19
+ clauses:
20
+ - R-004
21
+ - R-015a
22
+ - R-092
23
+ - R-010a
24
+ - incremental-output
25
+ - beacon-is-not-a-claim
26
+ ---
27
+
28
+ # Investigator
29
+
30
+ You have been given ONE mystery. You see the codebase and the symptom as it was
31
+ reported. You produce a root-cause verdict with evidence, and you change
32
+ nothing.
33
+
34
+ The reason this role exists as a separate dispatch, rather than as the first
35
+ half of the implementer's work, is that an agent which is about to fix
36
+ something reasons toward a fix. A verdict reached that way is fitted to the
37
+ remedy the agent already had in mind, and the measured cost of a wrong verdict
38
+ is a whole fix round aimed at the wrong mechanism.
39
+
40
+ Your output is a `report`, and the contract it must satisfy is written down in
41
+ `schemas/report.schema.json`, which is on your mandated reading. Read it BEFORE
42
+ you write, not after: it is the only place the shape of your own deliverable
43
+ exists, and the clauses below tell you what to think and not what fields to
44
+ fill. Two things in it are easy to meet late and expensive to meet late. It
45
+ requires `claims`, `deviations`, `honest-failures`, `environmental-claims` and
46
+ `gate-results` alongside your findings, which are records you can only make
47
+ while the work is happening. And it carries one conditional aimed at this role
48
+ by name: a report whose `role` is investigator AND which states a `verdict`
49
+ must also carry a `repro`. The moment you conclude, R-015a below is owed as a
50
+ field and not as good practice.
51
+
52
+ The finding set at `schemas/finding.schema.json` is NOT your contract, and it
53
+ is not on your reading list for that reason. It governs what an adversarial
54
+ plan review and a clean-room review produce. Your report carries a `findings`
55
+ array of its own, defined inside your own schema, and the two are different
56
+ shapes.
57
+
58
+ ## clause R-004: a root-cause verdict with evidence, and nothing fixed
59
+
60
+ Your output is a VERDICT: what the cause is, what it is not, and what each of
61
+ those rests on. It is not a patch, not a branch, and not a suggestion that the
62
+ next agent try something.
63
+
64
+ Fixing nothing is not modesty. It is what keeps the verdict falsifiable: an
65
+ investigation that also edited the code cannot say whether the symptom went
66
+ away because the cause was found or because something else moved. If you
67
+ believe you know the fix, write it down as a recommendation inside the report
68
+ and leave the tree unchanged.
69
+
70
+ A verdict states its own confidence in terms someone can check. "The importer
71
+ retries a 429 twice and then propagates" is a verdict. "The retry logic looks
72
+ wrong" is not; it names no mechanism, so nothing can be built on it and nothing
73
+ can refute it.
74
+
75
+ Name the MECHANISM, not the instance. "A FIFO at the beacon path hangs the
76
+ guard" is an instance. "Reading a path whose type has not been established" is
77
+ the mechanism, and it is the one that tells the next agent where else to look.
78
+ A verdict that names only the instance sends the fix round at one call site
79
+ when there were eleven.
80
+
81
+ ## clause R-015a: a runnable repro that is red on current code
82
+
83
+ Produce a RUNNABLE REPRO that is red against the current code. Not a
84
+ description of how to reproduce it, and not a passing test that documents the
85
+ present behaviour: a command someone else can run, which fails now, and which
86
+ would pass if the cause you named were removed.
87
+
88
+ An explanation without a repro is a hypothesis. It may be a good one, and this
89
+ process still does not accept it as a verdict, because the whole value of the
90
+ investigator's output is that the fix round can be measured against something.
91
+ A repro is what turns "we think it is X" into "here is the arm that is red".
92
+
93
+ The repro must be red against the DANGEROUS STATE and not merely against an
94
+ absent feature. A repro that exercises a path where the failure cannot occur is
95
+ green, looks like evidence, and is worthless. Say which state you drove the
96
+ system into and how you know it got there.
97
+
98
+ State what the repro does NOT cover. A repro whose scope is wrong returns a
99
+ clean result that is indistinguishable from an absence of the defect, and this
100
+ process has been bitten by that shape three times: a lock path probed that was
101
+ not the lock path in use; an inventory scoped to three directories while the
102
+ missed path sat at the root; a usage error read as a clean run.
103
+
104
+ ## clause R-092: reproduce before fixing, and if it will not reproduce, ship the harness and say so
105
+
106
+ Reproduce first. Do not reason your way to a cause and then look for the
107
+ evidence that agrees with it.
108
+
109
+ If it will NOT reproduce, that is a real and reportable outcome, and the way to
110
+ report it is to SHIP THE HARNESS and say so plainly. Hand over the scaffolding
111
+ you built, the exact commands, the states you drove the system into, and the
112
+ arms that stayed green. Then write the honest sentence: "I did not find a way
113
+ to force this arm." Do not write "this arm cannot be forced", which is a
114
+ different and much stronger claim, and one that stops the next reader from
115
+ trying.
116
+
117
+ The harness is the deliverable in that case. An investigation that failed to
118
+ reproduce and left nothing behind has spent the whole budget and returned
119
+ nothing; the same investigation that leaves a harness has bought the next agent
120
+ everything except the answer.
121
+
122
+ ## clause R-010a: every claim carries file:line evidence
123
+
124
+ Every claim in your report carries evidence a reader can resolve: a path with a
125
+ line number, a captured command with its exit code, a count, a URL. The
126
+ citation linter is the verifier attached to this role and it runs over what you
127
+ write, so an unresolvable citation is a red gate rather than a matter of taste.
128
+
129
+ The form that resolves is `path.ext:LINE`, in prose and outside backticks. A
130
+ bare path is not a citation, and a path inside backticks is deliberately
131
+ QUOTED: use that when you are naming a file you are not asserting exists at
132
+ that line, and know that it counts for nothing toward the evidence floor.
133
+
134
+ Evidence beats assertion everywhere. A claim with no verifiable artifact behind
135
+ it is treated as unknown, which is not the same as treated as false, and the
136
+ distinction is the reason to write down what you actually ran.
137
+
138
+ $include: _shared-dispatch-contract.md
@@ -0,0 +1,95 @@
1
+ ---
2
+ role: plan-writer
3
+ lifetime: One plan
4
+ sees:
5
+ - The input report
6
+ - The code
7
+ mandated-reading:
8
+ - roles/_shared-dispatch-contract.md
9
+ - schemas/plan.schema.json
10
+ - templates/plan.example.yaml
11
+ - gate-registry.yaml
12
+ never:
13
+ - Decides product questions
14
+ - Writes feature code
15
+ - Plans a phase on an unverified claim without marking it verification-first
16
+ verifiers:
17
+ - citations
18
+ outputs:
19
+ - plan
20
+ model-tier: strongest
21
+ clauses:
22
+ - R-005
23
+ - R-010a
24
+ - incremental-output
25
+ - beacon-is-not-a-claim
26
+ ---
27
+
28
+ # Plan writer
29
+
30
+ You have been given ONE plan to write. You see the input report and the code.
31
+ Your output is a plan instance that validates against
32
+ `schemas/plan.schema.json`, and the binding rule of that document applies to
33
+ everything downstream of you: if it is not written in the plan, it is not being
34
+ made.
35
+
36
+ That rule is what keeps ten agents from improvising, and it puts the whole
37
+ weight on you: an omission in the plan is not a gap someone fills in later, it
38
+ is work that does not happen. Write the phase you would want to be handed.
39
+
40
+ Every acceptance criterion is FALSIFIABLE. "Works correctly" is banned. The
41
+ register is "node --test exits 0 and reports N tests, N greater than zero", or
42
+ "this command exits 64 and prints this line to stderr". A criterion nobody can
43
+ fail is a criterion nobody has to meet.
44
+
45
+ ## clause R-005: never decide a product question, flag it
46
+
47
+ You do not decide product questions. When the input report leaves a choice that
48
+ is genuinely a choice, you FLAG it as a decision record and plan around the
49
+ flag rather than picking an answer and burying it in a step.
50
+
51
+ The test for whether something is a decision record is not "is it important".
52
+ It is: are two or more options genuinely comparable, AND is the consequence
53
+ high impact and costly to reverse. If your own analysis yields a recommendation
54
+ you would defend, the options are NOT comparable and there is nothing to ask.
55
+ Decide it, record the reasoning, and say what you decided. Write your
56
+ recommendation first; doing that is what reveals whether a question was ever a
57
+ question.
58
+
59
+ Raising a question whose answer was already obvious is a failure of the system
60
+ and not a display of care, because it spends the owner's attention, which is
61
+ the scarcest thing in the process. Raising an irreversible choice you quietly
62
+ made is the worse failure, and it is the one this clause exists against.
63
+
64
+ A flagged question does not stall the plan. The phase is planned around the
65
+ fill-in: the acceptance criteria, the tests and the gates are fixed regardless
66
+ of which way the question resolves, and the slot that depends on the answer is
67
+ declared as a slot.
68
+
69
+ ## clause R-010a: verify every input claim against the code before planning a phase
70
+
71
+ Before a single phase is planned, every claim in the input report gets a
72
+ CODE-LEVEL VERIFICATION PASS, each claim checked against actual file:line
73
+ evidence. The output is the section where the report and the code disagree,
74
+ and it is the most load-bearing part of the plan.
75
+
76
+ This is not a formality. In one measured run, five of eleven report assessments
77
+ did not survive contact with the code: features declared missing that had
78
+ shipped, display bugs that were schema-level projects, one-line bugs hiding
79
+ under grand theories. A plan built on the unverified report would have spent
80
+ five phases on work that did not exist.
81
+
82
+ A claim that FAILS verification does not get dropped and does not get believed.
83
+ It becomes a VERIFICATION-FIRST STEP: the owning phase's step 1 is "confirm
84
+ which of these failures this actually is, write it down, and only then build".
85
+ The plan schema carries that as a step kind, and a derived check requires the
86
+ step to exist in the phase the unverified claim names, so an unverified claim
87
+ with no verification-first step makes the plan invalid rather than making it
88
+ optimistic.
89
+
90
+ Citations resolve or they are not citations. The form is `path.ext:LINE`, in
91
+ prose and outside backticks; a bare path is not a citation and a path inside
92
+ backticks is quoted rather than asserted. The citation linter is the verifier
93
+ attached to this role.
94
+
95
+ $include: _shared-dispatch-contract.md
@@ -0,0 +1,82 @@
1
+ # Tiphys artifact schemas
2
+
3
+ Every kernel artifact type that is validated has one JSON Schema document
4
+ here. `tiphys validate --type <t> <file>` resolves a type to a document in
5
+ this directory; `--type auto` resolves it from the instance's `kind` field.
6
+
7
+ ## The dialect, and why it is declared in every file
8
+
9
+ Every document declares
10
+
11
+ ```
12
+ "$schema": "https://json-schema.org/draft/2020-12/schema"
13
+ ```
14
+
15
+ DR-0013 clause 3. It is asserted by a registered test over EVERY file in this
16
+ directory (`test/schemas.test.ts`, behavior `schemas-declare-2020-12-dialect`)
17
+ rather than by inspection, so a schema a later phase adds without the
18
+ declaration fails a gate rather than a reading.
19
+
20
+ ## The engine
21
+
22
+ Ajv 8.20.0 exact, Draft 2020-12, instantiated in `src/validate.ts` with strict
23
+ mode, all errors, schema and meta-schema validation, and no coercion, no
24
+ inserted defaults, no removal of additional properties, no mutation of the
25
+ validated input and no automatic loading of remote schemas (DR-0013 clause 4).
26
+ Unknown or invalidly combined keywords fail schema COMPILATION.
27
+
28
+ Ajv is an INTERNAL IMPLEMENTATION DETAIL. Its wording is never a public
29
+ contract: every error is mapped, by keyword, into
30
+ `INVALID <json-pointer> <message>` with a deterministic order.
31
+
32
+ ## The declared authoring vocabulary (DR-0013 clause 7)
33
+
34
+ Ajv supplies Draft 2020-12 entire. This list is what a Tiphys schema is
35
+ allowed to USE, so a keyword outside it is a deliberate, documented expansion
36
+ rather than an accident. Every keyword here has both a positive and a negative
37
+ test (`test/schemas.test.ts`).
38
+
39
+ | Keyword | Note |
40
+ |---|---|
41
+ | `type` | one type name per node |
42
+ | `required` | strict mode requires every named property to be declared in `properties` at the same level |
43
+ | `properties` | |
44
+ | `additionalProperties` | boolean only, and set to `false` at EVERY object level |
45
+ | `enum` | |
46
+ | `const` | |
47
+ | `items` | |
48
+ | `minItems` | |
49
+ | `uniqueItems` | boolean only; used by five shipped schemas here and MISSING FROM THIS TABLE from the day M3-P1 wrote both halves until the DR-0047 sweep, because nothing asserted the two agreed |
50
+ | `minLength` | |
51
+ | `pattern` | |
52
+ | `$ref` | local references only; a remote reference fails compilation |
53
+ | `oneOf` | |
54
+ | `if` / `then` | |
55
+ | `contains` | in the vocabulary and used by no document shipped in M3-P1; its positive, negative and discriminating tests run against a fixture schema in `test/fixtures/` |
56
+
57
+ Annotations that carry no constraint and are permitted anywhere: `$schema`,
58
+ `$id`, `$comment`, `title`, `description`, `$defs`.
59
+
60
+ Expanding this list is a deliberate act and is recorded here, per DR-0013
61
+ clause 7. Prohibiting an otherwise-valid keyword is a POLICY LINTER, never a
62
+ reimplementation of keyword semantics; `src/gates/validate.ts`'s `loadSchema`
63
+ is the one that exists today, and it enforces M2's narrower closed set over
64
+ the M2 gate schemas only.
65
+
66
+ ## Kind A and Kind B
67
+
68
+ A schema expresses properties of ONE document that a keyword reaches (Kind A).
69
+ Properties that compare array elements to each other, resolve a reference into
70
+ another document, compute arithmetic over sibling fields or touch the
71
+ filesystem are Kind B and live in `src/checks.ts` as named derived checks
72
+ (kernel plan M3 section 2.3, DR-0013 clause 8). They are never encoded as Ajv
73
+ extensions.
74
+
75
+ ## `$comment` carries clause ids
76
+
77
+ Every requirement row an artifact discharges appears in that artifact as a
78
+ clause id, here as a `$comment` tag or a property name.
79
+ `scripts/check-clause-map.mjs` fails when a row owned by a phase that is in
80
+ force has no entry, when an entry names a row the plan's inventory does not
81
+ contain, when a named artifact does not exist, or when the clause id does not
82
+ occur inside it.
@@ -0,0 +1,264 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://tiphys.dev/schemas/assurance-modes.schema.json",
4
+ "title": "Tiphys assurance modes",
5
+ "$comment": "R-024, R-096. Blueprint section 8 fixes three modes and their merge authority; this document is the machine-readable form of that table plus the pipeline the process document actually runs. Kernel plan M3, M3-P3 step 1. WHAT THIS SCHEMA CANNOT SEE, said here rather than left to be discovered: a mode that omits a stage `full` contains while declaring nothing in `skips[]` is a CROSS-OBJECT comparison, and the relative position of two entries in a variable-length array is not a keyword property (M3R-002). Those are Kind B and live in src/checks.ts as `mode-no-undeclared-downgrade` and `mode-stage-order`; the gate-set references and the charter enum are Kind B too, as `mode-gate-sets-resolve` and `charter-mode-enum-matches-modes`. This schema's own share is field presence, item type and the closed vocabularies.",
6
+ "description": "One document per repository. Which assurance modes exist, which pipeline stages each runs, which gates it selects from gate-registry.yaml, who may merge under it, and which stages it declares itself to skip.",
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "required": ["kind", "version", "modes"],
10
+ "properties": {
11
+ "kind": {
12
+ "description": "The artifact type, so `tiphys validate --type auto` resolves this document without being told.",
13
+ "type": "string",
14
+ "const": "assurance-modes"
15
+ },
16
+ "note": {
17
+ "description": "Free prose for this document's own readers.",
18
+ "type": "string"
19
+ },
20
+ "version": {
21
+ "$comment": "A closed set rather than a minimum, because the authoring vocabulary of schemas/README.md has no `minimum` keyword and a bare `type: integer` would admit 0 and negatives. Same shape as gate-registry.schema.json.",
22
+ "type": "integer",
23
+ "enum": [1]
24
+ },
25
+ "modes": {
26
+ "description": "Every mode this repository declares. Append-only in practice: adding one is what makes charter-mode-enum-matches-modes earn its place.",
27
+ "type": "array",
28
+ "minItems": 1,
29
+ "uniqueItems": true,
30
+ "items": {
31
+ "$ref": "#/$defs/mode"
32
+ }
33
+ }
34
+ },
35
+ "$defs": {
36
+ "stageId": {
37
+ "$comment": "THE CLOSED STAGE VOCABULARY. The first twelve are `full`'s pipeline, which is the process document's own sequence enumerated (process doc section 9 item 3, R-096), with `fix-round-verification` present because T-003 made it structural rather than discretionary. `orchestrator-diff-review` is the thirteenth and belongs to local-only alone: blueprint section 8 names it in that row (\"implement, orchestrator diff review, local fast-forward\") and a vocabulary without it would force local-only to be described as something it is not. CONSTRAINTS C-2 AND C-3 BIND THIS LIST: no stage is completed, detected or excluded by process liveness, by a signal, or by a detached long-running process. A registered test scans this file and assurance-modes.yaml for the four tokens C-2 and C-3 are written in and requires ZERO hits, which is why those four tokens do not appear here even as a disclaimer (M3-P3 criterion 5). It is a fixed-token presence check and is not stronger than that: a stage whose completion were liveness-detected WITHOUT using any of the four words would pass it, which the plan's hazard map states in the open rather than papering over. CLOSED VOCABULARY AT v0.1.0 (DR-0020): these are the tiphys kernel's OWN stage ids. This enum rejects every other value, so a consuming project cannot name a stage of its own at v0.1.0. Extension is an M4 question, deferred to a real pilot consumer for the same reversibility reason as the mode-id enum.",
38
+ "type": "string",
39
+ "enum": [
40
+ "intake",
41
+ "verification-pass",
42
+ "plan",
43
+ "adversarial-plan-review",
44
+ "implement",
45
+ "clean-room-review",
46
+ "fix-round",
47
+ "fix-round-verification",
48
+ "merge-on-green",
49
+ "orchestrator-diff-review",
50
+ "deploy-verify",
51
+ "migration-verify",
52
+ "final-report"
53
+ ]
54
+ },
55
+ "mode": {
56
+ "$comment": "FOUR conditional rules, chained through $ref rather than stacked in one object, because JSON Schema allows one `if`/`then` pair per schema object and `allOf` is outside the authoring vocabulary of schemas/README.md. Same construction as gate-registry.schema.json's `gate`. This link is M3-P3 criterion 3(c) and criterion 4c: `full` is the reference pipeline every other mode is measured against, so it must CONTAIN the fix-round verification stage T-003 made structural, and it must carry the stop-rather-than-grind bound rather than leaving it in an orchestrator's discipline (blueprint principle 6 calls prompt-only state temporary).",
57
+ "$ref": "#/$defs/modeAuthorityRule",
58
+ "if": {
59
+ "type": "object",
60
+ "required": ["id"],
61
+ "properties": {
62
+ "id": {
63
+ "const": "full"
64
+ }
65
+ }
66
+ },
67
+ "then": {
68
+ "type": "object",
69
+ "required": ["pipeline", "escalation-bounds"],
70
+ "properties": {
71
+ "pipeline": {
72
+ "type": "array",
73
+ "contains": {
74
+ "const": "fix-round-verification"
75
+ }
76
+ },
77
+ "escalation-bounds": {
78
+ "$ref": "#/$defs/escalationBounds"
79
+ }
80
+ }
81
+ }
82
+ },
83
+ "modeAuthorityRule": {
84
+ "$comment": "M3-P3 criterion 4b. `delegated-under-conditions` is the regime the owner has actually granted once, in DR-0012, and a grant with no conditions and no record reference is an authority downgrade with nothing behind it: exactly the improvisation blueprint section 8 forbids, applied to who may merge rather than to which stages run. `conditions` is minItems 1 so an EMPTY list is a rejection, not a technicality.",
85
+ "$ref": "#/$defs/modeReviewContractRule",
86
+ "if": {
87
+ "type": "object",
88
+ "required": ["merge-authority"],
89
+ "properties": {
90
+ "merge-authority": {
91
+ "const": "delegated-under-conditions"
92
+ }
93
+ }
94
+ },
95
+ "then": {
96
+ "type": "object",
97
+ "required": ["conditions", "granted-by"],
98
+ "properties": {
99
+ "conditions": {
100
+ "type": "array",
101
+ "minItems": 1,
102
+ "items": {
103
+ "type": "string",
104
+ "minLength": 1
105
+ }
106
+ },
107
+ "granted-by": {
108
+ "$ref": "#/$defs/decisionRecordReference"
109
+ }
110
+ }
111
+ }
112
+ },
113
+ "modeReviewContractRule": {
114
+ "$comment": "M3-P3 criterion 4d (T-007, D-M3-32). A mode that runs clean-room review declares its review CONTRACTS, not a reviewer count. T-007's measurement is why this is a schema rule: two reviewers on different model families walked all fifteen of M1-P5's acceptance criteria, agreed on every mechanical fact, and one returned APPROVE while the other found a high-severity defect that live-locks four commands, because the second was briefed on hazards rather than on criteria. Had both been briefed on the criteria, both would have approved, on any two models. The `uniqueItems` on modeShape's `review-contracts` is what stops two entries both named `criteria` from satisfying this `minItems` and reproducing exactly that failure; the two keywords live at ONE SITE EACH, because a duplicate of either would keep rejecting after the other was defanged and a red witness that stayed red for the wrong reason proves nothing about the keyword it names. DR-0012's requirement of two model FAMILIES is orthogonal and is checked elsewhere.",
115
+ "$ref": "#/$defs/modeShape",
116
+ "if": {
117
+ "type": "object",
118
+ "required": ["pipeline"],
119
+ "properties": {
120
+ "pipeline": {
121
+ "type": "array",
122
+ "contains": {
123
+ "const": "clean-room-review"
124
+ }
125
+ }
126
+ }
127
+ },
128
+ "then": {
129
+ "type": "object",
130
+ "required": ["review-contracts"],
131
+ "properties": {
132
+ "review-contracts": {
133
+ "type": "array",
134
+ "minItems": 2,
135
+ "items": {
136
+ "type": "string",
137
+ "minLength": 1
138
+ }
139
+ }
140
+ }
141
+ }
142
+ },
143
+ "modeShape": {
144
+ "type": "object",
145
+ "additionalProperties": false,
146
+ "required": [
147
+ "id",
148
+ "declared-by",
149
+ "pipeline",
150
+ "skips",
151
+ "gate-sets",
152
+ "merge-authority"
153
+ ],
154
+ "properties": {
155
+ "$comment": {
156
+ "description": "Clause ids this entry discharges, per schemas/README.md.",
157
+ "type": "string"
158
+ },
159
+ "id": {
160
+ "$comment": "The three ids of blueprint section 8. Closed here and closed again in gate-registry.schema.json's `modes` item enum and in schemas/charter.schema.json's `delivery-mode` enum, which is three copies of one list; `charter-mode-enum-matches-modes` is what keeps the charter copy honest, and test/gate-registry.test.ts already binds the registry copy. CLOSED VOCABULARY AT v0.1.0 (DR-0020): these three are the tiphys kernel's OWN mode ids. This enum rejects every other value, so a consuming project cannot declare a mode of its own name at v0.1.0. Whether to open it, and to what, is an M4 question to be answered by a real pilot consumer rather than guessed; widening an enum later is backward compatible and closing an open one is not, which is why it ships closed.",
161
+ "type": "string",
162
+ "enum": ["full", "direct-pr", "local-only"]
163
+ },
164
+ "declared-by": {
165
+ "description": "Where this mode's definition comes from. Prose with document references, so a reader can check the mode against its source rather than trusting it.",
166
+ "type": "string",
167
+ "minLength": 1
168
+ },
169
+ "pipeline": {
170
+ "description": "The stages this mode runs, IN ORDER. Order is load-bearing: R-024 says an adversarial plan review happens before anyone builds, and that is a property of the sequence, not of the set.",
171
+ "type": "array",
172
+ "minItems": 1,
173
+ "uniqueItems": true,
174
+ "items": {
175
+ "$ref": "#/$defs/stageId"
176
+ }
177
+ },
178
+ "skips": {
179
+ "$comment": "Blueprint section 8: \"Downgrades are declared, never improvised.\" This is the declaration. It is REQUIRED and may be empty, so a mode that omits a stage and says nothing is distinguishable from a mode that omits nothing; `mode-no-undeclared-downgrade` is what makes the difference cost something. THE CHECK RUNS IN THREE PARTS AND THE SCHEMA CAN SEE NONE OF THEM: an omitted stage missing from this list is a violation (completeness); an entry in this list that the SAME mode's `pipeline` still runs is a violation (soundness A); and an entry that the REFERENCE mode `full` does not run either is a violation too (soundness B), because this list is defined relative to `full`'s pipeline and not to the mode's own. All three are cross-property comparisons and none is a keyword property, and soundness B is a comparison against a DIFFERENT object in the same document, which is further outside the vocabulary still. Soundness A was added after a review measured that a list constrained in one direction only is not constrained at all: one bogus entry on `full` validated at exit 0 and made `tiphys mode show` state the opposite of the truth about this project's own delivery. Soundness B was added a round later, when a delta verification measured that the round adding A had written THIS SENTENCE claiming both directions were covered while an entry naming a stage nothing runs still validated at exit 0. On `full` A and B together force this list to be EMPTY, which is what lets `tiphys mode show` call `full` the un-downgraded process by name.",
180
+ "type": "array",
181
+ "uniqueItems": true,
182
+ "items": {
183
+ "$ref": "#/$defs/stageId"
184
+ }
185
+ },
186
+ "gate-sets": {
187
+ "$comment": "The gate ids from gate-registry.yaml this mode selects. `set` is the blueprint's word for the per-mode gate selection; here it is enumerated by id rather than named indirectly, so `mode-gate-sets-resolve` can check each entry against the registry with --context and a reference that resolves to nothing cannot pass by never being looked up.",
188
+ "type": "array",
189
+ "minItems": 1,
190
+ "uniqueItems": true,
191
+ "items": {
192
+ "type": "string",
193
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
194
+ }
195
+ },
196
+ "merge-authority": {
197
+ "$comment": "Blueprint section 8's third column, plus the value the owner has actually granted. `owner-approves-orchestrator-merges` is SC-008 and plan v1 D-6's reading of blueprint section 8's local-only row. IT DESCRIBES A REGIME THIS PROJECT HAS LEFT (DR-0015, 2026-08-05): for the Tiphys kernel the owner is not an approval step anywhere in execution, milestone boundaries included, and dual cross-model clean review is the signature. The value is kept representable rather than deleted because a future project may declare any of the three and the kernel is not the place to make another project's governance unrepresentable.",
198
+ "type": "string",
199
+ "enum": [
200
+ "owner",
201
+ "owner-approves-orchestrator-merges",
202
+ "delegated-under-conditions"
203
+ ]
204
+ },
205
+ "conditions": {
206
+ "$comment": "Required, and required to be NON-EMPTY, when merge-authority is delegated-under-conditions. The `minItems` lives in modeAuthorityRule's `then` and NOWHERE ELSE: a second copy here would keep rejecting an empty list after the conditional rule was defanged, which would make the conditional rule's witness green for the wrong reason and hide a rule that had stopped working. Quoted from the decision record rather than summarized.",
207
+ "type": "array",
208
+ "items": {
209
+ "type": "string",
210
+ "minLength": 1
211
+ }
212
+ },
213
+ "granted-by": {
214
+ "$ref": "#/$defs/decisionRecordReference"
215
+ },
216
+ "review-contracts": {
217
+ "$comment": "T-007, D-M3-32. The STARTING QUESTION each clean-room review is given, by id. Two contracts is not two reviewers: `criteria` walks the phase's acceptance criteria and `hazard` is handed the phase's declared hazard classes and works outward from them.",
218
+ "type": "array",
219
+ "uniqueItems": true,
220
+ "items": {
221
+ "type": "string",
222
+ "minLength": 1
223
+ }
224
+ },
225
+ "escalation-bounds": {
226
+ "$ref": "#/$defs/escalationBounds"
227
+ }
228
+ }
229
+ },
230
+ "decisionRecordReference": {
231
+ "description": "A decision record id, for example DR-0012. The record itself lives in the project's decisions directory; this is the reference that makes a grant checkable against it.",
232
+ "type": "string",
233
+ "pattern": "^DR-[0-9]{4}$"
234
+ },
235
+ "onExceeded": {
236
+ "$comment": "DR-0016. `fresh-implementer-and-third-contract` is the response that was measured to work: a fresh implementer plus a third review contract dispatched IMMEDIATELY, with the owner notified asynchronously. `escalate-to-owner` remains in the enum because DR-0016's residual guardrail is real: if the round after the fresh implementer also fails, the phase goes to the owner.",
237
+ "type": "string",
238
+ "enum": ["fresh-implementer-and-third-contract", "escalate-to-owner"]
239
+ },
240
+ "escalationBounds": {
241
+ "$comment": "DR-0012's stop-rather-than-grind limits, made data, plus DR-0016's response. THIS IS DATA THE ORCHESTRATOR BRIEF CITES (M3-P9), NOT AN ENFORCEMENT ENGINE: nothing in M3 counts fix rounds and nothing in M3 classifies a finding's component, and the plan's section 4.5 records that as unproven rather than implying otherwise. `on-exceeded` is in this object's OWN `required` list, which is what makes it required exactly when `escalation-bounds` is present, with no conditional rule to go vacuous. A bound that records the LIMIT but not the RESPONSE encodes the regime DR-0016 measured and replaced: DR-0012's bound was a stop-and-wait, that stop cost 4.7 hours on M1-P5 alone, it fired three times, all three times the owner chose the option the orchestrator had already recommended, and the intervention that actually broke the spiral was the FRESH IMPLEMENTER dispatched afterwards, which derived eleven call sites where the review had listed eight.",
242
+ "type": "object",
243
+ "additionalProperties": false,
244
+ "required": [
245
+ "max-fix-rounds-after-review",
246
+ "recurrence-of-high-in-one-component",
247
+ "on-exceeded"
248
+ ],
249
+ "properties": {
250
+ "max-fix-rounds-after-review": {
251
+ "description": "How many fix rounds may follow the first dual review before the bound fires. DR-0012 set two; DR-0035 replaced the single bound with a table running from one round (a zero or small subject) to three (a large subject at high impact), so what a mode records here is that table's CEILING rather than one phase's budget.",
252
+ "type": "integer"
253
+ },
254
+ "recurrence-of-high-in-one-component": {
255
+ "description": "How many times a high-severity finding may recur in one component across rounds before the bound fires. DR-0012 treats any recurrence as the trigger, so one.",
256
+ "type": "integer"
257
+ },
258
+ "on-exceeded": {
259
+ "$ref": "#/$defs/onExceeded"
260
+ }
261
+ }
262
+ }
263
+ }
264
+ }