@tiphys/kernel 0.0.0 → 0.1.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 (181) hide show
  1. package/AGENTS.md +611 -0
  2. package/LICENSE +202 -0
  3. package/assurance-modes.yaml +278 -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 +14 -0
  11. package/dist/src/brief.d.ts +32 -0
  12. package/dist/src/brief.js +59 -0
  13. package/dist/src/checklists.d.ts +169 -0
  14. package/dist/src/checklists.js +310 -0
  15. package/dist/src/checks.d.ts +828 -0
  16. package/dist/src/checks.js +3314 -0
  17. package/dist/src/cli.d.ts +9 -0
  18. package/dist/src/cli.js +57 -0
  19. package/dist/src/commands/brief.d.ts +92 -0
  20. package/dist/src/commands/brief.js +320 -0
  21. package/dist/src/commands/checklist.d.ts +42 -0
  22. package/dist/src/commands/checklist.js +168 -0
  23. package/dist/src/commands/doctor.d.ts +35 -0
  24. package/dist/src/commands/doctor.js +605 -0
  25. package/dist/src/commands/gates.d.ts +9 -0
  26. package/dist/src/commands/gates.js +360 -0
  27. package/dist/src/commands/init.d.ts +30 -0
  28. package/dist/src/commands/init.js +128 -0
  29. package/dist/src/commands/lock.d.ts +1 -0
  30. package/dist/src/commands/lock.js +229 -0
  31. package/dist/src/commands/mode.d.ts +40 -0
  32. package/dist/src/commands/mode.js +134 -0
  33. package/dist/src/commands/plan.d.ts +20 -0
  34. package/dist/src/commands/plan.js +105 -0
  35. package/dist/src/commands/pool.d.ts +1 -0
  36. package/dist/src/commands/pool.js +128 -0
  37. package/dist/src/commands/spawn.d.ts +1 -0
  38. package/dist/src/commands/spawn.js +146 -0
  39. package/dist/src/commands/status.d.ts +19 -0
  40. package/dist/src/commands/status.js +120 -0
  41. package/dist/src/commands/teardown.d.ts +1 -0
  42. package/dist/src/commands/teardown.js +79 -0
  43. package/dist/src/commands/tuition.d.ts +21 -0
  44. package/dist/src/commands/tuition.js +218 -0
  45. package/dist/src/commands/validate.d.ts +78 -0
  46. package/dist/src/commands/validate.js +360 -0
  47. package/dist/src/commands/watch.d.ts +1 -0
  48. package/dist/src/commands/watch.js +172 -0
  49. package/dist/src/exec/env.d.ts +128 -0
  50. package/dist/src/exec/env.js +190 -0
  51. package/dist/src/fleet.d.ts +51 -0
  52. package/dist/src/fleet.js +80 -0
  53. package/dist/src/gates/adapters/http-json.d.ts +5 -0
  54. package/dist/src/gates/adapters/http-json.js +283 -0
  55. package/dist/src/gates/adapters/migrations-command.d.ts +1 -0
  56. package/dist/src/gates/adapters/migrations-command.js +373 -0
  57. package/dist/src/gates/citations.d.ts +408 -0
  58. package/dist/src/gates/citations.js +1163 -0
  59. package/dist/src/gates/coverage.d.ts +284 -0
  60. package/dist/src/gates/coverage.js +701 -0
  61. package/dist/src/gates/credentials.d.ts +74 -0
  62. package/dist/src/gates/credentials.js +533 -0
  63. package/dist/src/gates/deploy.d.ts +1 -0
  64. package/dist/src/gates/deploy.js +33 -0
  65. package/dist/src/gates/manifest.d.ts +99 -0
  66. package/dist/src/gates/manifest.js +208 -0
  67. package/dist/src/gates/migrations.d.ts +1 -0
  68. package/dist/src/gates/migrations.js +36 -0
  69. package/dist/src/gates/pin.d.ts +114 -0
  70. package/dist/src/gates/pin.js +154 -0
  71. package/dist/src/gates/red-witness.d.ts +22 -0
  72. package/dist/src/gates/red-witness.js +390 -0
  73. package/dist/src/gates/release.d.ts +283 -0
  74. package/dist/src/gates/release.js +820 -0
  75. package/dist/src/gates/result.d.ts +116 -0
  76. package/dist/src/gates/result.js +91 -0
  77. package/dist/src/gates/run.d.ts +566 -0
  78. package/dist/src/gates/run.js +1536 -0
  79. package/dist/src/gates/schemas/citation-config.schema.json +59 -0
  80. package/dist/src/gates/schemas/coverage-config.schema.json +77 -0
  81. package/dist/src/gates/schemas/gate-manifest.schema.json +125 -0
  82. package/dist/src/gates/schemas/gate-result.schema.json +160 -0
  83. package/dist/src/gates/schemas/phase-declaration.schema.json +42 -0
  84. package/dist/src/gates/schemas/release-record.schema.json +119 -0
  85. package/dist/src/gates/schemas/verifier-config.schema.json +101 -0
  86. package/dist/src/gates/schemas/witness-spec.schema.json +110 -0
  87. package/dist/src/gates/scope.d.ts +131 -0
  88. package/dist/src/gates/scope.js +1018 -0
  89. package/dist/src/gates/suite.d.ts +217 -0
  90. package/dist/src/gates/suite.js +927 -0
  91. package/dist/src/gates/validate.d.ts +121 -0
  92. package/dist/src/gates/validate.js +414 -0
  93. package/dist/src/hooks.d.ts +32 -0
  94. package/dist/src/hooks.js +62 -0
  95. package/dist/src/liveness.d.ts +321 -0
  96. package/dist/src/liveness.js +396 -0
  97. package/dist/src/lock.d.ts +178 -0
  98. package/dist/src/lock.js +500 -0
  99. package/dist/src/modes.d.ts +149 -0
  100. package/dist/src/modes.js +258 -0
  101. package/dist/src/path-identity.d.ts +2 -0
  102. package/dist/src/path-identity.js +10 -0
  103. package/dist/src/plan.d.ts +73 -0
  104. package/dist/src/plan.js +153 -0
  105. package/dist/src/pool.d.ts +130 -0
  106. package/dist/src/pool.js +721 -0
  107. package/dist/src/roles.d.ts +430 -0
  108. package/dist/src/roles.js +734 -0
  109. package/dist/src/spawn.d.ts +177 -0
  110. package/dist/src/spawn.js +332 -0
  111. package/dist/src/status.d.ts +91 -0
  112. package/dist/src/status.js +119 -0
  113. package/dist/src/task.d.ts +264 -0
  114. package/dist/src/task.js +305 -0
  115. package/dist/src/teardown.d.ts +32 -0
  116. package/dist/src/teardown.js +314 -0
  117. package/dist/src/tuition.d.ts +159 -0
  118. package/dist/src/tuition.js +311 -0
  119. package/dist/src/validate.d.ts +230 -0
  120. package/dist/src/validate.js +732 -0
  121. package/dist/src/version.d.ts +3 -0
  122. package/dist/src/version.js +38 -0
  123. package/dist/src/watcher.d.ts +275 -0
  124. package/dist/src/watcher.js +859 -0
  125. package/dist/src/witness/run.d.ts +274 -0
  126. package/dist/src/witness/run.js +1327 -0
  127. package/dist/src/witness/spec.d.ts +102 -0
  128. package/dist/src/witness/spec.js +253 -0
  129. package/dist/tsconfig.src.tsbuildinfo +1 -0
  130. package/gate-registry.yaml +390 -0
  131. package/gates.manifest.json +195 -0
  132. package/package.json +57 -3
  133. package/role-model-config.yaml +88 -0
  134. package/roles/README.md +128 -0
  135. package/roles/_shared-dispatch-contract.md +87 -0
  136. package/roles/adversarial-plan-reviewer.md +80 -0
  137. package/roles/clean-room-reviewer.md +140 -0
  138. package/roles/implementer.md +460 -0
  139. package/roles/investigator.md +138 -0
  140. package/roles/plan-writer.md +95 -0
  141. package/schemas/README.md +81 -0
  142. package/schemas/assurance-modes.schema.json +264 -0
  143. package/schemas/charter.schema.json +166 -0
  144. package/schemas/checklist.schema.json +114 -0
  145. package/schemas/decision-record.schema.json +88 -0
  146. package/schemas/final-report.schema.json +90 -0
  147. package/schemas/finding.schema.json +106 -0
  148. package/schemas/gate-registry.schema.json +260 -0
  149. package/schemas/mechanism-index.schema.json +94 -0
  150. package/schemas/plan.schema.json +300 -0
  151. package/schemas/report.schema.json +579 -0
  152. package/schemas/role-brief.schema.json +105 -0
  153. package/schemas/role-model-config.schema.json +90 -0
  154. package/schemas/status-line.schema.json +40 -0
  155. package/schemas/tuition.schema.json +191 -0
  156. package/schemas/verdict.schema.json +289 -0
  157. package/schemas/work-history.schema.json +183 -0
  158. package/templates/charter.example.yaml +54 -0
  159. package/templates/decision-record.example.yaml +27 -0
  160. package/templates/final-report.example.yaml +80 -0
  161. package/templates/plan.example.yaml +87 -0
  162. package/templates/report.example.yaml +236 -0
  163. package/templates/warnings.md +74 -0
  164. package/templates/work-history.example.yaml +185 -0
  165. package/tuition/README.md +76 -0
  166. package/tuition/T-001.yaml +48 -0
  167. package/tuition/T-002.yaml +51 -0
  168. package/tuition/T-003.yaml +100 -0
  169. package/tuition/T-004.yaml +52 -0
  170. package/tuition/T-005.yaml +72 -0
  171. package/tuition/T-006.yaml +81 -0
  172. package/tuition/T-007.yaml +56 -0
  173. package/tuition/T-008.yaml +111 -0
  174. package/tuition/T-009.yaml +50 -0
  175. package/tuition/T-015.yaml +36 -0
  176. package/tuition/T-016.yaml +36 -0
  177. package/tuition/T-017.yaml +46 -0
  178. package/tuition/T-018.yaml +84 -0
  179. package/tuition/T-021.yaml +40 -0
  180. package/tuition/T-022.yaml +36 -0
  181. package/tuition/mechanism-index.yaml +256 -0
