@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,523 @@
1
+ /**
2
+ * `.gateforge.yml` loading and validation (pin #6).
3
+ *
4
+ * Fail-closed by design: a missing file, unparsable YAML, an unknown
5
+ * `schemaVersion`, or any schema violation raises
6
+ * {@link GateforgeConfigError} carrying actionable diagnostics — each
7
+ * with the source file, a JSON path, and expected-vs-got detail.
8
+ * Exit code for this failure class is 2 (config/usage error).
9
+ */
10
+ import { readFileSync } from 'node:fs';
11
+ import { parse as parseYaml } from 'yaml';
12
+ import { SchemaVersionField, TransportSchema } from '../schemas/common.js';
13
+ import { CoveragePolicySchema } from '../schemas/coverage-policy.js';
14
+ import { z } from 'zod';
15
+ /**
16
+ * A plugin entry in `.gateforge.yml`. Unlike a run-manifest plugin
17
+ * registration, a config entry also declares HOW to launch the plugin:
18
+ * `subprocess` plugins get `command` (argv, run without network);
19
+ * `in-process` plugins get `module` (a TS module specifier).
20
+ */
21
+ export const ConfigPluginSchema = z
22
+ .object({
23
+ /** Plugin id, e.g. `gateforge.pack-sqlalchemy`. */
24
+ id: z.string().min(1),
25
+ /** Declared plugin version (handshake-checked at spawn, pin #5). */
26
+ version: z.string().min(1),
27
+ /** Transport over the plugin boundary (ADR 0002). */
28
+ transport: TransportSchema,
29
+ /** argv to spawn (subprocess transport only), executed with no network. */
30
+ command: z.array(z.string().min(1)).min(1).optional(),
31
+ /** Module specifier to import (in-process transport only). */
32
+ module: z.string().min(1).optional(),
33
+ })
34
+ .strict()
35
+ .superRefine((plugin, ctx) => {
36
+ // Issuer reservation (ADR 0003 D2/D6): `gateforge.core` is the
37
+ // ENGINE's suppressive-signal authority. A plugin configured under
38
+ // that id would let ordinary plugin output forge engine-issued
39
+ // declarations, so the id is reserved at config validation — the
40
+ // engine is not a configurable plugin.
41
+ if (plugin.id === 'gateforge.core') {
42
+ ctx.addIssue({
43
+ code: 'custom',
44
+ path: ['id'],
45
+ message: "plugin id 'gateforge.core' is reserved: suppressive classification authority is engine-issued, never plugin-issued",
46
+ });
47
+ }
48
+ if (plugin.transport === 'subprocess') {
49
+ if (plugin.command === undefined) {
50
+ ctx.addIssue({
51
+ code: 'custom',
52
+ path: ['command'],
53
+ message: `subprocess plugin '${plugin.id}' requires 'command' (argv to spawn)`,
54
+ });
55
+ }
56
+ if (plugin.module !== undefined) {
57
+ ctx.addIssue({
58
+ code: 'custom',
59
+ path: ['module'],
60
+ message: `subprocess plugin '${plugin.id}' must not declare 'module' (in-process only)`,
61
+ });
62
+ }
63
+ }
64
+ else {
65
+ if (plugin.module === undefined) {
66
+ ctx.addIssue({
67
+ code: 'custom',
68
+ path: ['module'],
69
+ message: `in-process plugin '${plugin.id}' requires 'module' (module specifier to import)`,
70
+ });
71
+ }
72
+ if (plugin.command !== undefined) {
73
+ ctx.addIssue({
74
+ code: 'custom',
75
+ path: ['command'],
76
+ message: `in-process plugin '${plugin.id}' must not declare 'command' (subprocess only)`,
77
+ });
78
+ }
79
+ }
80
+ });
81
+ /**
82
+ * Enforcement-mode configuration (plan 2026-09-13 §3.4/§3.3, ADR 0005
83
+ * D1/D4). OPTIONAL and off by default — enabling strict E2E is an
84
+ * explicit, tracked owner decision.
85
+ */
86
+ export const EnforcementConfigSchema = z
87
+ .object({
88
+ /**
89
+ * `standard` = local hook + mandatory trusted server check (honest
90
+ * about --no-verify); `managed` = authoritative commit broker outside
91
+ * the agent's write/process boundary. Later phases enforce this; the
92
+ * value is recorded here from Phase 0 on.
93
+ */
94
+ mode: z.enum(['standard', 'managed']).default('standard'),
95
+ /**
96
+ * Strict E2E mode (plan §3.3): when true, a waived or baselined
97
+ * in-scope E2E obligation is NOT proof and cannot authorize the
98
+ * change — the gate reports it blocking (ENFORCEMENT_UNTRUSTED), and
99
+ * required contracts whose proof channel is unavailable fail the
100
+ * setup closed (preflight capability validation).
101
+ */
102
+ strictE2E: z.boolean().default(false),
103
+ /**
104
+ * The OWNER-APPROVED policy revision digest (ADR 0005 D6 enforcement):
105
+ * the `trustedPolicyDigest` value the owner pinned as the approved
106
+ * policy revision. Gates compare the candidate's recomputed digest
107
+ * against it, so a candidate that edits classifiers, exclusions,
108
+ * waivers, baselines, or coverage cannot authorize its own weaker
109
+ * checks.
110
+ *
111
+ * TRUST BOUNDARY: this value must NEVER come from candidate-controlled
112
+ * files in strict mode. It is honored only when the config document
113
+ * carrying it lives OUTSIDE the candidate repository (loaded through
114
+ * the explicit `GATEFORGE_TRUSTED_CONFIG` path) or when the digest is
115
+ * provisioned through `GATEFORGE_APPROVED_POLICY_DIGEST` /
116
+ * `--approved-policy-digest`. Declaring it in the candidate's own
117
+ * `.gateforge.yml` is never a trusted source: strict gates block with
118
+ * ENFORCEMENT_UNTRUSTED instead of honoring it.
119
+ */
120
+ approvedPolicyDigest: z
121
+ .string()
122
+ .regex(/^[0-9a-f]{64}$/, 'approvedPolicyDigest must be 64-char lowercase hex')
123
+ .optional(),
124
+ })
125
+ .strict();
126
+ /**
127
+ * One configured diagnostic suite (plan 2026-09-13 §3.5, phase 2 item
128
+ * 8): an EXISTING suite the owner registers for the advisory "red means
129
+ * inspect this" alarm. Gateforge never discovers suites on its own — no
130
+ * directory scans, no executing commands found on disk; everything comes
131
+ * from this explicit, tracked configuration.
132
+ *
133
+ * Only `pytest` is accepted today: other runners stay explicitly
134
+ * unsupported until an adapter exists (plan phase 2 item 6) — a typo'd
135
+ * or aspirational runner name must fail the config load, not silently
136
+ * disable a suite.
137
+ */
138
+ export const DiagnosticSuiteSchema = z
139
+ .object({
140
+ /** Suite name used in reports and commands, e.g. `backend-pytest`. */
141
+ name: z.string().min(1),
142
+ /** The only runner with an adapter today (fail closed otherwise). */
143
+ runner: z.enum(['pytest']),
144
+ /** Repo-root-relative working directory the argv runs in. */
145
+ cwd: z.string().min(1),
146
+ /**
147
+ * Interpreter + args, e.g. `['python', '-m', 'pytest']`. The adapter
148
+ * appends collection/report flags; it never executes anything beyond
149
+ * this configured argv.
150
+ */
151
+ argv: z.array(z.string().min(1)).min(1),
152
+ /**
153
+ * Paths handed to the runner VERBATIM (suite-`cwd`-relative), e.g.
154
+ * `['tests']`. The adapter never widens them: gateforge never scans
155
+ * directories the owner did not name here.
156
+ */
157
+ testPaths: z.array(z.string().min(1)).min(1),
158
+ /** Finite wall-clock bound for one adapter invocation (seconds). */
159
+ timeoutMs: z.number().int().min(1),
160
+ })
161
+ .strict();
162
+ /**
163
+ * The `diagnostics` config section (plan §3.5): registered diagnostic
164
+ * suites. ABSENT = no diagnostic suites (the default; the alarm is
165
+ * opt-in and never a commit blocker by itself).
166
+ */
167
+ export const DiagnosticsConfigSchema = z
168
+ .object({
169
+ /** Explicitly registered diagnostic suites. */
170
+ suites: z.array(DiagnosticSuiteSchema),
171
+ })
172
+ .strict()
173
+ .superRefine((diagnostics, ctx) => {
174
+ // Duplicate suite names would make `tests diagnose --suite <name>`
175
+ // and per-suite reporting ambiguous — reject at config load.
176
+ const seen = new Set();
177
+ for (let index = 0; index < diagnostics.suites.length; index += 1) {
178
+ const name = diagnostics.suites[index]?.name;
179
+ if (name === undefined)
180
+ continue;
181
+ if (seen.has(name)) {
182
+ ctx.addIssue({
183
+ code: 'custom',
184
+ path: ['suites', index, 'name'],
185
+ message: `duplicate diagnostic suite name '${name}': suite selection must be unambiguous`,
186
+ });
187
+ }
188
+ seen.add(name);
189
+ }
190
+ });
191
+ /**
192
+ * The `.gateforge.yml` document schema (pin #6). All paths are
193
+ * repo-root-relative. Unknown keys are rejected — a typo must fail the
194
+ * config load, not silently disable a subsystem.
195
+ */
196
+ export const GateforgeConfigSchema = z
197
+ .object({
198
+ schemaVersion: SchemaVersionField,
199
+ /** Project-wide discovery settings. */
200
+ project: z
201
+ .object({
202
+ /** Languages detectors should run for, e.g. ['python']. */
203
+ languages: z.array(z.string().min(1)).min(1),
204
+ /** Path filters applied to discovery. */
205
+ paths: z
206
+ .object({
207
+ /** Globs to include. */
208
+ include: z.array(z.string().min(1)).min(1),
209
+ /** Globs to exclude. */
210
+ exclude: z.array(z.string().min(1)),
211
+ })
212
+ .strict(),
213
+ })
214
+ .strict(),
215
+ /** Plugin set: subprocess (GPP/3) and in-process detectors. */
216
+ plugins: z.array(ConfigPluginSchema),
217
+ /** Path to the policies YAML document. */
218
+ policies: z.string().min(1),
219
+ /**
220
+ * Path to the classification-policy YAML document (plan phase 5,
221
+ * ADR 0003 D5): repository-wide deterministic classification rules.
222
+ * Effective classifications are computed from detector signals on
223
+ * every run; there is no manual classifications document.
224
+ */
225
+ classificationPolicy: z.string().min(1),
226
+ /** Directory of reviewed evidence adapters (.mjs, engine-loaded). */
227
+ adapters: z.string().min(1),
228
+ /** Directory of waiver documents. */
229
+ waivers: z.string().min(1),
230
+ /** Path to the baseline document (`.gateforge/baselines/obligations.json`). */
231
+ baselines: z.string().min(1),
232
+ /** Changed-file provider selection (architecture contract 5). */
233
+ changed: z
234
+ .object({
235
+ provider: z.enum(['auto', 'local-staged', 'github-pr', 'gitlab-mr']),
236
+ })
237
+ .strict(),
238
+ /** Witness service bounds. */
239
+ witness: z
240
+ .object({
241
+ /** Upper bound for a single witness call, in seconds. */
242
+ maxDurationSeconds: z.number().int().min(1),
243
+ })
244
+ .strict(),
245
+ /** Clock selection: system time, or a fixed instant for determinism. */
246
+ clock: z
247
+ .object({
248
+ mode: z.enum(['system', 'fixed']),
249
+ /** Required with mode 'fixed'; meaningless otherwise (rejected). */
250
+ fixedAt: z.iso.datetime().optional(),
251
+ })
252
+ .strict()
253
+ .superRefine((clock, ctx) => {
254
+ if (clock.mode === 'fixed' && clock.fixedAt === undefined) {
255
+ ctx.addIssue({
256
+ code: 'custom',
257
+ path: ['fixedAt'],
258
+ message: "clock.mode 'fixed' requires 'fixedAt' (ISO-8601 instant)",
259
+ });
260
+ }
261
+ if (clock.mode === 'system' && clock.fixedAt !== undefined) {
262
+ ctx.addIssue({
263
+ code: 'custom',
264
+ path: ['fixedAt'],
265
+ message: "'fixedAt' is only valid with clock.mode 'fixed'",
266
+ });
267
+ }
268
+ }),
269
+ /**
270
+ * Enforcement modes (plan 2026-09-13 §3.3/§3.4, ADR 0005 D1/D4).
271
+ * ABSENT = feature off (standard mode, strict E2E off) so existing
272
+ * configs keep their exact behavior; enabling strict E2E is opt-in.
273
+ */
274
+ enforcement: EnforcementConfigSchema.optional(),
275
+ /**
276
+ * Closed-world CRUD coverage policy (plan 2026-09-13 §3.6, ADR 0005
277
+ * D5): tracked, owner-owned enumeration of user-facing tables with
278
+ * required operations and owner dispositions. ABSENT/empty = feature
279
+ * off (opt-in). Validated against the current run's resource
280
+ * inventory on every run when present.
281
+ */
282
+ coveragePolicy: CoveragePolicySchema.optional(),
283
+ /**
284
+ * Registered diagnostic suites (plan 2026-09-13 §3.5). ABSENT = no
285
+ * suites; the advisory alarm is opt-in via explicit, tracked
286
+ * configuration — gateforge never scans for or launches anything the
287
+ * owner did not register here.
288
+ */
289
+ diagnostics: DiagnosticsConfigSchema.optional(),
290
+ })
291
+ .strict();
292
+ /** Error raised for any fail-closed config problem. */
293
+ export class GateforgeConfigError extends Error {
294
+ /** All collected diagnostics (first is the primary cause). */
295
+ diagnostics;
296
+ /**
297
+ * Builds the error from diagnostics.
298
+ *
299
+ * Args:
300
+ * diagnostics: nonempty list of actionable diagnostics.
301
+ */
302
+ constructor(diagnostics) {
303
+ super(formatDiagnostics(diagnostics));
304
+ this.name = 'GateforgeConfigError';
305
+ this.diagnostics = diagnostics;
306
+ }
307
+ }
308
+ /**
309
+ * Renders a diagnostic input value compactly for `got` fields.
310
+ *
311
+ * Args:
312
+ * value: the offending value from the parsed document.
313
+ *
314
+ * Returns:
315
+ * string: single-line, length-capped rendering of the value.
316
+ */
317
+ function renderGot(value) {
318
+ let rendered;
319
+ if (typeof value === 'string') {
320
+ rendered = JSON.stringify(value);
321
+ }
322
+ else if (value === undefined) {
323
+ rendered = 'undefined';
324
+ }
325
+ else {
326
+ try {
327
+ rendered = JSON.stringify(value) ?? String(value);
328
+ }
329
+ catch {
330
+ rendered = String(value);
331
+ }
332
+ }
333
+ return rendered.length > 80 ? `${rendered.slice(0, 77)}...` : rendered;
334
+ }
335
+ /**
336
+ * Converts a zod issue path to a JSONPath-style string (`$.a.b[0]`).
337
+ *
338
+ * Args:
339
+ * path: zod issue path segments.
340
+ *
341
+ * Returns:
342
+ * string: JSON path with a leading `$`.
343
+ */
344
+ export function jsonPathFor(path) {
345
+ let out = '$';
346
+ for (const segment of path) {
347
+ out += typeof segment === 'number' ? `[${String(segment)}]` : `.${String(segment)}`;
348
+ }
349
+ return out;
350
+ }
351
+ /**
352
+ * Reads the offending value out of the original document by issue path.
353
+ * Zod v4 issues do not carry the rejected input, so we recover it here.
354
+ *
355
+ * Args:
356
+ * input: the original parsed document handed to the schema.
357
+ * path: zod issue path segments.
358
+ *
359
+ * Returns:
360
+ * unknown: the value at the path, or undefined when unreachable.
361
+ */
362
+ function valueAtPath(input, path) {
363
+ let current = input;
364
+ for (const segment of path) {
365
+ if (current === null || typeof current !== 'object') {
366
+ return undefined;
367
+ }
368
+ current = current[segment];
369
+ }
370
+ return current;
371
+ }
372
+ /**
373
+ * Extracts the "expected" detail from a zod issue when available:
374
+ * enum/literal issues carry `values`, type issues carry `expected`.
375
+ *
376
+ * Args:
377
+ * issue: the zod issue.
378
+ *
379
+ * Returns:
380
+ * string | undefined: rendered expectation, when the issue has one.
381
+ */
382
+ function expectedFromIssue(issue) {
383
+ const record = issue;
384
+ const values = record['values'];
385
+ if (Array.isArray(values) && values.length > 0) {
386
+ return values.map((value) => JSON.stringify(value)).join(' | ');
387
+ }
388
+ return typeof record['expected'] === 'string' ? record['expected'] : undefined;
389
+ }
390
+ /**
391
+ * Converts zod issues into actionable config diagnostics.
392
+ *
393
+ * Args:
394
+ * error: failed zod result error.
395
+ * file: file name to attach to every diagnostic.
396
+ * input: the original parsed document, used to recover got-values.
397
+ *
398
+ * Returns:
399
+ * ConfigDiagnostic[]: one diagnostic per issue, same order.
400
+ */
401
+ export function diagnosticsFromZodError(error, file, input) {
402
+ return error.issues.map((issue) => {
403
+ const gotValue = input === undefined ? undefined : valueAtPath(input, issue.path);
404
+ return {
405
+ file,
406
+ jsonPath: jsonPathFor(issue.path),
407
+ message: issue.message,
408
+ expected: expectedFromIssue(issue),
409
+ got: gotValue === undefined ? undefined : renderGot(gotValue),
410
+ };
411
+ });
412
+ }
413
+ /**
414
+ * Formats diagnostics into the multi-line message users see.
415
+ *
416
+ * Args:
417
+ * diagnostics: diagnostics to render.
418
+ *
419
+ * Returns:
420
+ * string: human-readable, single-cause-first listing.
421
+ */
422
+ export function formatDiagnostics(diagnostics) {
423
+ const head = diagnostics.length === 1
424
+ ? 'invalid gateforge config (1 error)'
425
+ : `invalid gateforge config (${String(diagnostics.length)} errors)`;
426
+ const lines = diagnostics.map((diagnostic) => {
427
+ const parts = [diagnostic.file, diagnostic.jsonPath, diagnostic.message];
428
+ if (diagnostic.expected !== undefined) {
429
+ parts.push(`expected: ${diagnostic.expected}`);
430
+ }
431
+ if (diagnostic.got !== undefined) {
432
+ parts.push(`got: ${diagnostic.got}`);
433
+ }
434
+ return ` - ${parts.filter((part) => part.length > 0).join(': ')}`;
435
+ });
436
+ return [head, ...lines].join('\n');
437
+ }
438
+ /**
439
+ * Validates an already-parsed config document against the schema.
440
+ *
441
+ * Args:
442
+ * input: parsed YAML/JSON document (an unknown value).
443
+ * file: source file name for diagnostics (default '<inline>').
444
+ *
445
+ * Returns:
446
+ * GateforgeConfig: the validated config.
447
+ *
448
+ * Raises:
449
+ * GateforgeConfigError: on any schema violation, including unknown
450
+ * schemaVersion (never migrated) and unknown keys (typos fail loud).
451
+ */
452
+ export function parseConfig(input, { file = '<inline>' } = {}) {
453
+ // Migration diagnostic (plan phase 5): the authoritative manual
454
+ // classifications document was removed in the automatic-classification
455
+ // cutover. Fail with the exact migration steps, never a generic
456
+ // unknown-key error.
457
+ if (input !== null && typeof input === 'object' && 'classifications' in input) {
458
+ throw new GateforgeConfigError([
459
+ {
460
+ file,
461
+ jsonPath: '$.classifications',
462
+ message: "config key 'classifications' was removed: classification is now automatic. " +
463
+ "Delete the key and add `classificationPolicy: .gateforge/classification-policy.yml` " +
464
+ '(create it with `gateforge init`); its scanRoots gate every closed-world proof. ' +
465
+ 'Per-resource entries became `gateforge classify --write-snapshot` output ' +
466
+ '(a derived artifact — never authoritative input) or source declarations.',
467
+ },
468
+ ]);
469
+ }
470
+ const result = GateforgeConfigSchema.safeParse(input);
471
+ if (result.success) {
472
+ return result.data;
473
+ }
474
+ throw new GateforgeConfigError(diagnosticsFromZodError(result.error, file, input));
475
+ }
476
+ /**
477
+ * Loads and validates `.gateforge.yml` from disk. Fail-closed: a missing
478
+ * file, unparsable YAML, or schema violations all raise
479
+ * {@link GateforgeConfigError} with actionable diagnostics.
480
+ *
481
+ * Args:
482
+ * path: config file path (default '.gateforge.yml').
483
+ *
484
+ * Returns:
485
+ * GateforgeConfig: the validated config.
486
+ *
487
+ * Raises:
488
+ * GateforgeConfigError: for missing/unreadable/unparsable/invalid config.
489
+ */
490
+ export function loadConfig(path = '.gateforge.yml') {
491
+ let raw;
492
+ try {
493
+ raw = readFileSync(path, 'utf8');
494
+ }
495
+ catch (cause) {
496
+ const code = cause.code ?? 'UNKNOWN';
497
+ const hint = code === 'ENOENT'
498
+ ? 'run the init command or pass an explicit config path'
499
+ : 'check file permissions';
500
+ throw new GateforgeConfigError([
501
+ {
502
+ file: path,
503
+ jsonPath: '$',
504
+ message: `cannot read config file (${code}); ${hint}`,
505
+ },
506
+ ]);
507
+ }
508
+ let document;
509
+ try {
510
+ document = parseYaml(raw);
511
+ }
512
+ catch (cause) {
513
+ throw new GateforgeConfigError([
514
+ {
515
+ file: path,
516
+ jsonPath: '$',
517
+ message: `invalid YAML: ${cause.message.split('\n')[0] ?? 'parse error'}`,
518
+ },
519
+ ]);
520
+ }
521
+ return parseConfig(document, { file: path });
522
+ }
523
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,CAAC;IACN,mDAAmD;IACnD,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,oEAAoE;IACpE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,qDAAqD;IACrD,SAAS,EAAE,eAAe;IAC1B,2EAA2E;IAC3E,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACrD,8DAA8D;IAC9D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;CACrC,CAAC;KACD,MAAM,EAAE;KACR,WAAW,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;IAC3B,+DAA+D;IAC/D,mEAAmE;IACnE,+DAA+D;IAC/D,iEAAiE;IACjE,uCAAuC;IACvC,IAAI,MAAM,CAAC,EAAE,KAAK,gBAAgB,EAAE,CAAC;QACnC,GAAG,CAAC,QAAQ,CAAC;YACX,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,CAAC,IAAI,CAAC;YACZ,OAAO,EACL,oHAAoH;SACvH,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,KAAK,YAAY,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,CAAC;gBACjB,OAAO,EAAE,sBAAsB,MAAM,CAAC,EAAE,sCAAsC;aAC/E,CAAC,CAAC;QACL,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,QAAQ,CAAC;gBAChB,OAAO,EAAE,sBAAsB,MAAM,CAAC,EAAE,+CAA+C;aACxF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChC,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,QAAQ,CAAC;gBAChB,OAAO,EAAE,sBAAsB,MAAM,CAAC,EAAE,kDAAkD;aAC3F,CAAC,CAAC;QACL,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACjC,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,CAAC;gBACjB,OAAO,EAAE,sBAAsB,MAAM,CAAC,EAAE,gDAAgD;aACzF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAKL;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC;KACrC,MAAM,CAAC;IACN;;;;;OAKG;IACH,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IACzD;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IACrC;;;;;;;;;;;;;;;;OAgBG;IACH,oBAAoB,EAAE,CAAC;SACpB,MAAM,EAAE;SACR,KAAK,CAAC,gBAAgB,EAAE,oDAAoD,CAAC;SAC7E,QAAQ,EAAE;CACd,CAAC;KACD,MAAM,EAAE,CAAC;AAKZ;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,MAAM,CAAC;IACN,sEAAsE;IACtE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,qEAAqE;IACrE,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1B,6DAA6D;IAC7D,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB;;;;OAIG;IACH,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC;;;;OAIG;IACH,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,oEAAoE;IACpE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACnC,CAAC;KACD,MAAM,EAAE,CAAC;AAKZ;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC;KACrC,MAAM,CAAC;IACN,+CAA+C;IAC/C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,qBAAqB,CAAC;CACvC,CAAC;KACD,MAAM,EAAE;KACR,WAAW,CAAC,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE;IAChC,mEAAmE;IACnE,6DAA6D;IAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;QAC7C,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnB,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC;gBAC/B,OAAO,EAAE,oCAAoC,IAAI,wCAAwC;aAC1F,CAAC,CAAC;QACL,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjB,CAAC;AACH,CAAC,CAAC,CAAC;AAKL;;;;GAIG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC;KACnC,MAAM,CAAC;IACN,aAAa,EAAE,kBAAkB;IACjC,uCAAuC;IACvC,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,2DAA2D;QAC3D,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,yCAAyC;QACzC,KAAK,EAAE,CAAC;aACL,MAAM,CAAC;YACN,wBAAwB;YACxB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1C,wBAAwB;YACxB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;SACpC,CAAC;aACD,MAAM,EAAE;KACZ,CAAC;SACD,MAAM,EAAE;IACX,+DAA+D;IAC/D,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;IACpC,0CAA0C;IAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B;;;;;OAKG;IACH,oBAAoB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvC,qEAAqE;IACrE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,qCAAqC;IACrC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,+EAA+E;IAC/E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,iEAAiE;IACjE,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;KACrE,CAAC;SACD,MAAM,EAAE;IACX,8BAA8B;IAC9B,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,yDAAyD;QACzD,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC5C,CAAC;SACD,MAAM,EAAE;IACX,wEAAwE;IACxE,KAAK,EAAE,CAAC;SACL,MAAM,CAAC;QACN,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjC,oEAAoE;QACpE,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;KACrC,CAAC;SACD,MAAM,EAAE;SACR,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC1B,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1D,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,CAAC;gBACjB,OAAO,EAAE,0DAA0D;aACpE,CAAC,CAAC;QACL,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC3D,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,SAAS,CAAC;gBACjB,OAAO,EAAE,iDAAiD;aAC3D,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;IACJ;;;;OAIG;IACH,WAAW,EAAE,uBAAuB,CAAC,QAAQ,EAAE;IAC/C;;;;;;OAMG;IACH,cAAc,EAAE,oBAAoB,CAAC,QAAQ,EAAE;IAC/C;;;;;OAKG;IACH,WAAW,EAAE,uBAAuB,CAAC,QAAQ,EAAE;CAChD,CAAC;KACD,MAAM,EAAE,CAAC;AAqBZ,uDAAuD;AACvD,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,8DAA8D;IACrD,WAAW,CAAqB;IAEzC;;;;;OAKG;IACH,YAAY,WAA+B;QACzC,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IACjC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,QAAgB,CAAC;IACrB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,QAAQ,GAAG,WAAW,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACzE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,IAAmB;IAC7C,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;QAC3B,GAAG,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,WAAW,CAAC,KAAc,EAAE,IAAmB;IACtD,IAAI,OAAO,GAAY,KAAK,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,IAAI,EAAE,CAAC;QAC3B,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YACpD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,GAAI,OAAwC,CAAC,OAAO,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,iBAAiB,CAAC,KAAiB;IAC1C,MAAM,MAAM,GAAG,KAA2C,CAAC;IAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjF,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAiB,EACjB,IAAY,EACZ,KAAe;IAEf,OAAO,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAChC,MAAM,QAAQ,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAClF,OAAO;YACL,IAAI;YACJ,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC;YACjC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,QAAQ,EAAE,iBAAiB,CAAC,KAAK,CAAC;YAClC,GAAG,EAAE,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC;SAC9D,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAA+B;IAC/D,MAAM,IAAI,GACR,WAAW,CAAC,MAAM,KAAK,CAAC;QACtB,CAAC,CAAC,oCAAoC;QACtC,CAAC,CAAC,6BAA6B,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;IACxE,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;QACzE,IAAI,UAAU,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,aAAa,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,UAAU,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC,QAAQ,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACrE,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CACzB,KAAc,EACd,EAAE,IAAI,GAAG,UAAU,KAAwB,EAAE;IAE7C,gEAAgE;IAChE,uEAAuE;IACvE,gEAAgE;IAChE,qBAAqB;IACrB,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,iBAAiB,IAAI,KAAK,EAAE,CAAC;QAC9E,MAAM,IAAI,oBAAoB,CAAC;YAC7B;gBACE,IAAI;gBACJ,QAAQ,EAAE,mBAAmB;gBAC7B,OAAO,EACL,6EAA6E;oBAC7E,sFAAsF;oBACtF,kFAAkF;oBAClF,2EAA2E;oBAC3E,0EAA0E;aAC7E;SACF,CAAC,CAAC;IACL,CAAC;IACD,MAAM,MAAM,GAAG,qBAAqB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;IACD,MAAM,IAAI,oBAAoB,CAAC,uBAAuB,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,UAAU,CAAC,IAAI,GAAG,gBAAgB;IAChD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,IAAI,SAAS,CAAC;QAChE,MAAM,IAAI,GACR,IAAI,KAAK,QAAQ;YACf,CAAC,CAAC,sDAAsD;YACxD,CAAC,CAAC,wBAAwB,CAAC;QAC/B,MAAM,IAAI,oBAAoB,CAAC;YAC7B;gBACE,IAAI,EAAE,IAAI;gBACV,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,4BAA4B,IAAI,MAAM,IAAI,EAAE;aACtD;SACF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QACH,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,oBAAoB,CAAC;YAC7B;gBACE,IAAI,EAAE,IAAI;gBACV,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,iBAAkB,KAAe,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,aAAa,EAAE;aACrF;SACF,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Obligation fingerprint (pin #2): the stable identity a baseline stores.
3
+ *
4
+ * `fingerprint(obligation-ish) = sha256(GF-canonical-JSON of
5
+ * {resourceId, contract, policyId, lifecycle})` where `lifecycle` is the
6
+ * classification lifecycle relevant to that contract. Key order in the
7
+ * input is irrelevant — canonical JSON sorts keys before hashing.
8
+ */
9
+ import { z } from 'zod';
10
+ import { type BlockingEntry } from './policy/evaluate.js';
11
+ /** Exactly the identity fields hashed into an obligation fingerprint. */
12
+ export declare const FingerprintInputSchema: z.ZodObject<{
13
+ resourceId: z.ZodString;
14
+ contract: z.ZodString;
15
+ policyId: z.ZodString;
16
+ lifecycle: z.ZodObject<{
17
+ create: z.ZodBoolean;
18
+ read: z.ZodBoolean;
19
+ update: z.ZodBoolean;
20
+ delete: z.ZodBoolean;
21
+ deleteSemantics: z.ZodOptional<z.ZodEnum<{
22
+ hard: "hard";
23
+ archive: "archive";
24
+ }>>;
25
+ archiveFields: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
26
+ updateableFields: z.ZodOptional<z.ZodArray<z.ZodString>>;
27
+ }, z.core.$strict>;
28
+ }, z.core.$strict>;
29
+ /** Inferred fingerprint-input shape. */
30
+ export type FingerprintInput = z.infer<typeof FingerprintInputSchema>;
31
+ /**
32
+ * Computes the obligation fingerprint (pin #2).
33
+ *
34
+ * Args:
35
+ * input: the obligation identity — resourceId, contract, policyId,
36
+ * and the relevant lifecycle attributes.
37
+ *
38
+ * Returns:
39
+ * string: 64-char lowercase sha256 hex over the GF-canonical-JSON of
40
+ * the identity object. Stable across key order and process runs.
41
+ */
42
+ export declare function fingerprint(input: FingerprintInput): string;
43
+ /**
44
+ * The BLOCKING-ENTRY fingerprint (phase 8 workstream C): the stable
45
+ * identity a baseline stores for gate red that is not an obligation —
46
+ * unclassified/unresolved resources, detector/graph findings, and stale
47
+ * references. sha256 over the GF-canonical-JSON of the whole entry
48
+ * (kind, resourceId, name, detail, location): any change to the cause —
49
+ * including wording or location of the underlying problem — mints a NEW
50
+ * fingerprint, which the baseline does not contain, which blocks again.
51
+ * That is the fail-closed direction: the adoption baseline forgives the
52
+ * debt exactly as it stood at adoption; anything that shifts must be
53
+ * re-proven, never re-forgiven (the baseline is shrink-only).
54
+ */
55
+ export declare function blockingEntryFingerprint(entry: BlockingEntry): string;
56
+ //# sourceMappingURL=fingerprints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprints.d.ts","sourceRoot":"","sources":["../src/fingerprints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE/E,yEAAyE;AACzE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;kBAcxB,CAAC;AAEZ,wCAAwC;AACxC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAE3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAErE"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Obligation fingerprint (pin #2): the stable identity a baseline stores.
3
+ *
4
+ * `fingerprint(obligation-ish) = sha256(GF-canonical-JSON of
5
+ * {resourceId, contract, policyId, lifecycle})` where `lifecycle` is the
6
+ * classification lifecycle relevant to that contract. Key order in the
7
+ * input is irrelevant — canonical JSON sorts keys before hashing.
8
+ */
9
+ import { z } from 'zod';
10
+ import { sha256Canonical } from './canonical-json.js';
11
+ import { ContractNameSchema } from './schemas/common.js';
12
+ import { LifecycleSchema } from './schemas/classification.js';
13
+ import { BlockingEntrySchema } from './policy/evaluate.js';
14
+ /** Exactly the identity fields hashed into an obligation fingerprint. */
15
+ export const FingerprintInputSchema = z
16
+ .object({
17
+ /** Resource the obligation attaches to (no colons). */
18
+ resourceId: z
19
+ .string()
20
+ .min(1)
21
+ .regex(/^[^:]+$/, "resourceId must not contain ':'"),
22
+ /** Contract name, e.g. `crud:update`. */
23
+ contract: ContractNameSchema,
24
+ /** Policy id that generated the obligation. */
25
+ policyId: z.string().min(1),
26
+ /** Classification lifecycle attributes relevant to the contract. */
27
+ lifecycle: LifecycleSchema,
28
+ })
29
+ .strict();
30
+ /**
31
+ * Computes the obligation fingerprint (pin #2).
32
+ *
33
+ * Args:
34
+ * input: the obligation identity — resourceId, contract, policyId,
35
+ * and the relevant lifecycle attributes.
36
+ *
37
+ * Returns:
38
+ * string: 64-char lowercase sha256 hex over the GF-canonical-JSON of
39
+ * the identity object. Stable across key order and process runs.
40
+ */
41
+ export function fingerprint(input) {
42
+ return sha256Canonical(FingerprintInputSchema.parse(input));
43
+ }
44
+ /**
45
+ * The BLOCKING-ENTRY fingerprint (phase 8 workstream C): the stable
46
+ * identity a baseline stores for gate red that is not an obligation —
47
+ * unclassified/unresolved resources, detector/graph findings, and stale
48
+ * references. sha256 over the GF-canonical-JSON of the whole entry
49
+ * (kind, resourceId, name, detail, location): any change to the cause —
50
+ * including wording or location of the underlying problem — mints a NEW
51
+ * fingerprint, which the baseline does not contain, which blocks again.
52
+ * That is the fail-closed direction: the adoption baseline forgives the
53
+ * debt exactly as it stood at adoption; anything that shifts must be
54
+ * re-proven, never re-forgiven (the baseline is shrink-only).
55
+ */
56
+ export function blockingEntryFingerprint(entry) {
57
+ return sha256Canonical(BlockingEntrySchema.parse(entry));
58
+ }
59
+ //# sourceMappingURL=fingerprints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprints.js","sourceRoot":"","sources":["../src/fingerprints.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAsB,MAAM,sBAAsB,CAAC;AAE/E,yEAAyE;AACzE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC;KACpC,MAAM,CAAC;IACN,uDAAuD;IACvD,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,KAAK,CAAC,SAAS,EAAE,iCAAiC,CAAC;IACtD,yCAAyC;IACzC,QAAQ,EAAE,kBAAkB;IAC5B,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,oEAAoE;IACpE,SAAS,EAAE,eAAe;CAC3B,CAAC;KACD,MAAM,EAAE,CAAC;AAKZ;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IACjD,OAAO,eAAe,CAAC,sBAAsB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAoB;IAC3D,OAAO,eAAe,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3D,CAAC"}