@gate-forge/core 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 (242) hide show
  1. package/LICENSE +202 -0
  2. package/dist/baselines/adoption.d.ts +76 -0
  3. package/dist/baselines/adoption.d.ts.map +1 -0
  4. package/dist/baselines/adoption.js +163 -0
  5. package/dist/baselines/adoption.js.map +1 -0
  6. package/dist/baselines/index.d.ts +102 -0
  7. package/dist/baselines/index.d.ts.map +1 -0
  8. package/dist/baselines/index.js +186 -0
  9. package/dist/baselines/index.js.map +1 -0
  10. package/dist/canonical-json.d.ts +51 -0
  11. package/dist/canonical-json.d.ts.map +1 -0
  12. package/dist/canonical-json.js +112 -0
  13. package/dist/canonical-json.js.map +1 -0
  14. package/dist/classifier/bind.d.ts +64 -0
  15. package/dist/classifier/bind.d.ts.map +1 -0
  16. package/dist/classifier/bind.js +188 -0
  17. package/dist/classifier/bind.js.map +1 -0
  18. package/dist/classifier/classify.d.ts +154 -0
  19. package/dist/classifier/classify.d.ts.map +1 -0
  20. package/dist/classifier/classify.js +1207 -0
  21. package/dist/classifier/classify.js.map +1 -0
  22. package/dist/classifier/glob.d.ts +48 -0
  23. package/dist/classifier/glob.d.ts.map +1 -0
  24. package/dist/classifier/glob.js +104 -0
  25. package/dist/classifier/glob.js.map +1 -0
  26. package/dist/classifier/index.d.ts +10 -0
  27. package/dist/classifier/index.d.ts.map +1 -0
  28. package/dist/classifier/index.js +21 -0
  29. package/dist/classifier/index.js.map +1 -0
  30. package/dist/classifier/schema.d.ts +150 -0
  31. package/dist/classifier/schema.d.ts.map +1 -0
  32. package/dist/classifier/schema.js +139 -0
  33. package/dist/classifier/schema.js.map +1 -0
  34. package/dist/config/index.d.ts +259 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +523 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/fingerprints.d.ts +56 -0
  39. package/dist/fingerprints.d.ts.map +1 -0
  40. package/dist/fingerprints.js +59 -0
  41. package/dist/fingerprints.js.map +1 -0
  42. package/dist/graph/build.d.ts +16 -0
  43. package/dist/graph/build.d.ts.map +1 -0
  44. package/dist/graph/build.js +423 -0
  45. package/dist/graph/build.js.map +1 -0
  46. package/dist/graph/index.d.ts +12 -0
  47. package/dist/graph/index.d.ts.map +1 -0
  48. package/dist/graph/index.js +10 -0
  49. package/dist/graph/index.js.map +1 -0
  50. package/dist/graph/schema.d.ts +448 -0
  51. package/dist/graph/schema.d.ts.map +1 -0
  52. package/dist/graph/schema.js +237 -0
  53. package/dist/graph/schema.js.map +1 -0
  54. package/dist/graph/symbols.d.ts +129 -0
  55. package/dist/graph/symbols.d.ts.map +1 -0
  56. package/dist/graph/symbols.js +177 -0
  57. package/dist/graph/symbols.js.map +1 -0
  58. package/dist/graph/util.d.ts +40 -0
  59. package/dist/graph/util.d.ts.map +1 -0
  60. package/dist/graph/util.js +41 -0
  61. package/dist/graph/util.js.map +1 -0
  62. package/dist/index.d.ts +683 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +563 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/mapping/resolve.d.ts +177 -0
  67. package/dist/mapping/resolve.d.ts.map +1 -0
  68. package/dist/mapping/resolve.js +523 -0
  69. package/dist/mapping/resolve.js.map +1 -0
  70. package/dist/policy/coverage.d.ts +79 -0
  71. package/dist/policy/coverage.d.ts.map +1 -0
  72. package/dist/policy/coverage.js +119 -0
  73. package/dist/policy/coverage.js.map +1 -0
  74. package/dist/policy/evaluate.d.ts +275 -0
  75. package/dist/policy/evaluate.d.ts.map +1 -0
  76. package/dist/policy/evaluate.js +382 -0
  77. package/dist/policy/evaluate.js.map +1 -0
  78. package/dist/policy/index.d.ts +15 -0
  79. package/dist/policy/index.d.ts.map +1 -0
  80. package/dist/policy/index.js +14 -0
  81. package/dist/policy/index.js.map +1 -0
  82. package/dist/policy/trusted.d.ts +59 -0
  83. package/dist/policy/trusted.d.ts.map +1 -0
  84. package/dist/policy/trusted.js +96 -0
  85. package/dist/policy/trusted.js.map +1 -0
  86. package/dist/provenance.d.ts +170 -0
  87. package/dist/provenance.d.ts.map +1 -0
  88. package/dist/provenance.js +306 -0
  89. package/dist/provenance.js.map +1 -0
  90. package/dist/receipt/index.d.ts +74 -0
  91. package/dist/receipt/index.d.ts.map +1 -0
  92. package/dist/receipt/index.js +154 -0
  93. package/dist/receipt/index.js.map +1 -0
  94. package/dist/report/index.d.ts +100 -0
  95. package/dist/report/index.d.ts.map +1 -0
  96. package/dist/report/index.js +355 -0
  97. package/dist/report/index.js.map +1 -0
  98. package/dist/schemas/adoption.d.ts +40 -0
  99. package/dist/schemas/adoption.d.ts.map +1 -0
  100. package/dist/schemas/adoption.js +87 -0
  101. package/dist/schemas/adoption.js.map +1 -0
  102. package/dist/schemas/baseline.d.ts +19 -0
  103. package/dist/schemas/baseline.d.ts.map +1 -0
  104. package/dist/schemas/baseline.js +45 -0
  105. package/dist/schemas/baseline.js.map +1 -0
  106. package/dist/schemas/claim.d.ts +32 -0
  107. package/dist/schemas/claim.d.ts.map +1 -0
  108. package/dist/schemas/claim.js +34 -0
  109. package/dist/schemas/claim.js.map +1 -0
  110. package/dist/schemas/classification-policy.d.ts +84 -0
  111. package/dist/schemas/classification-policy.d.ts.map +1 -0
  112. package/dist/schemas/classification-policy.js +130 -0
  113. package/dist/schemas/classification-policy.js.map +1 -0
  114. package/dist/schemas/classification-signal.d.ts +125 -0
  115. package/dist/schemas/classification-signal.d.ts.map +1 -0
  116. package/dist/schemas/classification-signal.js +126 -0
  117. package/dist/schemas/classification-signal.js.map +1 -0
  118. package/dist/schemas/classification.d.ts +120 -0
  119. package/dist/schemas/classification.d.ts.map +1 -0
  120. package/dist/schemas/classification.js +154 -0
  121. package/dist/schemas/classification.js.map +1 -0
  122. package/dist/schemas/common.d.ts +73 -0
  123. package/dist/schemas/common.d.ts.map +1 -0
  124. package/dist/schemas/common.js +60 -0
  125. package/dist/schemas/common.js.map +1 -0
  126. package/dist/schemas/coverage-policy.d.ts +89 -0
  127. package/dist/schemas/coverage-policy.d.ts.map +1 -0
  128. package/dist/schemas/coverage-policy.js +81 -0
  129. package/dist/schemas/coverage-policy.js.map +1 -0
  130. package/dist/schemas/evidence.d.ts +65 -0
  131. package/dist/schemas/evidence.d.ts.map +1 -0
  132. package/dist/schemas/evidence.js +64 -0
  133. package/dist/schemas/evidence.js.map +1 -0
  134. package/dist/schemas/execution-result.d.ts +214 -0
  135. package/dist/schemas/execution-result.d.ts.map +1 -0
  136. package/dist/schemas/execution-result.js +240 -0
  137. package/dist/schemas/execution-result.js.map +1 -0
  138. package/dist/schemas/gate-receipt.d.ts +86 -0
  139. package/dist/schemas/gate-receipt.d.ts.map +1 -0
  140. package/dist/schemas/gate-receipt.js +193 -0
  141. package/dist/schemas/gate-receipt.js.map +1 -0
  142. package/dist/schemas/index.d.ts +22 -0
  143. package/dist/schemas/index.d.ts.map +1 -0
  144. package/dist/schemas/index.js +22 -0
  145. package/dist/schemas/index.js.map +1 -0
  146. package/dist/schemas/obligation.d.ts +37 -0
  147. package/dist/schemas/obligation.d.ts.map +1 -0
  148. package/dist/schemas/obligation.js +46 -0
  149. package/dist/schemas/obligation.js.map +1 -0
  150. package/dist/schemas/plugin.d.ts +19 -0
  151. package/dist/schemas/plugin.d.ts.map +1 -0
  152. package/dist/schemas/plugin.js +20 -0
  153. package/dist/schemas/plugin.js.map +1 -0
  154. package/dist/schemas/policy.d.ts +73 -0
  155. package/dist/schemas/policy.d.ts.map +1 -0
  156. package/dist/schemas/policy.js +46 -0
  157. package/dist/schemas/policy.js.map +1 -0
  158. package/dist/schemas/resource.d.ts +26 -0
  159. package/dist/schemas/resource.d.ts.map +1 -0
  160. package/dist/schemas/resource.js +29 -0
  161. package/dist/schemas/resource.js.map +1 -0
  162. package/dist/schemas/run-manifest.d.ts +72 -0
  163. package/dist/schemas/run-manifest.d.ts.map +1 -0
  164. package/dist/schemas/run-manifest.js +125 -0
  165. package/dist/schemas/run-manifest.js.map +1 -0
  166. package/dist/schemas/runner-adapter.d.ts +169 -0
  167. package/dist/schemas/runner-adapter.d.ts.map +1 -0
  168. package/dist/schemas/runner-adapter.js +2 -0
  169. package/dist/schemas/runner-adapter.js.map +1 -0
  170. package/dist/schemas/test-catalog.d.ts +472 -0
  171. package/dist/schemas/test-catalog.d.ts.map +1 -0
  172. package/dist/schemas/test-catalog.js +311 -0
  173. package/dist/schemas/test-catalog.js.map +1 -0
  174. package/dist/schemas/test-map.d.ts +99 -0
  175. package/dist/schemas/test-map.d.ts.map +1 -0
  176. package/dist/schemas/test-map.js +103 -0
  177. package/dist/schemas/test-map.js.map +1 -0
  178. package/dist/schemas/verdict.d.ts +73 -0
  179. package/dist/schemas/verdict.d.ts.map +1 -0
  180. package/dist/schemas/verdict.js +92 -0
  181. package/dist/schemas/verdict.js.map +1 -0
  182. package/dist/schemas/waiver.d.ts +36 -0
  183. package/dist/schemas/waiver.d.ts.map +1 -0
  184. package/dist/schemas/waiver.js +42 -0
  185. package/dist/schemas/waiver.js.map +1 -0
  186. package/dist/supervision/index.d.ts +170 -0
  187. package/dist/supervision/index.d.ts.map +1 -0
  188. package/dist/supervision/index.js +354 -0
  189. package/dist/supervision/index.js.map +1 -0
  190. package/dist/testing/clock.d.ts +50 -0
  191. package/dist/testing/clock.d.ts.map +1 -0
  192. package/dist/testing/clock.js +75 -0
  193. package/dist/testing/clock.js.map +1 -0
  194. package/dist/testing/env.d.ts +66 -0
  195. package/dist/testing/env.d.ts.map +1 -0
  196. package/dist/testing/env.js +106 -0
  197. package/dist/testing/env.js.map +1 -0
  198. package/dist/testing/gate-runner.d.ts +141 -0
  199. package/dist/testing/gate-runner.d.ts.map +1 -0
  200. package/dist/testing/gate-runner.js +173 -0
  201. package/dist/testing/gate-runner.js.map +1 -0
  202. package/dist/testing/gf19.d.ts +106 -0
  203. package/dist/testing/gf19.d.ts.map +1 -0
  204. package/dist/testing/gf19.js +282 -0
  205. package/dist/testing/gf19.js.map +1 -0
  206. package/dist/testing/index.d.ts +20 -0
  207. package/dist/testing/index.d.ts.map +1 -0
  208. package/dist/testing/index.js +14 -0
  209. package/dist/testing/index.js.map +1 -0
  210. package/dist/testing/red-probe.d.ts +138 -0
  211. package/dist/testing/red-probe.d.ts.map +1 -0
  212. package/dist/testing/red-probe.js +251 -0
  213. package/dist/testing/red-probe.js.map +1 -0
  214. package/dist/testing/temp-repo.d.ts +126 -0
  215. package/dist/testing/temp-repo.d.ts.map +1 -0
  216. package/dist/testing/temp-repo.js +214 -0
  217. package/dist/testing/temp-repo.js.map +1 -0
  218. package/dist/verdict/cause.d.ts +99 -0
  219. package/dist/verdict/cause.d.ts.map +1 -0
  220. package/dist/verdict/cause.js +206 -0
  221. package/dist/verdict/cause.js.map +1 -0
  222. package/dist/verdict/evaluate.d.ts +135 -0
  223. package/dist/verdict/evaluate.d.ts.map +1 -0
  224. package/dist/verdict/evaluate.js +1513 -0
  225. package/dist/verdict/evaluate.js.map +1 -0
  226. package/dist/verdict/index.d.ts +21 -0
  227. package/dist/verdict/index.d.ts.map +1 -0
  228. package/dist/verdict/index.js +20 -0
  229. package/dist/verdict/index.js.map +1 -0
  230. package/dist/verdict/pack-verifiers.d.ts +97 -0
  231. package/dist/verdict/pack-verifiers.d.ts.map +1 -0
  232. package/dist/verdict/pack-verifiers.js +763 -0
  233. package/dist/verdict/pack-verifiers.js.map +1 -0
  234. package/dist/verdict/registry.d.ts +180 -0
  235. package/dist/verdict/registry.d.ts.map +1 -0
  236. package/dist/verdict/registry.js +67 -0
  237. package/dist/verdict/registry.js.map +1 -0
  238. package/dist/waivers/index.d.ts +103 -0
  239. package/dist/waivers/index.d.ts.map +1 -0
  240. package/dist/waivers/index.js +192 -0
  241. package/dist/waivers/index.js.map +1 -0
  242. package/package.json +40 -0
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Test-catalog schemas (plan 2026-09-13 §5.1 row 1 + §5.2): the derived
3
+ * inventory of a repository's existing tests.
4
+ *
5
+ * Identity rules (§5.2, hard):
6
+ * - The `logicalKey` is the stable manual-mapping identity: an explicit
7
+ * slug when a mapping declares one, otherwise deterministically derived
8
+ * from runner + project + repo-relative file + full title path
9
+ * ({@link deriveLogicalKey}).
10
+ * - Line numbers are DIAGNOSTICS, never identity: adding a comment keeps
11
+ * the logical key stable while `sourceDigest` changes.
12
+ * - Duplicate logical keys are a typed parse error listing BOTH sources —
13
+ * never "bind the first match".
14
+ *
15
+ * Discovery is data, not a gate result: `unresolved` entries and
16
+ * `parseErrors` are first-class catalog rows so a failed scan can never
17
+ * be misread as "no tests".
18
+ */
19
+ import { z } from 'zod';
20
+ import { LocationSchema, SchemaVersionField } from './common.js';
21
+ /** Runner names with an implemented adapter (plan phase 2 item 6). */
22
+ export const SUPPORTED_TEST_RUNNERS = ['playwright', 'pytest'];
23
+ /**
24
+ * A runner name. `playwright` and `pytest` are the adapters implemented
25
+ * so far; any other string is legal data (an adapter must exist before
26
+ * its entries drive gates — plan phase 2 item 6).
27
+ */
28
+ export const TestRunnerSchema = z.string().min(1);
29
+ /**
30
+ * What a test IS (plan §3.2). `unknown` is a kept, visible outcome.
31
+ *
32
+ * `server-e2e` (server-witnessed persistence channel) declares an
33
+ * existing test whose persistence evidence is witnessed SERVER-side:
34
+ * the engine's own adapter probe observes the app database directly,
35
+ * because the obligated state (e.g. a transactional outbox) can never
36
+ * honestly appear in a UI. Browser-kind tests never grade through it —
37
+ * the witness stamps the channel only for obligations registered
38
+ * `server-e2e` on the verifier-key supervisor surface, and the verdict
39
+ * engine admits `channel: 'server'` records only with that stamp.
40
+ */
41
+ export const TestKindSchema = z.enum([
42
+ 'browser-e2e',
43
+ 'server-e2e',
44
+ 'api-e2e',
45
+ 'unit',
46
+ 'integration',
47
+ 'component',
48
+ 'unknown',
49
+ ]);
50
+ /** Catalog row discovery status (plan §5.1 row 1). */
51
+ export const DiscoveryStatusSchema = z.enum(['discovered', 'unresolved', 'parse-error']);
52
+ /** Reconciliation outcome against the runner's native enumeration. */
53
+ export const ReconciliationStatusSchema = z.enum(['matched', 'static-only', 'list-only', 'unavailable']);
54
+ /** One inference rule that fired, with the code location that fed it. */
55
+ export const RuleEvidenceSchema = z
56
+ .object({
57
+ /** Stable rule id, e.g. `browser-fixture` or `category-keywords`. */
58
+ ruleId: z.string().min(1),
59
+ /** Single-cause explanation of what the rule observed. */
60
+ evidence: z.string().min(1),
61
+ /** Source location the rule's evidence came from. */
62
+ location: LocationSchema,
63
+ })
64
+ .strict();
65
+ /**
66
+ * A strong kind signal: a rule that proposes a {@link TestKind} with its
67
+ * code evidence. Conflicting proposals resolve to `unknown` — never to
68
+ * whichever rule ran last (plan phase 2 item 5: no opaque confidence).
69
+ */
70
+ export const KindSignalSchema = RuleEvidenceSchema.extend({
71
+ /** The kind this rule proposes. */
72
+ kind: TestKindSchema,
73
+ }).strict();
74
+ /**
75
+ * A weak signal (title/folder hints). Weak signals are recorded for the
76
+ * agent but must NEVER decide a kind by themselves (plan §3.2).
77
+ */
78
+ export const WeakSignalSchema = RuleEvidenceSchema.strict();
79
+ /**
80
+ * A behavior-category hint (plan §3.2): extensible dotted labels such as
81
+ * `persistence.create`. Hints only — a label never creates or satisfies
82
+ * a contract.
83
+ */
84
+ export const CategorySignalSchema = z
85
+ .object({
86
+ /** Dotted category label, e.g. `persistence.delete`. */
87
+ label: z.string().min(1),
88
+ /** The rule that produced the hint. */
89
+ ruleId: z.string().min(1),
90
+ /** Source location the hint came from. */
91
+ location: LocationSchema,
92
+ })
93
+ .strict();
94
+ /**
95
+ * Suppression/mock signals: skip, only, fixme, and known mock patterns.
96
+ * These qualify (and can disqualify) later proof; discovery only records
97
+ * them with locations (plan §3.2/§3.3).
98
+ */
99
+ export const SuppressionSignalKindSchema = z.enum(['skip', 'only', 'fixme', 'mock']);
100
+ /** One recorded suppression/mock signal with its location. */
101
+ export const SuppressionSignalSchema = z
102
+ .object({
103
+ kind: SuppressionSignalKindSchema,
104
+ /** Single-cause explanation, e.g. `test.skip modifier` or `page.route`. */
105
+ detail: z.string().min(1),
106
+ location: LocationSchema,
107
+ })
108
+ .strict();
109
+ /**
110
+ * One catalog row (plan §5.1 row 1): what test exists, plus the signals
111
+ * discovery gathered. Rows are NEVER dropped — an unresolvable call is
112
+ * a row with `discoveryStatus: 'unresolved'`, not an omission.
113
+ */
114
+ export const TestCatalogEntrySchema = z
115
+ .object({
116
+ /**
117
+ * Stable mapping identity (§5.2): explicit slug or the deterministic
118
+ * derivation of {@link deriveLogicalKey}. Unique across the catalog.
119
+ */
120
+ logicalKey: z.string().min(1),
121
+ /** Runner the test executes under, e.g. `playwright`. */
122
+ runner: TestRunnerSchema,
123
+ /**
124
+ * Runner project, e.g. `chromium`. `null` for rows no native
125
+ * enumeration has bound to a project yet (static-only rows).
126
+ */
127
+ project: z.string().min(1).nullable(),
128
+ /** Repo-root-relative posix path of the test file. */
129
+ file: z.string().min(1),
130
+ /** Full title path: enclosing describe titles, then the test title. */
131
+ titlePath: z.array(z.string().min(1)).min(1),
132
+ /** Last segment of {@link titlePath} (the test's own title). */
133
+ title: z.string().min(1),
134
+ /** Where the test is declared (file:startLine:startCol) — diagnostics. */
135
+ sourceLocation: LocationSchema,
136
+ /**
137
+ * Framework repeat/parameter identity, e.g. a `test.each` template
138
+ * slot or the native spec id. `null` when the case is not
139
+ * parameterized.
140
+ */
141
+ parameterIdentity: z.string().min(1).nullable(),
142
+ /** sha256 of the test file's bytes (stale-proof check input, §5.2). */
143
+ sourceDigest: z.string().regex(/^[0-9a-f]{64}$/, 'sourceDigest must be 64-char lowercase hex'),
144
+ /**
145
+ * Which enumeration resolved this row's identity (plan phase 2 item
146
+ * 4, static-first with native fallback): `'static'` when the static
147
+ * scan derived the case (the native list at most confirmed it);
148
+ * `'native-list'` when ONLY the runner's native enumeration produced
149
+ * it (the static scan could not or did not derive it). Absent for
150
+ * rows whose enumeration is neither (e.g. pytest collection).
151
+ * Honesty label: a `'native-list'` row's kind/category signals are
152
+ * necessarily weaker — its call-site facts were never read.
153
+ */
154
+ resolutionOrigin: z.enum(['static', 'native-list']).optional(),
155
+ discoveryStatus: DiscoveryStatusSchema,
156
+ /**
157
+ * Reconciliation verdict against the runner's native enumeration.
158
+ * `unavailable` = no native enumeration ran (e.g. no playwright
159
+ * config); recorded, not silent.
160
+ */
161
+ reconciliation: ReconciliationStatusSchema,
162
+ /** The kind inference concluded (default `unknown`; §3.2). */
163
+ inferredKind: TestKindSchema,
164
+ /** Strong kind rules that fired with their code evidence. */
165
+ kindSignals: z.array(KindSignalSchema),
166
+ /** Weak title/folder hints — never kind-deciding (§3.2). */
167
+ weakSignals: z.array(WeakSignalSchema),
168
+ /** Every inference rule that fired (rule id + source location). */
169
+ rulesFired: z.array(RuleEvidenceSchema),
170
+ /** Behavior-category hints (labels only, never proof; §3.2). */
171
+ categorySignals: z.array(CategorySignalSchema),
172
+ /** skip/only/fixme/mock signals with locations (§3.2). */
173
+ suppressionSignals: z.array(SuppressionSignalSchema),
174
+ /** Why the row is `unresolved` (required in that state). */
175
+ unresolvedReason: z
176
+ .object({ code: z.string().min(1), detail: z.string().min(1) })
177
+ .strict()
178
+ .optional(),
179
+ })
180
+ .strict()
181
+ .superRefine((entry, ctx) => {
182
+ if (entry.discoveryStatus === 'unresolved' && entry.unresolvedReason === undefined) {
183
+ ctx.addIssue({
184
+ code: 'custom',
185
+ path: ['discoveryStatus'],
186
+ message: "unresolved entries require 'unresolvedReason' (fail closed: an unexplained gap is not data)",
187
+ });
188
+ }
189
+ if (entry.discoveryStatus !== 'unresolved' && entry.unresolvedReason !== undefined) {
190
+ ctx.addIssue({
191
+ code: 'custom',
192
+ path: ['unresolvedReason'],
193
+ message: "'unresolvedReason' is only valid with discoveryStatus 'unresolved'",
194
+ });
195
+ }
196
+ if (entry.title !== entry.titlePath[entry.titlePath.length - 1]) {
197
+ ctx.addIssue({
198
+ code: 'custom',
199
+ path: ['title'],
200
+ message: "title must equal the last segment of titlePath",
201
+ });
202
+ }
203
+ });
204
+ /** One parser failure with its source location (never swallowed). */
205
+ export const CatalogParseErrorSchema = z
206
+ .object({
207
+ /** Repo-root-relative posix path of the file that failed to parse. */
208
+ file: z.string().min(1),
209
+ /** The parser's message, first line only (no stack dumps). */
210
+ message: z.string().min(1),
211
+ /** Where the parser failed. */
212
+ location: LocationSchema,
213
+ })
214
+ .strict();
215
+ /** One runner-level summary line (playwright reconciliation, pytest suites). */
216
+ export const RunnerSummarySchema = z
217
+ .object({
218
+ /** Runner the summary is about, e.g. `playwright` or `pytest`. */
219
+ runner: TestRunnerSchema,
220
+ /** Suite/config name (`playwright` for the native reconciliation). */
221
+ name: z.string().min(1),
222
+ /** `discovered` = enumerated; `registered` = configured, not collected. */
223
+ status: z.enum(['discovered', 'registered', 'unavailable']),
224
+ /** Single-cause human detail (e.g. why enumeration is unavailable). */
225
+ detail: z.string().min(1),
226
+ })
227
+ .strict();
228
+ /**
229
+ * The derived test catalog (plan §5.1). Every case is a row in
230
+ * `entries`; `unresolved` and `parseErrors` are the typed roll-ups of
231
+ * the rows needing attention. `inventoryComplete` captures scan
232
+ * completeness SEPARATELY from classification uncertainty: `unknown`
233
+ * kinds do not make an inventory incomplete, a failed scan does.
234
+ */
235
+ export const TestCatalogSchema = z
236
+ .object({
237
+ schemaVersion: SchemaVersionField,
238
+ /** Every discovered case, sorted by (file, titlePath, project). */
239
+ entries: z.array(TestCatalogEntrySchema),
240
+ /** Roll-up of entries with discoveryStatus `unresolved`. */
241
+ unresolved: z.array(z
242
+ .object({
243
+ /** Logical key of the corresponding entry row. */
244
+ logicalKey: z.string().min(1),
245
+ /** Stable reason code, e.g. `traversal-budget-exceeded`. */
246
+ code: z.string().min(1),
247
+ /** Single-cause human explanation. */
248
+ detail: z.string().min(1),
249
+ /** Call/import location the gap was detected at. */
250
+ location: LocationSchema,
251
+ })
252
+ .strict()),
253
+ /** Parser failures with locations — a failed scan is never "no tests". */
254
+ parseErrors: z.array(CatalogParseErrorSchema),
255
+ /** True only when every scan and reconciliation step completed. */
256
+ inventoryComplete: z.boolean(),
257
+ /** Per-runner status lines (native reconciliation, pytest suites). */
258
+ runnerSummaries: z.array(RunnerSummarySchema),
259
+ })
260
+ .strict()
261
+ .superRefine((catalog, ctx) => {
262
+ // §5.2: validate uniqueness — duplicate keys list BOTH sources, and
263
+ // never bind the first match.
264
+ const seen = new Map();
265
+ for (let index = 0; index < catalog.entries.length; index += 1) {
266
+ const entry = catalog.entries[index];
267
+ if (entry === undefined)
268
+ continue;
269
+ const previous = seen.get(entry.logicalKey);
270
+ if (previous !== undefined) {
271
+ ctx.addIssue({
272
+ code: 'custom',
273
+ path: ['entries', index, 'logicalKey'],
274
+ message: `duplicate logical key '${entry.logicalKey}' — sources: ` +
275
+ `${previous.file}:${String(previous.sourceLocation.line)} and ` +
276
+ `${entry.file}:${String(entry.sourceLocation.line)}`,
277
+ });
278
+ continue;
279
+ }
280
+ seen.set(entry.logicalKey, entry);
281
+ }
282
+ // The roll-up arrays must agree with the entry rows (a mismatch would
283
+ // let a consumer read "no unresolved" while a row says otherwise).
284
+ const unresolvedKeys = new Set(catalog.unresolved.map((entry) => entry.logicalKey));
285
+ for (const entry of catalog.entries) {
286
+ const inRollup = unresolvedKeys.has(entry.logicalKey);
287
+ if (entry.discoveryStatus === 'unresolved' && !inRollup) {
288
+ ctx.addIssue({
289
+ code: 'custom',
290
+ path: ['unresolved'],
291
+ message: `entry '${entry.logicalKey}' is unresolved but missing from the unresolved roll-up`,
292
+ });
293
+ }
294
+ }
295
+ });
296
+ /**
297
+ * Derives the deterministic logical key for a test (§5.2): runner,
298
+ * project (`-` when unbound), repo-relative file, then the full title
299
+ * path joined with `>`. Pure string shaping — stable across line moves
300
+ * and comment edits (line numbers are never identity input).
301
+ *
302
+ * Args:
303
+ * input: runner, project, file, and title path.
304
+ *
305
+ * Returns:
306
+ * string: e.g. `playwright:chromium:e2e/accounts.spec.ts:Accounts>creates an account`.
307
+ */
308
+ export function deriveLogicalKey(input) {
309
+ return `${input.runner}:${input.project ?? '-'}:${input.file}:${input.titlePath.join('>')}`;
310
+ }
311
+ //# sourceMappingURL=test-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-catalog.js","sourceRoot":"","sources":["../../src/schemas/test-catalog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Test-mapping sidecar schema (plan 2026-09-13 §5.3): the versioned
3
+ * `.gateforge/test-map.yml` document an agent (or `tests mark`) writes
4
+ * to connect an EXISTING test to obligations without rewriting a test
5
+ * body.
6
+ *
7
+ * One declaration model (§5.3): native `{type: 'gateforge'}` annotations
8
+ * and sidecar entries normalize through one resolver into the same claim
9
+ * surface — a sidecar entry DECLARES INTENT and supplies no test result
10
+ * or trusted evidence. Rules enforced here (fail closed):
11
+ * - every entry claims at least one obligation (`claims` non-empty);
12
+ * - claim ids must already look like obligation ids
13
+ * (`<resourceId>:<contract>`) — a `'*'` wildcard is not an obligation
14
+ * id and never parses;
15
+ * - `kind` must be a supported {@link TestKind} value when present;
16
+ * - `reason` is required free text (a declaration without a why is not
17
+ * reviewable);
18
+ * - duplicate entry keys are a typed parse error naming BOTH entries —
19
+ * never "bind the first match".
20
+ *
21
+ * YAML stays OUT of this module: the CLI parses `.gateforge/test-map.yml`
22
+ * with the repository's `yaml` dependency and passes the plain document
23
+ * here, so core speaks only validated data.
24
+ */
25
+ import { z } from 'zod';
26
+ /**
27
+ * Which existing test an entry declares (plan §5.3 selector). `titlePath`
28
+ * is part of the identity rules (§5.2): a selector WITHOUT one would
29
+ * cover a whole file — the resolver treats that as the prohibited
30
+ * wildcard (unsafe declaration), so honest entries always carry it.
31
+ */
32
+ export declare const TestSelectorSchema: z.ZodObject<{
33
+ runner: z.ZodString;
34
+ project: z.ZodOptional<z.ZodString>;
35
+ file: z.ZodString;
36
+ titlePath: z.ZodOptional<z.ZodArray<z.ZodString>>;
37
+ }, z.core.$strict>;
38
+ /** Inferred test-selector type. */
39
+ export type TestSelector = z.infer<typeof TestSelectorSchema>;
40
+ /**
41
+ * One sidecar mapping entry (plan §5.3): a stable logical key, the
42
+ * selector locating the existing test, the declared kind/categories, the
43
+ * claimed obligation ids, and the required human reason.
44
+ */
45
+ export declare const TestMapEntrySchema: z.ZodObject<{
46
+ key: z.ZodString;
47
+ selector: z.ZodObject<{
48
+ runner: z.ZodString;
49
+ project: z.ZodOptional<z.ZodString>;
50
+ file: z.ZodString;
51
+ titlePath: z.ZodOptional<z.ZodArray<z.ZodString>>;
52
+ }, z.core.$strict>;
53
+ kind: z.ZodOptional<z.ZodEnum<{
54
+ unknown: "unknown";
55
+ "browser-e2e": "browser-e2e";
56
+ "server-e2e": "server-e2e";
57
+ "api-e2e": "api-e2e";
58
+ unit: "unit";
59
+ integration: "integration";
60
+ component: "component";
61
+ }>>;
62
+ categories: z.ZodOptional<z.ZodArray<z.ZodString>>;
63
+ claims: z.ZodArray<z.ZodString>;
64
+ reason: z.ZodString;
65
+ }, z.core.$strict>;
66
+ /** Inferred test-map-entry type. */
67
+ export type TestMapEntry = z.infer<typeof TestMapEntrySchema>;
68
+ /**
69
+ * The `.gateforge/test-map.yml` document (plan §5.3): a tracked,
70
+ * versioned sidecar of mapping declarations. Duplicate keys fail the
71
+ * parse naming both entries' keys and selectors.
72
+ */
73
+ export declare const TestMapSchema: z.ZodObject<{
74
+ schemaVersion: z.ZodLiteral<1>;
75
+ tests: z.ZodArray<z.ZodObject<{
76
+ key: z.ZodString;
77
+ selector: z.ZodObject<{
78
+ runner: z.ZodString;
79
+ project: z.ZodOptional<z.ZodString>;
80
+ file: z.ZodString;
81
+ titlePath: z.ZodOptional<z.ZodArray<z.ZodString>>;
82
+ }, z.core.$strict>;
83
+ kind: z.ZodOptional<z.ZodEnum<{
84
+ unknown: "unknown";
85
+ "browser-e2e": "browser-e2e";
86
+ "server-e2e": "server-e2e";
87
+ "api-e2e": "api-e2e";
88
+ unit: "unit";
89
+ integration: "integration";
90
+ component: "component";
91
+ }>>;
92
+ categories: z.ZodOptional<z.ZodArray<z.ZodString>>;
93
+ claims: z.ZodArray<z.ZodString>;
94
+ reason: z.ZodString;
95
+ }, z.core.$strict>>;
96
+ }, z.core.$strict>;
97
+ /** Inferred test-map document type. */
98
+ export type TestMap = z.infer<typeof TestMapSchema>;
99
+ //# sourceMappingURL=test-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-map.d.ts","sourceRoot":"","sources":["../../src/schemas/test-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;kBAWpB,CAAC;AAEZ,mCAAmC;AACnC,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;kBAkBpB,CAAC;AAEZ,oCAAoC;AACpC,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;kBA4BtB,CAAC;AAEL,uCAAuC;AACvC,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Test-mapping sidecar schema (plan 2026-09-13 §5.3): the versioned
3
+ * `.gateforge/test-map.yml` document an agent (or `tests mark`) writes
4
+ * to connect an EXISTING test to obligations without rewriting a test
5
+ * body.
6
+ *
7
+ * One declaration model (§5.3): native `{type: 'gateforge'}` annotations
8
+ * and sidecar entries normalize through one resolver into the same claim
9
+ * surface — a sidecar entry DECLARES INTENT and supplies no test result
10
+ * or trusted evidence. Rules enforced here (fail closed):
11
+ * - every entry claims at least one obligation (`claims` non-empty);
12
+ * - claim ids must already look like obligation ids
13
+ * (`<resourceId>:<contract>`) — a `'*'` wildcard is not an obligation
14
+ * id and never parses;
15
+ * - `kind` must be a supported {@link TestKind} value when present;
16
+ * - `reason` is required free text (a declaration without a why is not
17
+ * reviewable);
18
+ * - duplicate entry keys are a typed parse error naming BOTH entries —
19
+ * never "bind the first match".
20
+ *
21
+ * YAML stays OUT of this module: the CLI parses `.gateforge/test-map.yml`
22
+ * with the repository's `yaml` dependency and passes the plain document
23
+ * here, so core speaks only validated data.
24
+ */
25
+ import { z } from 'zod';
26
+ import { SchemaVersionField } from './common.js';
27
+ import { ObligationIdSchema } from './claim.js';
28
+ import { TestKindSchema } from './test-catalog.js';
29
+ /**
30
+ * Which existing test an entry declares (plan §5.3 selector). `titlePath`
31
+ * is part of the identity rules (§5.2): a selector WITHOUT one would
32
+ * cover a whole file — the resolver treats that as the prohibited
33
+ * wildcard (unsafe declaration), so honest entries always carry it.
34
+ */
35
+ export const TestSelectorSchema = z
36
+ .object({
37
+ /** Runner the test executes under, e.g. `playwright`. */
38
+ runner: z.string().min(1),
39
+ /** Runner project, e.g. `chromium`. Absent = every project of the file/title. */
40
+ project: z.string().min(1).optional(),
41
+ /** Repo-root-relative posix path of the test file. */
42
+ file: z.string().min(1),
43
+ /** Full title path (describe stack, then the test title). */
44
+ titlePath: z.array(z.string().min(1)).optional(),
45
+ })
46
+ .strict();
47
+ /**
48
+ * One sidecar mapping entry (plan §5.3): a stable logical key, the
49
+ * selector locating the existing test, the declared kind/categories, the
50
+ * claimed obligation ids, and the required human reason.
51
+ */
52
+ export const TestMapEntrySchema = z
53
+ .object({
54
+ /** Stable logical key of the test (the catalog's `logicalKey`). */
55
+ key: z.string().min(1),
56
+ /** Selector locating the current test instance(s). */
57
+ selector: TestSelectorSchema,
58
+ /** Declared kind; resolves `unknown`, never observed mocking (§5.3). */
59
+ kind: TestKindSchema.optional(),
60
+ /** Behavior-category labels (hints only, never proof; §3.2). */
61
+ categories: z.array(z.string().min(1)).optional(),
62
+ /** Claimed obligation ids — at least one; `'*'` never parses. */
63
+ claims: z.array(ObligationIdSchema).min(1, 'every mapping entry must claim at least one obligation'),
64
+ /** Required free-text why (a declaration must be reviewable). */
65
+ reason: z
66
+ .string()
67
+ .trim()
68
+ .min(8, 'reason is required free text (at least 8 characters) explaining the declaration'),
69
+ })
70
+ .strict();
71
+ /**
72
+ * The `.gateforge/test-map.yml` document (plan §5.3): a tracked,
73
+ * versioned sidecar of mapping declarations. Duplicate keys fail the
74
+ * parse naming both entries' keys and selectors.
75
+ */
76
+ export const TestMapSchema = z
77
+ .object({
78
+ schemaVersion: SchemaVersionField,
79
+ /** Mapping declarations, unique by `key` (order is data, not identity). */
80
+ tests: z.array(TestMapEntrySchema),
81
+ })
82
+ .strict()
83
+ .superRefine((document, ctx) => {
84
+ // §5.2: validate uniqueness — duplicate keys list BOTH entries and
85
+ // never bind the first match.
86
+ const seen = new Map();
87
+ for (let index = 0; index < document.tests.length; index += 1) {
88
+ const entry = document.tests[index];
89
+ if (entry === undefined)
90
+ continue;
91
+ const previous = seen.get(entry.key);
92
+ if (previous !== undefined) {
93
+ ctx.addIssue({
94
+ code: 'custom',
95
+ path: ['tests', index, 'key'],
96
+ message: `duplicate sidecar key '${entry.key}' — entries at tests[${String(document.tests.indexOf(previous))}] (file ${previous.selector.file}) and tests[${String(index)}] (file ${entry.selector.file})`,
97
+ });
98
+ continue;
99
+ }
100
+ seen.set(entry.key, entry);
101
+ }
102
+ });
103
+ //# sourceMappingURL=test-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-map.js","sourceRoot":"","sources":["../../src/schemas/test-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Verdict + UnresolvedReason schemas (ADR 0001 seven verdicts, pin #5
3
+ * unresolved-entry shape). The pure evaluator itself lives in
4
+ * `src/verdict` (G3); these are the frozen data shapes it speaks.
5
+ */
6
+ import { z } from 'zod';
7
+ /**
8
+ * The seven verdicts. Blocking (non-clean) verdicts: `missing`,
9
+ * `invalid`, `unclassified`, `unresolved`, `stale`. Clean: `satisfied`,
10
+ * `waived`.
11
+ */
12
+ export declare const VerdictSchema: z.ZodEnum<{
13
+ satisfied: "satisfied";
14
+ missing: "missing";
15
+ invalid: "invalid";
16
+ unclassified: "unclassified";
17
+ unresolved: "unresolved";
18
+ waived: "waived";
19
+ stale: "stale";
20
+ }>;
21
+ /** Inferred verdict shape. */
22
+ export type Verdict = z.infer<typeof VerdictSchema>;
23
+ /** Machine-readable reason attached to `unresolved` verdicts. */
24
+ export declare const UnresolvedReasonSchema: z.ZodObject<{
25
+ code: z.ZodString;
26
+ detail: z.ZodString;
27
+ location: z.ZodObject<{
28
+ file: z.ZodString;
29
+ line: z.ZodNumber;
30
+ col: z.ZodNumber;
31
+ }, z.core.$strict>;
32
+ }, z.core.$strict>;
33
+ /** Inferred unresolved-reason shape. */
34
+ export type UnresolvedReason = z.infer<typeof UnresolvedReasonSchema>;
35
+ /**
36
+ * Stable cause codes for the shared report model (plan §5.4, ADR 0005).
37
+ * Blocking-obligation causes name WHY an obligation is not satisfied and
38
+ * select its next action; the three `DIAGNOSTIC_*` codes are advisory
39
+ * result causes for the separate diagnostic run (plan §3.5) — never
40
+ * obligation verdicts. The seven verdict VALUES are unchanged; causes
41
+ * enrich them without weakening any contract.
42
+ */
43
+ export declare const CauseCodeSchema: z.ZodEnum<{
44
+ TEST_INVENTORY_INCOMPLETE: "TEST_INVENTORY_INCOMPLETE";
45
+ TEST_KIND_UNKNOWN: "TEST_KIND_UNKNOWN";
46
+ TEST_MAPPING_MISSING: "TEST_MAPPING_MISSING";
47
+ TEST_MAPPING_AMBIGUOUS: "TEST_MAPPING_AMBIGUOUS";
48
+ TEST_MAPPING_STALE: "TEST_MAPPING_STALE";
49
+ EVIDENCE_NOT_COLLECTED: "EVIDENCE_NOT_COLLECTED";
50
+ VERIFIER_UNSUPPORTED: "VERIFIER_UNSUPPORTED";
51
+ TEST_NOT_EXECUTED: "TEST_NOT_EXECUTED";
52
+ TEST_FAILED: "TEST_FAILED";
53
+ RUN_INCOMPLETE: "RUN_INCOMPLETE";
54
+ EVIDENCE_STALE: "EVIDENCE_STALE";
55
+ CHANGE_UNMAPPED: "CHANGE_UNMAPPED";
56
+ EVIDENCE_SCOPE_INCOMPLETE: "EVIDENCE_SCOPE_INCOMPLETE";
57
+ ENFORCEMENT_UNTRUSTED: "ENFORCEMENT_UNTRUSTED";
58
+ EVIDENCE_VALUE_MISMATCH: "EVIDENCE_VALUE_MISMATCH";
59
+ SERVER_PROBE_UNAVAILABLE: "SERVER_PROBE_UNAVAILABLE";
60
+ CRUD_COVERAGE_MISSING: "CRUD_COVERAGE_MISSING";
61
+ DIAGNOSTIC_TEST_FAILURE: "DIAGNOSTIC_TEST_FAILURE";
62
+ DIAGNOSTIC_RUN_INCOMPLETE: "DIAGNOSTIC_RUN_INCOMPLETE";
63
+ DIAGNOSTIC_RESULT_STALE: "DIAGNOSTIC_RESULT_STALE";
64
+ }>;
65
+ /** Inferred cause-code union. */
66
+ export type CauseCode = z.infer<typeof CauseCodeSchema>;
67
+ /**
68
+ * The plan §5.4 next action per cause code. Text, JSON, and SARIF
69
+ * renderings all carry the same strings so every surface agrees on what
70
+ * to do next.
71
+ */
72
+ export declare const CAUSE_NEXT_ACTIONS: Readonly<Record<CauseCode, string>>;
73
+ //# sourceMappingURL=verdict.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../../src/schemas/verdict.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;EAQxB,CAAC;AAEH,8BAA8B;AAC9B,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAEpD,iEAAiE;AACjE,eAAO,MAAM,sBAAsB;;;;;;;;kBASxB,CAAC;AAEZ,wCAAwC;AACxC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;EAqB1B,CAAC;AAEH,iCAAiC;AACjC,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CA4BjE,CAAC"}