@@ -0,0 +1,217 @@
1
+ /**
2
+ * THE SUITE GATE (kernel plan M2, M2-P3).
3
+ *
4
+ * Replaces "the suite is green" with a machine-countable claim: the suite
5
+ * ran as configured, every discovered test file was reported, every
6
+ * registered behavior resolves to a reported test, no behavior registered
7
+ * at the merge base has been deleted, every skip carries a reason, the
8
+ * tree did not change under the run (M2-C-5 pin), and the counts come from
9
+ * a pinned structured stream plus the child's exit code and from nowhere
10
+ * else (C-1).
11
+ *
12
+ * HOW THE SUITE IS RUN. The repository's own `package.json` scripts.test
13
+ * is executed VERBATIM through `/bin/sh -c`, exactly as npm runs it. The
14
+ * gate never parses or reconstructs the script: deciding what another
15
+ * program will do by pattern-matching the text of a file it consumes is
16
+ * the mechanism MECHANISMS.md records four fix rounds for. What npm adds
17
+ * beyond sh -c (node_modules/.bin on PATH, lifecycle hooks) is not
18
+ * reproduced; a test script that depends on either fails LOUDLY here
19
+ * (the reporter stream never appears, which is `error`), never silently.
20
+ *
21
+ * THE REPORTER IS A PINNED, REQUESTED INPUT (M2-P3 step 2, MECHANISMS.md
22
+ * "Parsing another program's reporter output"). Measured on both installed
23
+ * toolchains (v22.22.2 and v26.6.0, work history m2-p3 step 1):
24
+ *
25
+ * - tap carries NO file attribution for passing tests, so it cannot
26
+ * support discovery parity or name the missing file;
27
+ * - junit loses file attribution on nested tests and DROPS raw test
28
+ * output, so a counterfeit line cannot be captured verbatim from it;
29
+ * - the documented custom-reporter event stream carries file, name,
30
+ * nesting, skip (with reason), todo, entity type and failureType for
31
+ * every test on both toolchains, and delivers raw test output as
32
+ * test:stdout/test:stderr events whose payload is a JSON string.
33
+ *
34
+ * So the gate pins `tiphys-suite-events-v1`: an NDJSON stream emitted by
35
+ * the reporter module below, embedded as a data: URL so the reporter
36
+ * cannot drift apart from the parser that consumes it. It is REQUESTED
37
+ * explicitly for the child via child-scoped NODE_OPTIONS; the inherited
38
+ * NODE_OPTIONS is deliberately dropped, because an inherited reporter
39
+ * option is precisely the ambient default the pin exists to exclude. The
40
+ * received stream is validated to be this format BEFORE any count is
41
+ * parsed: header first, every line a known event, explicit stream-end
42
+ * trailer last. A stream in any other format, or truncated, is `error`
43
+ * naming the expected and observed formats. Widening the parse to accept
44
+ * whichever format arrived is forbidden.
45
+ *
46
+ * WHY A COUNTERFEIT LINE CANNOT COUNT (C-1, criterion 6). A test body
47
+ * printing "pass 999", or even a byte-exact tiphys event line, arrives as
48
+ * a test:stdout EVENT whose text sits INSIDE a JSON string field, escaped
49
+ * by the reporter's own JSON.stringify. It cannot form an event line, so
50
+ * it cannot reach the arithmetic; it is captured verbatim in the evidence
51
+ * instead. The measured tap contrast is in the work history: there the
52
+ * same bytes land as `# pass 999`, byte-identical in grammar to the real
53
+ * `# pass 3` summary line below it.
54
+ *
55
+ * DISCOVERY PARITY (step 3, PR-106): candidates are enumerated by WALKING
56
+ * the declared test roots for the declared suffix, never by expanding the
57
+ * runner's own selection pattern, because the pattern is the thing that
58
+ * can be wrong and an enumeration sharing it cannot see that. Both
59
+ * directions are enforced: a walked file absent from the reporter and a
60
+ * reported file outside the walk are each parity failures naming the file.
61
+ *
62
+ * M2-C-6: every path this gate reads that it did not create goes through
63
+ * the delivered classifyEntry / readRegularFileIfPresent /
64
+ * refuseOpenForWrite from src/task.ts. The walk probes types before
65
+ * reading names' targets and throws on anything irregular, so a named
66
+ * pipe inside a declared root is `error` naming the path and type, never
67
+ * a hang.
68
+ *
69
+ * CHILD ENVIRONMENT, deterministic by construction: NODE_OPTIONS is
70
+ * replaced (see above) and NODE_TEST_CONTEXT/NODE_TEST_* are removed,
71
+ * because a nested `node --test` that inherits them switches to its
72
+ * child-of-a-runner protocol and reports nothing usable (measured by
73
+ * M1-P6; see test/exit-test-local.test.ts identityLessEnv).
74
+ */
75
+ export declare const SUITE_GATE_ID = "suite";
76
+ export declare const SUITE_UNIT_LABEL = "tests reported";
77
+ export declare const REPORTER_NAME = "tiphys-suite-events-v1";
78
+ export declare const STREAM_FILE = "suite-events.ndjson";
79
+ export declare const STDOUT_FILE = "suite-stdout.txt";
80
+ export declare const STDERR_FILE = "suite-stderr.txt";
81
+ export declare const RAW_OUTPUT_FILE = "suite-raw-output.txt";
82
+ export declare const COUNTS_FILE = "counts.json";
83
+ export declare function reporterDataUrl(): string;
84
+ /** One reported test point, decoded from the pinned stream. */
85
+ export interface SuitePoint {
86
+ event: "test:pass" | "test:fail";
87
+ name: string;
88
+ file: string;
89
+ nesting: number;
90
+ skip?: boolean | string;
91
+ todo?: boolean | string;
92
+ entityType: "test" | "suite";
93
+ failureType?: string;
94
+ }
95
+ export interface SuiteStream {
96
+ /** process.version of the node that actually ran the suite. */
97
+ childNode: string;
98
+ points: SuitePoint[];
99
+ /** Raw test output, concatenated in stream order. Evidence, never data. */
100
+ rawOutput: string;
101
+ }
102
+ export type StreamParse = {
103
+ ok: true;
104
+ stream: SuiteStream;
105
+ } | {
106
+ ok: false;
107
+ reason: string;
108
+ };
109
+ /**
110
+ * Validate that `body` is a tiphys-suite-events-v1 stream and decode it.
111
+ * The format is checked BEFORE any count is derived; a stream in another
112
+ * format, however valid in its own grammar, is a refusal naming both
113
+ * formats, never a widened parse.
114
+ */
115
+ export declare function parseSuiteStream(body: string): StreamParse;
116
+ /**
117
+ * THE MAPPING, recorded here once and restated in every counts.json
118
+ * (M2-P3 step 6, M2R-022). Buckets are mutually exclusive and each
119
+ * reported test lands in exactly one:
120
+ *
121
+ * skipped the point carries a skip marker (reason or bare)
122
+ * todo not skipped, carries a todo marker
123
+ * didNotRun test:fail with failureType cancelledByParent; this is the
124
+ * one shape node itself counted under "# cancelled" in the
125
+ * same measured run (work history step 1 finding 7). Every
126
+ * other failureType, including testTimeoutFailure, ran and
127
+ * failed, which is `fail`.
128
+ * fail any other test:fail
129
+ * pass any other test:pass
130
+ *
131
+ * `reported` counts points whose entityType is `test`, which reproduces
132
+ * node's own "# tests" semantics for every REAL test (measured: suites
133
+ * are not tests). This does NOT hold for a file that defines zero tests:
134
+ * node still emits one nesting-0 test:pass for it, entityType `test`,
135
+ * named after the file's own invocation path (CR-1306, fixed below by
136
+ * `isFileWrapperPhantom`; a prior version of this comment asserted the
137
+ * false generalization "file wrappers emit no pass/fail"). The identity
138
+ * pass + fail + skipped + todo + didNotRun == reported is asserted, and
139
+ * `discovered` is the independent walk's file set, tied to `reported` by
140
+ * the file-set equality check rather than by unit-mixing arithmetic.
141
+ */
142
+ export declare const MAPPING_STATEMENT: string;
143
+ /**
144
+ * CR-1306: a `.test.ts` file that defines ZERO tests is not silent. Node
145
+ * itself (measured on v22.22.2 and v26.6.0, both directions of the glob
146
+ * the repo's own test script uses) still emits exactly one nesting-0
147
+ * test:pass point for such a file, entityType `test`, whose `name` is the
148
+ * file's own path exactly AS IT WAS INVOKED. Counting that point as
149
+ * `entityType === "test"` like every other reported point (the mechanism
150
+ * `bucketPoints` and the discovery/registry filters below all shared)
151
+ * inflates `units` by one per emptied file, and because `units > 0` the
152
+ * M2-C-2 "never green by omission" rewrite in result.ts never triggers:
153
+ * a suite that ran zero real tests would report green.
154
+ *
155
+ * A real top-level test is ALSO nesting 0 and entityType `test` (measured:
156
+ * `describe()` wrappers are entityType `suite` and never collide), so
157
+ * nesting and entityType alone cannot distinguish the phantom from a real
158
+ * test. The one further fact that does, and the only one node offers, is
159
+ * the point's own name coinciding exactly with its file's identity; a real
160
+ * test can only produce that collision by deliberately naming itself after
161
+ * its own file, which this function accepts as the residual, documented
162
+ * non-coverage (see delivery/work-history/m2-p3.md fix round one
163
+ * derivation).
164
+ *
165
+ * CR-1410-1 (fix round two): the string this coincidence is compared
166
+ * against MUST be spelling-invariant, not one particular spelling. Round
167
+ * one compared `point.name === relative(cwd, point.file)`, which is a
168
+ * comparison between two DIFFERENT strings whenever the invocation spells
169
+ * the path other than relative-to-cwd; node names the phantom by the
170
+ * file's path exactly as invoked (measured, both toolchains, fix round two
171
+ * derivation in delivery/work-history/m2-p3.md step "fix round two"):
172
+ * relative glob, bare auto-discovery and a `./`-prefixed path all name it
173
+ * relatively, but an ABSOLUTE-path invocation names it absolutely, and
174
+ * `relative(cwd, point.file)` is always relative, so the comparison misses
175
+ * that spelling and the phantom is counted as a real test again -- the
176
+ * exact CR-1306 defect through a different spelling, and the gate cannot
177
+ * control the spelling because it reads the target repo's `scripts.test`
178
+ * verbatim (see the file header). The fix compares two REPRESENTATIONS OF
179
+ * THE SAME FILE instead of two spellings of a path: `resolve(cwd,
180
+ * point.name)` normalizes whatever spelling `name` carries (relative,
181
+ * `./`-prefixed, or already absolute -- `resolve` returns an absolute
182
+ * argument unchanged, measured) into the same absolute string `point.file`
183
+ * already is, so the equality is invariant across every spelling node
184
+ * produces it in, by construction rather than by enumeration.
185
+ *
186
+ * The fix filters the phantom out before ANY of the three counting sites
187
+ * that read `entityType === "test"` (bucketPoints, the discovery-parity
188
+ * reportedFiles set, and the registry-resolution reportedTestNames set) so
189
+ * an emptied file is not silently miscounted as a passing test; it instead
190
+ * falls out of `reportedFiles`, which the existing discovery-parity check
191
+ * (step 3, unchanged) already reports as "test file discovered by the walk
192
+ * but absent from the reporter" -- a red finding, never a counted green.
193
+ */
194
+ export declare function isFileWrapperPhantom(point: SuitePoint, cwd: string): boolean;
195
+ export interface SuiteCounts {
196
+ reported: number;
197
+ pass: number;
198
+ fail: number;
199
+ skipped: number;
200
+ todo: number;
201
+ didNotRun: number;
202
+ }
203
+ export declare function bucketPoints(points: SuitePoint[]): {
204
+ counts: SuiteCounts;
205
+ skipsWithoutReason: SuitePoint[];
206
+ failures: SuitePoint[];
207
+ cancelled: SuitePoint[];
208
+ };
209
+ /**
210
+ * Walk one declared root for files carrying the declared suffix. The walk
211
+ * never expands the runner's selection pattern; the roots and suffix are
212
+ * the declaration, and the walk is exhaustive under them. Fail closed on
213
+ * anything that is not a regular file or a real directory (M2-C-6): a
214
+ * named pipe inside a test root makes the gate `error`, never a hang.
215
+ */
216
+ export declare function walkTestFiles(root: string, suffix: string): string[];
217
+ export declare function runSuiteGate(argv: string[]): number;