@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,461 @@
1
+ /**
2
+ * ROLE BRIEFS: frontmatter, the shared clause include, the clause round trip,
3
+ * and the phase projection `tiphys brief compose` emits (kernel plan M3,
4
+ * M3-P5 step 6).
5
+ *
6
+ * A role brief is markdown with YAML frontmatter, which section 1.5 of the
7
+ * plan grants as a JUSTIFIED EXCEPTION to the structured-artifact rule: a
8
+ * brief's effect comes from argument, ordering and emphasis, and splitting it
9
+ * into fields produces either one giant string or a set of fragments no agent
10
+ * reads as an argument. The frontmatter carries everything enumerable and is
11
+ * schema-validated; this module is what makes the BODY checkable in the one
12
+ * respect a machine can reach.
13
+ *
14
+ * THREE MECHANISMS LIVE HERE AND THEY ARE DELIBERATELY SEPARATE.
15
+ *
16
+ * 1. Frontmatter split. A brief is decoded before it is validated, exactly
17
+ * as `tiphys validate` decodes before it validates: a malformed
18
+ * frontmatter block names the decode, a failing contract names the
19
+ * pointer, and neither produces a stack trace.
20
+ * 2. The include. `$include: <name>` on a line of its own is resolved
21
+ * against the brief's own directory. It exists because M3-P5's three
22
+ * briefs and M3-P6's two carry the SAME dispatch-contract clause text,
23
+ * and five independently editable copies of a rule drift into five
24
+ * different rules. There is one copy, `roles/_shared-dispatch-contract.md`.
25
+ * 3. The clause round trip. Every id in `clauses[]` occurs exactly once as a
26
+ * body heading anchor of the include-expanded body, and every anchor
27
+ * occurs in `clauses[]`. This is what stops a clause id being a label
28
+ * with nothing behind it, which would make the clause map a rubber stamp.
29
+ * It proves PRESENCE and never content: whether the text under a heading
30
+ * says the opposite of the row it discharges is judgment, and the phase's
31
+ * own hazard-class table records that no criterion reaches it.
32
+ *
33
+ * D-M3-27 BINDS EVERY PATH THIS MODULE TOUCHES. Composition's whole job is
34
+ * resolving and reading paths it did not create, so every one of them goes
35
+ * through `classifyEntry` and `refuseOpenForWrite` in src/task.ts. A named
36
+ * pipe at a mandated-reading path is a reported refusal naming the path and
37
+ * the observed entry type, never a blocked open. This module adds no bare
38
+ * `readFileSync` and does not patch `src/brief.ts`, which is M1-P4's and
39
+ * carries its own open instance of that class.
40
+ */
41
+ import type { Diagnostic } from "./validate.ts";
42
+ /**
43
+ * The six roles of blueprint section 6 and of the process document's role
44
+ * table. Identical to `schemas/role-brief.schema.json`'s `role` enum and to
45
+ * `role-model-config.yaml`'s `role` values; test/roles.test.ts asserts the
46
+ * three agree rather than trusting this comment.
47
+ */
48
+ export declare const ROLE_IDS: readonly string[];
49
+ /**
50
+ * WHERE EACH ROLE'S BRIEF ACTUALLY SHIPS, relative to the kernel root.
51
+ *
52
+ * The vocabulary above has six members and `roles/` holds FIVE briefs. The
53
+ * sixth, the orchestrator's, ships as `AGENTS.md` at the package root, with
54
+ * `role: orchestrator` frontmatter, which roles/README.md states and
55
+ * package.json's `files` list carries. Until this constant existed, the
56
+ * composer resolved every id to `roles/<id>.md`, so
57
+ * `tiphys brief compose --role orchestrator` answered, against the PUBLISHED
58
+ * TARBALL, "role brief .../roles/orchestrator.md: ... does not exist" for a
59
+ * brief that is in the same tarball at a path the resolver never looked in.
60
+ * A consumer reads that as a broken install.
61
+ *
62
+ * This is a composition defect no per-phase review could have caught: M3-P5
63
+ * built the six-member resolver over `roles/<id>.md`, M3-P6 added files to
64
+ * that directory, and M3-P9 put the sixth brief somewhere else. Each is
65
+ * correct alone.
66
+ *
67
+ * DECLARED RATHER THAN DERIVED ON PURPOSE. A resolver that fell back to
68
+ * "look for <id>.md anywhere" would answer for a file that happened to be
69
+ * there, and the property wanted is the opposite: the package states where
70
+ * each declared role's brief IS, and test/sweep-exclusion-sync.test.ts turns
71
+ * a role added without one into a red test rather than a failure at use.
72
+ */
73
+ export declare const ROLE_BRIEF_FILES: Readonly<Record<string, string>>;
74
+ /**
75
+ * The brief path for a role, relative to the kernel root, or undefined when
76
+ * the vocabulary declares a role the package does not ship. The second case
77
+ * is a REFUSAL the caller names, never a path that is then found missing.
78
+ */
79
+ export declare function roleBriefFile(roleId: string): string | undefined;
80
+ /** The fence a role brief's YAML frontmatter block is delimited by. */
81
+ export declare const FRONTMATTER_FENCE = "---";
82
+ /** The include directive, on a line of its own. */
83
+ export declare const INCLUDE_PATTERN: RegExp;
84
+ /**
85
+ * A body heading anchor: `## clause <id>` with an optional `: title`.
86
+ *
87
+ * DELIBERATELY EXPLICIT. An anchor form that guessed (say, "a heading whose
88
+ * text looks like an identifier") would classify ordinary headings such as
89
+ * `## Scope` as anchors and redden every brief that has one. The word
90
+ * `clause` is the marker, and a heading without it is prose.
91
+ */
92
+ export declare const CLAUSE_ANCHOR_PATTERN: RegExp;
93
+ export type RoleBriefSplit = {
94
+ ok: true;
95
+ frontmatter: string;
96
+ body: string;
97
+ } | {
98
+ ok: false;
99
+ reason: string;
100
+ };
101
+ /**
102
+ * Split a role brief into its frontmatter text and its body.
103
+ *
104
+ * The document must OPEN with the fence. A markdown file with a `---` rule
105
+ * somewhere in the middle is not a role brief with frontmatter, and reading
106
+ * it as one is how a horizontal rule becomes a contract.
107
+ */
108
+ export declare function splitFrontmatter(text: string, label: string): RoleBriefSplit;
109
+ export type IncludeExpansion = {
110
+ ok: true;
111
+ text: string;
112
+ included: string[];
113
+ } | {
114
+ ok: false;
115
+ reason: string;
116
+ };
117
+ /**
118
+ * Resolve every `$include:` directive in a body against `baseDirectory`.
119
+ *
120
+ * ONE LEVEL, NOT RECURSIVE, and that is a decision rather than an omission: a
121
+ * nested include is a second place the shared text could come from, and the
122
+ * whole point of the shared block is that there is exactly one. An include
123
+ * inside an included file is refused by name.
124
+ */
125
+ export declare function expandIncludes(body: string, baseDirectory: string, label: string): IncludeExpansion;
126
+ /** Every clause anchor in a body, in the order they occur, duplicates kept. */
127
+ export declare function clauseAnchors(body: string): string[];
128
+ /**
129
+ * The round trip, in both directions, as diagnostics in the same
130
+ * `INVALID <pointer> <message>` contract the schema validator emits.
131
+ *
132
+ * A frontmatter clause with no anchor is ORPHANED: the id is declared, the
133
+ * clause map resolves it because the id occurs somewhere in the file, and
134
+ * there is no text behind it. A stray anchor is the mirror failure: text
135
+ * exists under a clause id nothing declared, so nothing tracks it.
136
+ */
137
+ export declare function clauseRoundTripDiagnostics(clauses: readonly string[], body: string): Diagnostic[];
138
+ /**
139
+ * THE OUTPUT CONTRACT CHECK (M3-P5 fix round 1, clean-room finding 1).
140
+ *
141
+ * Every artifact type a brief declares in `outputs[]` has a schema document
142
+ * that governs it, and the brief must put that document on its
143
+ * `mandated-reading` list. A brief that does not is a brief whose agent is
144
+ * never told where the shape of its own deliverable is written.
145
+ *
146
+ * THE MECHANISM, NOT THE INSTANCE. The instance found in review was
147
+ * `roles/investigator.md` declaring `outputs: [report]` while its reading list
148
+ * carried `schemas/finding.schema.json`, the contract of a DIFFERENT role's
149
+ * artifact. Repairing that one list leaves the method that produced it, and
150
+ * three correct lists that can drift are worth less than one check that cannot
151
+ * be forgotten. M3-P6 ships two more briefs; this runs on them the day they
152
+ * land, with nobody having to remember it.
153
+ *
154
+ * WHY A CHECK AND NOT A DERIVATION, which was the alternative considered.
155
+ * `resolveMandatedReading` could have INJECTED `schemas/<type>.schema.json`
156
+ * into the list from `outputs[]`, making the omission impossible rather than
157
+ * merely refused. Rejected, for three reasons that are properties of the
158
+ * artifact rather than preferences. (1) It would split the truth in two: the
159
+ * brief file on disk would say one thing and the composed brief another, so a
160
+ * reader of `roles/investigator.md` could no longer see what its agent reads,
161
+ * and `tiphys validate --type role-brief` (which reads the file) and
162
+ * `tiphys brief compose` (which would read the file plus an injection) would
163
+ * hold two different opinions about one property. (2) The list is ORDERED and
164
+ * the order is authored; an injected entry has no authored position, and
165
+ * criterion 3 asserts the composed output's ordering. (3) Injection makes the
166
+ * defect invisible instead of absent: the wrong entry that pointed the
167
+ * investigator at the wrong document would still be sitting on the list,
168
+ * silently, with the right one bolted on beside it. The check makes the author
169
+ * fix the file, which is the artifact a consumer of the kernel reads.
170
+ *
171
+ * WHAT IT DOES NOT REACH, stated at the definition site. An `outputs` entry
172
+ * naming a type NO schema is registered for is SKIPPED rather than refused:
173
+ * there is no document to mandate, and schemas/role-brief.schema.json declares
174
+ * that residue deliberately (an enum there would serialise M3-P6, M3-P7 and
175
+ * M3-P8 against one file). It reaches the FRONTMATTER only: a brief whose body
176
+ * prose describes the wrong output shape passes this, and that is the judgment
177
+ * case the plan's hazard table hands to M3-P7's `clause-text-matches-row`
178
+ * probe. And it is one sub-case of the hazard row at
179
+ * delivery/plan/kernel-plan-m3.md:3021 ("nothing can compute which document a
180
+ * role NEEDS"); the output contract is the part of that which IS computable,
181
+ * and the rest of the row stands.
182
+ */
183
+ /**
184
+ * THE ONE CANONICAL FORM OF A MANDATED-READING ENTRY (fix round 2, D-3).
185
+ *
186
+ * Entries are kernel-root-relative by definition
187
+ * (schemas/role-brief.schema.json:60 says resolution is "against the kernel
188
+ * root"), so `schemas/report.schema.json`, `./schemas/report.schema.json` and
189
+ * `schemas/../schemas/report.schema.json` are three spellings of one document.
190
+ *
191
+ * IT EXISTS BECAUSE TWO COMMANDS WERE COMPARING THE SAME ENTRY DIFFERENTLY.
192
+ * `outputContractDiagnostics` tested raw string membership while
193
+ * `resolveMandatedReading` resolved with `join`, which normalises; so a brief
194
+ * writing `./schemas/report.schema.json` COMPOSED cleanly and was REFUSED by
195
+ * `tiphys validate --type role-brief`. That divergence is fail-safe (the
196
+ * refusal is the strict side) and it is still the shape this round's own
197
+ * argument against injecting the entry rejected: two commands holding two
198
+ * opinions about one property. Both now ask this function.
199
+ *
200
+ * A LEADING `/` IS STRIPPED rather than treated as an absolute path, because
201
+ * `join(root, "/schemas/x")` already resolves to `<root>/schemas/x`: stripping
202
+ * makes the comparison agree with the resolution that was always happening,
203
+ * instead of introducing a form the two commands read differently. This
204
+ * function changes what is COMPARED; it changes nothing about what is OPENED.
205
+ */
206
+ export declare function canonicalReadingEntry(entry: string): string;
207
+ export declare function outputContractDiagnostics(outputs: readonly string[], reading: readonly string[], schemaFileForType: (type: string) => string | undefined): Diagnostic[];
208
+ /**
209
+ * Locate the installed kernel root by walking UP from this module and testing
210
+ * for a `roles/` directory holding at least one brief.
211
+ *
212
+ * Counting `..` would be right in exactly one of the two layouts this code
213
+ * runs in (`src/` from source, `dist/src/` from the built entry), which is
214
+ * the layout-dependent break `schemasDirectory` in src/commands/validate.ts
215
+ * already documents. Walking up and TESTING is right in both, and in a
216
+ * relocated copy as well.
217
+ */
218
+ export declare function kernelRoot(): string;
219
+ export type ReadingResolution = {
220
+ ok: true;
221
+ paths: string[];
222
+ } | {
223
+ ok: false;
224
+ reason: string;
225
+ };
226
+ /**
227
+ * Resolve every mandated-reading path against the kernel root, IN ORDER, and
228
+ * stop at the first one that is not a regular file.
229
+ *
230
+ * THE PATH IS NEVER OPENED. Existence and type are established by
231
+ * `classifyEntry`, so a named pipe at a mandated-reading path is refused with
232
+ * its observed type in bounded time instead of blocking this command forever.
233
+ * A MISSING path and a NON-REGULAR path are different states with different
234
+ * failure modes and they are reported differently on purpose (criteria 2 and
235
+ * 6c, which the plan is explicit are not the same criterion).
236
+ */
237
+ export declare function resolveMandatedReading(reading: readonly string[], root: string): ReadingResolution;
238
+ /**
239
+ * A body SECTION anchor: `## section <id>` with an optional `: title`.
240
+ *
241
+ * A SECOND MARKER RATHER THAN A REUSE OF THE CLAUSE ONE, and the separation is
242
+ * the point. A clause discharges a requirement row and round-trips against
243
+ * `clauses[]`; a section is a structural part of the brief that R-033a
244
+ * enumerates, and it has no frontmatter list to round-trip against. Marking
245
+ * both with `clause` would mean either declaring six section ids in `clauses[]`
246
+ * (where the clause map would then try to resolve them as rows) or exempting
247
+ * six anchors from the round trip, which is a hole in the check that exists to
248
+ * stop labels with nothing behind them.
249
+ */
250
+ export declare const SECTION_ANCHOR_PATTERN: RegExp;
251
+ /**
252
+ * The six sections R-033a enumerates, IN THE ORDER THE ROW GIVES THEM.
253
+ *
254
+ * HAND-WRITTEN, and there is nowhere to derive it from: R-033a is a row of a
255
+ * markdown table in a plan document, and parsing a requirement row's prose to
256
+ * recover six section names would be the "deciding what another program will
257
+ * do by pattern-matching the text of a file" mechanism, applied to a file that
258
+ * is not even machine-readable. The list is short, closed, and named in the
259
+ * plan; a phase that changes it changes this line and the criterion that
260
+ * witnesses it.
261
+ */
262
+ export declare const R033A_SECTIONS: readonly string[];
263
+ /** Every section anchor in a body, in order, duplicates kept. */
264
+ export declare function sectionAnchors(body: string): string[];
265
+ /**
266
+ * The text under one section anchor: everything from the line after the anchor
267
+ * up to the next heading of any level, or the end of the body.
268
+ */
269
+ export declare function sectionBody(body: string, section: string): string | undefined;
270
+ /**
271
+ * Why an include-expanded implementer body does not satisfy R-033a, or the
272
+ * empty list when it does.
273
+ *
274
+ * NON-EMPTY IS CHECKED, NOT ONLY PRESENT, and criterion 2 says so in as many
275
+ * words. A section reduced to its heading is the dangerous state here rather
276
+ * than a deleted one: the brief still has six anchors, still composes, still
277
+ * looks complete, and instructs nobody. A check that only counted anchors
278
+ * would be green against exactly that.
279
+ */
280
+ export declare function missingRequiredSections(body: string): string[];
281
+ /**
282
+ * The markers delimiting the generated gate list inside a brief.
283
+ *
284
+ * THE MODE IS IN THE BEGIN MARKER, which is where the brief DECLARES which
285
+ * mode's gate set it carries. It cannot go in the frontmatter: the frontmatter
286
+ * schema is closed (`additionalProperties: false`) and belongs to M3-P5, and a
287
+ * phase that needed a new frontmatter key would be editing another phase's
288
+ * merged contract. The marker is body text, it is visible to a reader of the
289
+ * brief, and `scripts/check-brief-drift.mjs` reads the mode back out of it, so
290
+ * the declaration and the rendering cannot disagree about which mode was meant.
291
+ *
292
+ * HTML comments, so they are invisible in rendered markdown and unambiguous to
293
+ * a line scanner, and they name the producing script so the next person to edit
294
+ * the block by hand is told what to edit instead. The same shape M3-P2 used for
295
+ * CLAUDE.md, deliberately: two drift checks that look different are two things
296
+ * to learn.
297
+ */
298
+ export declare function briefGateBlockBeginMarker(mode: string): string;
299
+ export declare const BRIEF_GATE_BLOCK_END_MARKER = "<!-- END GENERATED GATE LIST -->";
300
+ /**
301
+ * THE MODE THE SHIPPED BRIEF'S GATE BLOCK MUST DECLARE, pinned HERE and not in
302
+ * the brief (M3-P6 fix round 1, CV-1).
303
+ *
304
+ * The mechanism this closes, stated as a mechanism rather than as the instance
305
+ * that exposed it: A CHECK WHOSE SUBJECT IS SELECTED BY A VALUE READ FROM THE
306
+ * ARTIFACT IT AUDITS CAN BE SILENTLY NARROWED BY EDITING THAT ARTIFACT. The
307
+ * mode above is read out of the brief's own begin marker, deliberately, so that
308
+ * no CALLER can point the comparison at a mode the brief never claimed. That
309
+ * left the EDITOR of the brief holding the same power: switching the marker to
310
+ * a narrower mode and re-rendering produces a brief advertising five gates
311
+ * instead of fifteen with the drift check green, which is an instruction-surface
312
+ * defect every future implementer reads.
313
+ *
314
+ * Two clean-room contracts reached this from different directions on the same
315
+ * head, one by forcing the narrowing and one by deriving it from the unit
316
+ * arithmetic below, and neither was pointed at it.
317
+ *
318
+ * WHY IT IS A CONSTANT HERE AND NOT A REGISTRY KEY. `gate-registry.yaml` is
319
+ * closed (`additionalProperties: false`) and its schema belongs to M3-P2, so a
320
+ * registry key would be this phase editing another phase's merged contract, the
321
+ * same reasoning that put the mode in the marker rather than in the frontmatter.
322
+ * WHY `full` IS THE RIGHT VALUE is not asserted here as a bare literal: the
323
+ * registered test derives from the registry that this mode selects every gate
324
+ * any mode selects, so narrowing is the only direction the value can move.
325
+ */
326
+ export declare const BRIEF_GATE_BLOCK_MODE = "full";
327
+ export type GateBlockLocation = {
328
+ ok: true;
329
+ mode: string;
330
+ block: string;
331
+ begin: number;
332
+ end: number;
333
+ } | {
334
+ ok: false;
335
+ reason: string;
336
+ };
337
+ /**
338
+ * Locate the generated block in a brief, or say why it cannot be located.
339
+ *
340
+ * A MISSING MARKER IS A REFUSAL AND NEVER A SILENT "NO DRIFT". A check that
341
+ * reports clean because it could not find the thing it compares is the
342
+ * guard-condition failure this repository has recorded twice: the watchdog that
343
+ * tested existence instead of freshness, and the byte check that could not see
344
+ * the one byte it existed to catch.
345
+ */
346
+ export declare function locateGateBlock(text: string, path: string): GateBlockLocation;
347
+ interface RegistryPreflightEntry {
348
+ command: string[];
349
+ note: string;
350
+ }
351
+ interface RegistryGateEntry {
352
+ id: string;
353
+ applicability: string;
354
+ unitLabel: string;
355
+ modes: string[];
356
+ "verified-by": string;
357
+ probe?: string;
358
+ }
359
+ export interface GateRegistryDocument {
360
+ preflight: RegistryPreflightEntry[];
361
+ gates: RegistryGateEntry[];
362
+ }
363
+ export interface GateBlockRendering {
364
+ text: string;
365
+ /**
366
+ * How many GATE ROWS the rendering produced. The gate's `units`, so M2-C-2
367
+ * bites, and it counts the thing the gate's `unitLabel` names.
368
+ *
369
+ * IT USED TO INCLUDE THE PREFLIGHT STEPS AND THAT MADE THE VACUITY GUARD
370
+ * UNREACHABLE (M3-P6 fix round 1, CV-1's second face). `preflight` is
371
+ * mode-independent and always non-empty, so `preflight.length + selected.length`
372
+ * had a floor it could never fall below: a rendering that selected ZERO gates
373
+ * still reported three units, and M2-C-2 rewrites green-with-zero-units and
374
+ * nothing else. The check could therefore report `green (3 generated brief
375
+ * gate rows compared)` over a gate table holding a header, a separator and
376
+ * NOTHING ELSE, and the header's promise that "a run that compared ZERO rows
377
+ * becomes error with vacuous: true" was true of the plumbing and false of the
378
+ * behaviour.
379
+ *
380
+ * The general shape is the one this repository keeps paying for: a count that
381
+ * does not measure what its label names cannot make a guard fire.
382
+ */
383
+ units: number;
384
+ }
385
+ /**
386
+ * Render the brief's gate-list block from the registry ALONE, for one mode.
387
+ *
388
+ * IT DERIVES, IT DOES NOT READ THE BLOCK. The hazard the plan names for this
389
+ * criterion by name is "a generated gate-list block whose drift check compares
390
+ * the block TO ITSELF rather than to the registry", and that check is green
391
+ * forever. This function takes the decoded registry and a mode string, and
392
+ * nothing else; the brief file is opened only to compare against or write into.
393
+ *
394
+ * ONE RENDERER, TWO CALLERS. `scripts/check-brief-drift.mjs` calls it to
395
+ * compare and to write, and the registered test calls it to assert the composed
396
+ * brief is byte-identical to the registry's rendering. A second copy of this
397
+ * table in the test would be the test asserting agreement with itself.
398
+ */
399
+ export declare function renderBriefGateBlock(registry: GateRegistryDocument, mode: string): GateBlockRendering;
400
+ /**
401
+ * The two review contracts of `assurance-modes.yaml`'s `review-contracts`.
402
+ *
403
+ * TWO CONTRACTS, NOT TWO REVIEWERS, and the two are different axes that full
404
+ * mode requires both of. The measured evidence is that both reviews of one
405
+ * phase walked all fifteen acceptance criteria and agreed on every mechanical
406
+ * fact, and the one briefed on hazards found a high-severity defect the other's
407
+ * report does not name.
408
+ */
409
+ export declare const REVIEW_CONTRACTS: readonly string[];
410
+ /** The clause id carrying one contract's instructions. */
411
+ export declare function reviewContractClause(contract: string): string;
412
+ /**
413
+ * The role whose brief carries a contract per value. Named rather than assumed,
414
+ * because `--review-contract` on any other role is a usage error and the check
415
+ * that says so needs something to compare against.
416
+ */
417
+ export declare const REVIEW_CONTRACT_ROLE = "clean-room-reviewer";
418
+ export type ContractSelection = {
419
+ ok: true;
420
+ text: string;
421
+ } | {
422
+ ok: false;
423
+ reason: string;
424
+ };
425
+ /**
426
+ * Keep the selected contract's clause block and DROP the others.
427
+ *
428
+ * The composed brief is what a dispatched reviewer reads, and a brief carrying
429
+ * both contracts has told the reviewer to start from the criteria and not to
430
+ * start from the criteria. Dropping happens at COMPOSE time and never in the
431
+ * file: the file declares both clause ids and carries both blocks, so the
432
+ * clause round trip still sees a complete brief and `tiphys validate` still
433
+ * checks both texts. A design that split the two into two files would have put
434
+ * the shared four-fifths of the brief in two places.
435
+ */
436
+ export declare function selectReviewContract(body: string, contract: string): ContractSelection;
437
+ /**
438
+ * THE FIELDS OF A PLAN PHASE THAT `brief compose` RENDERS, in order.
439
+ *
440
+ * HAND-WRITTEN ON PURPOSE, AND THE TEST THAT GUARDS IT IS NOT. Criterion 3b
441
+ * requires the rendered phase text to be a COMPLETE projection of the phase
442
+ * object, and requires the assertion to be driven FROM
443
+ * `schemas/plan.schema.json`'s phase `required` array rather than from a
444
+ * hand-written list. If this list were also derived from the schema the two
445
+ * would move together and the test could never redden, which is the shape of
446
+ * a guard whose condition does not test the property that matters.
447
+ *
448
+ * So: the SCHEMA is the test's source and this list is the renderer's, they
449
+ * are independent, and a later phase adding a required phase field reddens
450
+ * `brief compose renders every required field of the plan schema's phase` until
451
+ * this list is extended. The dangerous state the criterion names is the
452
+ * realistic one, a renderer that silently drops a field while the composed
453
+ * output still contains a mandated-reading list, a body and SOME phase text,
454
+ * and deleting an entry from this list is exactly that state.
455
+ */
456
+ export declare const PHASE_FIELD_ORDER: readonly string[];
457
+ /** Render one field value as markdown lines. */
458
+ export declare function renderFieldValue(value: unknown, indent: string): string[];
459
+ /** Render one plan phase as the brief's phase section. */
460
+ export declare function renderPhase(phase: Record<string, unknown>): string[];
461
+ export {};