@veraxhq/verax 0.2.0 → 0.3.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 (217) hide show
  1. package/README.md +14 -18
  2. package/bin/verax.js +7 -0
  3. package/package.json +15 -5
  4. package/src/cli/commands/baseline.js +104 -0
  5. package/src/cli/commands/default.js +323 -111
  6. package/src/cli/commands/doctor.js +36 -4
  7. package/src/cli/commands/ga.js +243 -0
  8. package/src/cli/commands/gates.js +95 -0
  9. package/src/cli/commands/inspect.js +131 -2
  10. package/src/cli/commands/release-check.js +213 -0
  11. package/src/cli/commands/run.js +498 -103
  12. package/src/cli/commands/security-check.js +211 -0
  13. package/src/cli/commands/truth.js +114 -0
  14. package/src/cli/entry.js +305 -68
  15. package/src/cli/util/angular-component-extractor.js +179 -0
  16. package/src/cli/util/angular-navigation-detector.js +141 -0
  17. package/src/cli/util/angular-network-detector.js +161 -0
  18. package/src/cli/util/angular-state-detector.js +162 -0
  19. package/src/cli/util/ast-interactive-detector.js +546 -0
  20. package/src/cli/util/ast-network-detector.js +603 -0
  21. package/src/cli/util/ast-usestate-detector.js +602 -0
  22. package/src/cli/util/bootstrap-guard.js +86 -0
  23. package/src/cli/util/detection-engine.js +4 -3
  24. package/src/cli/util/determinism-runner.js +123 -0
  25. package/src/cli/util/determinism-writer.js +129 -0
  26. package/src/cli/util/env-url.js +4 -0
  27. package/src/cli/util/events.js +76 -0
  28. package/src/cli/util/expectation-extractor.js +380 -74
  29. package/src/cli/util/findings-writer.js +126 -15
  30. package/src/cli/util/learn-writer.js +3 -1
  31. package/src/cli/util/observation-engine.js +69 -23
  32. package/src/cli/util/observe-writer.js +3 -1
  33. package/src/cli/util/paths.js +6 -14
  34. package/src/cli/util/project-discovery.js +23 -0
  35. package/src/cli/util/project-writer.js +3 -1
  36. package/src/cli/util/redact.js +2 -2
  37. package/src/cli/util/run-resolver.js +64 -0
  38. package/src/cli/util/runtime-budget.js +147 -0
  39. package/src/cli/util/source-requirement.js +55 -0
  40. package/src/cli/util/summary-writer.js +13 -1
  41. package/src/cli/util/svelte-navigation-detector.js +163 -0
  42. package/src/cli/util/svelte-network-detector.js +80 -0
  43. package/src/cli/util/svelte-sfc-extractor.js +147 -0
  44. package/src/cli/util/svelte-state-detector.js +243 -0
  45. package/src/cli/util/vue-navigation-detector.js +177 -0
  46. package/src/cli/util/vue-sfc-extractor.js +162 -0
  47. package/src/cli/util/vue-state-detector.js +215 -0
  48. package/src/types/global.d.ts +28 -0
  49. package/src/types/ts-ast.d.ts +24 -0
  50. package/src/verax/cli/doctor.js +2 -2
  51. package/src/verax/cli/finding-explainer.js +56 -3
  52. package/src/verax/cli/init.js +1 -1
  53. package/src/verax/cli/url-safety.js +12 -2
  54. package/src/verax/cli/wizard.js +13 -2
  55. package/src/verax/core/artifacts/registry.js +154 -0
  56. package/src/verax/core/artifacts/verifier.js +980 -0
  57. package/src/verax/core/baseline/baseline.enforcer.js +137 -0
  58. package/src/verax/core/baseline/baseline.snapshot.js +231 -0
  59. package/src/verax/core/budget-engine.js +1 -1
  60. package/src/verax/core/capabilities/gates.js +499 -0
  61. package/src/verax/core/capabilities/registry.js +475 -0
  62. package/src/verax/core/confidence/confidence-compute.js +137 -0
  63. package/src/verax/core/confidence/confidence-invariants.js +234 -0
  64. package/src/verax/core/confidence/confidence-report-writer.js +112 -0
  65. package/src/verax/core/confidence/confidence-weights.js +44 -0
  66. package/src/verax/core/confidence/confidence.defaults.js +65 -0
  67. package/src/verax/core/confidence/confidence.loader.js +79 -0
  68. package/src/verax/core/confidence/confidence.schema.js +94 -0
  69. package/src/verax/core/confidence-engine-refactor.js +484 -0
  70. package/src/verax/core/confidence-engine.js +486 -0
  71. package/src/verax/core/confidence-engine.js.backup +471 -0
  72. package/src/verax/core/contracts/index.js +29 -0
  73. package/src/verax/core/contracts/types.js +185 -0
  74. package/src/verax/core/contracts/validators.js +381 -0
  75. package/src/verax/core/decision-snapshot.js +31 -4
  76. package/src/verax/core/decisions/decision.trace.js +276 -0
  77. package/src/verax/core/determinism/contract-writer.js +89 -0
  78. package/src/verax/core/determinism/contract.js +139 -0
  79. package/src/verax/core/determinism/diff.js +364 -0
  80. package/src/verax/core/determinism/engine.js +221 -0
  81. package/src/verax/core/determinism/finding-identity.js +148 -0
  82. package/src/verax/core/determinism/normalize.js +438 -0
  83. package/src/verax/core/determinism/report-writer.js +92 -0
  84. package/src/verax/core/determinism/run-fingerprint.js +118 -0
  85. package/src/verax/core/determinism-model.js +35 -6
  86. package/src/verax/core/dynamic-route-intelligence.js +528 -0
  87. package/src/verax/core/evidence/evidence-capture-service.js +307 -0
  88. package/src/verax/core/evidence/evidence-intent-ledger.js +165 -0
  89. package/src/verax/core/evidence-builder.js +487 -0
  90. package/src/verax/core/execution-mode-context.js +77 -0
  91. package/src/verax/core/execution-mode-detector.js +190 -0
  92. package/src/verax/core/failures/exit-codes.js +86 -0
  93. package/src/verax/core/failures/failure-summary.js +76 -0
  94. package/src/verax/core/failures/failure.factory.js +225 -0
  95. package/src/verax/core/failures/failure.ledger.js +132 -0
  96. package/src/verax/core/failures/failure.types.js +196 -0
  97. package/src/verax/core/failures/index.js +10 -0
  98. package/src/verax/core/ga/ga-report-writer.js +43 -0
  99. package/src/verax/core/ga/ga.artifact.js +49 -0
  100. package/src/verax/core/ga/ga.contract.js +434 -0
  101. package/src/verax/core/ga/ga.enforcer.js +86 -0
  102. package/src/verax/core/guardrails/guardrails-report-writer.js +109 -0
  103. package/src/verax/core/guardrails/policy.defaults.js +210 -0
  104. package/src/verax/core/guardrails/policy.loader.js +83 -0
  105. package/src/verax/core/guardrails/policy.schema.js +110 -0
  106. package/src/verax/core/guardrails/truth-reconciliation.js +136 -0
  107. package/src/verax/core/guardrails-engine.js +505 -0
  108. package/src/verax/core/incremental-store.js +15 -7
  109. package/src/verax/core/observe/run-timeline.js +316 -0
  110. package/src/verax/core/perf/perf.contract.js +186 -0
  111. package/src/verax/core/perf/perf.display.js +65 -0
  112. package/src/verax/core/perf/perf.enforcer.js +91 -0
  113. package/src/verax/core/perf/perf.monitor.js +209 -0
  114. package/src/verax/core/perf/perf.report.js +198 -0
  115. package/src/verax/core/pipeline-tracker.js +238 -0
  116. package/src/verax/core/product-definition.js +127 -0
  117. package/src/verax/core/release/provenance.builder.js +271 -0
  118. package/src/verax/core/release/release-report-writer.js +40 -0
  119. package/src/verax/core/release/release.enforcer.js +159 -0
  120. package/src/verax/core/release/reproducibility.check.js +221 -0
  121. package/src/verax/core/release/sbom.builder.js +283 -0
  122. package/src/verax/core/replay-validator.js +4 -4
  123. package/src/verax/core/replay.js +1 -1
  124. package/src/verax/core/report/cross-index.js +192 -0
  125. package/src/verax/core/report/human-summary.js +222 -0
  126. package/src/verax/core/route-intelligence.js +419 -0
  127. package/src/verax/core/security/secrets.scan.js +326 -0
  128. package/src/verax/core/security/security-report.js +50 -0
  129. package/src/verax/core/security/security.enforcer.js +124 -0
  130. package/src/verax/core/security/supplychain.defaults.json +38 -0
  131. package/src/verax/core/security/supplychain.policy.js +326 -0
  132. package/src/verax/core/security/vuln.scan.js +265 -0
  133. package/src/verax/core/silence-impact.js +1 -1
  134. package/src/verax/core/silence-model.js +9 -7
  135. package/src/verax/core/truth/truth.certificate.js +250 -0
  136. package/src/verax/core/ui-feedback-intelligence.js +515 -0
  137. package/src/verax/detect/comparison.js +8 -3
  138. package/src/verax/detect/confidence-engine.js +645 -57
  139. package/src/verax/detect/confidence-helper.js +33 -0
  140. package/src/verax/detect/detection-engine.js +19 -2
  141. package/src/verax/detect/dynamic-route-findings.js +335 -0
  142. package/src/verax/detect/evidence-index.js +15 -65
  143. package/src/verax/detect/expectation-chain-detector.js +417 -0
  144. package/src/verax/detect/expectation-model.js +56 -3
  145. package/src/verax/detect/explanation-helpers.js +1 -1
  146. package/src/verax/detect/finding-detector.js +2 -2
  147. package/src/verax/detect/findings-writer.js +149 -20
  148. package/src/verax/detect/flow-detector.js +4 -4
  149. package/src/verax/detect/index.js +265 -15
  150. package/src/verax/detect/interactive-findings.js +3 -4
  151. package/src/verax/detect/journey-stall-detector.js +558 -0
  152. package/src/verax/detect/route-findings.js +218 -0
  153. package/src/verax/detect/signal-mapper.js +2 -2
  154. package/src/verax/detect/skip-classifier.js +4 -4
  155. package/src/verax/detect/ui-feedback-findings.js +207 -0
  156. package/src/verax/detect/verdict-engine.js +61 -9
  157. package/src/verax/detect/view-switch-correlator.js +242 -0
  158. package/src/verax/flow/flow-engine.js +3 -2
  159. package/src/verax/flow/flow-spec.js +1 -2
  160. package/src/verax/index.js +413 -33
  161. package/src/verax/intel/effect-detector.js +1 -1
  162. package/src/verax/intel/index.js +2 -2
  163. package/src/verax/intel/route-extractor.js +3 -3
  164. package/src/verax/intel/vue-navigation-extractor.js +81 -18
  165. package/src/verax/intel/vue-router-extractor.js +4 -2
  166. package/src/verax/learn/action-contract-extractor.js +684 -66
  167. package/src/verax/learn/ast-contract-extractor.js +53 -1
  168. package/src/verax/learn/index.js +36 -2
  169. package/src/verax/learn/manifest-writer.js +28 -14
  170. package/src/verax/learn/route-extractor.js +1 -1
  171. package/src/verax/learn/route-validator.js +12 -8
  172. package/src/verax/learn/state-extractor.js +1 -1
  173. package/src/verax/learn/static-extractor-navigation.js +1 -1
  174. package/src/verax/learn/static-extractor-validation.js +2 -2
  175. package/src/verax/learn/static-extractor.js +8 -7
  176. package/src/verax/learn/ts-contract-resolver.js +14 -12
  177. package/src/verax/observe/browser.js +22 -3
  178. package/src/verax/observe/console-sensor.js +2 -2
  179. package/src/verax/observe/expectation-executor.js +2 -1
  180. package/src/verax/observe/focus-sensor.js +1 -1
  181. package/src/verax/observe/human-driver.js +29 -10
  182. package/src/verax/observe/index.js +92 -844
  183. package/src/verax/observe/interaction-discovery.js +27 -15
  184. package/src/verax/observe/interaction-runner.js +31 -14
  185. package/src/verax/observe/loading-sensor.js +6 -0
  186. package/src/verax/observe/navigation-sensor.js +1 -1
  187. package/src/verax/observe/observe-context.js +205 -0
  188. package/src/verax/observe/observe-helpers.js +191 -0
  189. package/src/verax/observe/observe-runner.js +226 -0
  190. package/src/verax/observe/observers/budget-observer.js +185 -0
  191. package/src/verax/observe/observers/console-observer.js +102 -0
  192. package/src/verax/observe/observers/coverage-observer.js +107 -0
  193. package/src/verax/observe/observers/interaction-observer.js +471 -0
  194. package/src/verax/observe/observers/navigation-observer.js +132 -0
  195. package/src/verax/observe/observers/network-observer.js +87 -0
  196. package/src/verax/observe/observers/safety-observer.js +82 -0
  197. package/src/verax/observe/observers/ui-feedback-observer.js +99 -0
  198. package/src/verax/observe/settle.js +1 -0
  199. package/src/verax/observe/state-sensor.js +8 -4
  200. package/src/verax/observe/state-ui-sensor.js +7 -1
  201. package/src/verax/observe/traces-writer.js +27 -16
  202. package/src/verax/observe/ui-feedback-detector.js +742 -0
  203. package/src/verax/observe/ui-signal-sensor.js +155 -2
  204. package/src/verax/scan-summary-writer.js +46 -9
  205. package/src/verax/shared/artifact-manager.js +9 -6
  206. package/src/verax/shared/budget-profiles.js +2 -2
  207. package/src/verax/shared/caching.js +1 -1
  208. package/src/verax/shared/config-loader.js +1 -2
  209. package/src/verax/shared/css-spinner-rules.js +204 -0
  210. package/src/verax/shared/dynamic-route-utils.js +12 -6
  211. package/src/verax/shared/retry-policy.js +1 -6
  212. package/src/verax/shared/root-artifacts.js +1 -1
  213. package/src/verax/shared/view-switch-rules.js +208 -0
  214. package/src/verax/shared/zip-artifacts.js +1 -0
  215. package/src/verax/validate/context-validator.js +1 -1
  216. package/src/verax/observe/index.js.backup +0 -1
  217. package/src/verax/validate/context-validator.js.bak +0 -0
@@ -0,0 +1,499 @@
1
+ /**
2
+ * PHASE 19 — Capability Gates
3
+ *
4
+ * Enforces quality gates for capabilities based on maturity level.
5
+ * No capability can be marked STABLE (or introduced) unless it satisfies required gates.
6
+ */
7
+
8
+ import { readFileSync, existsSync, readdirSync } from 'fs';
9
+ import { join, resolve } from 'path';
10
+ import { fileURLToPath, pathToFileURL } from 'url';
11
+ import { dirname } from 'path';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = dirname(__filename);
15
+
16
+ /**
17
+ * PHASE 19: Gate failure reason codes
18
+ */
19
+ export const GATE_REASON = {
20
+ MISSING_TEST_MATRIX: 'GATE_MISSING_TEST_MATRIX',
21
+ MISSING_FIXTURE: 'GATE_MISSING_FIXTURE',
22
+ MISSING_DOCS: 'GATE_MISSING_DOCS',
23
+ MISSING_DETERMINISM: 'GATE_MISSING_DETERMINISM',
24
+ MISSING_ARTIFACT_ASSERTIONS: 'GATE_MISSING_ARTIFACT_ASSERTIONS',
25
+ MISSING_GUARDRAILS: 'GATE_MISSING_GUARDRAILS',
26
+ INVALID_MATURITY: 'GATE_INVALID_MATURITY',
27
+ NOT_IN_REGISTRY: 'GATE_NOT_IN_REGISTRY',
28
+ };
29
+
30
+ /**
31
+ * PHASE 19: Capability maturity levels
32
+ */
33
+ export const CAPABILITY_MATURITY = {
34
+ EXPERIMENTAL: 'experimental',
35
+ PARTIAL: 'partial',
36
+ STABLE: 'stable',
37
+ };
38
+
39
+ /**
40
+ * PHASE 19: Capability categories that require guardrails
41
+ */
42
+ const GUARDRAILS_REQUIRED_CATEGORIES = [
43
+ 'network',
44
+ 'navigation',
45
+ 'routes',
46
+ 'ui-feedback',
47
+ 'validation',
48
+ ];
49
+
50
+ /**
51
+ * PHASE 19: Evaluate capability gates
52
+ *
53
+ * @param {string} capabilityId - Capability ID
54
+ * @param {Object} context - Context including registry, testMatrix, fixtures, docs, etc.
55
+ * @returns {Object} { pass, failures[], warnings[], evidence }
56
+ */
57
+ export function evaluateCapabilityGates(capabilityId, context) {
58
+ const {
59
+ capabilityRegistry,
60
+ testMatrix,
61
+ fixtureIndex,
62
+ docsIndex,
63
+ artifactsRegistry,
64
+ guardrailsRules,
65
+ determinismTests,
66
+ } = context;
67
+
68
+ const failures = [];
69
+ const warnings = [];
70
+ const evidence = {
71
+ inRegistry: false,
72
+ inTestMatrix: false,
73
+ hasFixture: false,
74
+ hasDocs: false,
75
+ hasDeterminism: false,
76
+ hasArtifactAssertions: false,
77
+ hasGuardrails: false,
78
+ };
79
+
80
+ // Check if capability exists in registry
81
+ const capability = capabilityRegistry[capabilityId];
82
+ if (!capability) {
83
+ failures.push({
84
+ reasonCode: GATE_REASON.NOT_IN_REGISTRY,
85
+ message: `Capability "${capabilityId}" not found in registry`,
86
+ });
87
+ return { pass: false, failures, warnings, evidence };
88
+ }
89
+
90
+ evidence.inRegistry = true;
91
+
92
+ // Get maturity level
93
+ const maturity = capability.maturity || CAPABILITY_MATURITY.EXPERIMENTAL;
94
+
95
+ // Gate 1: Test Matrix (required for all maturity levels)
96
+ const testMatrixEntry = testMatrix[capabilityId];
97
+ if (!testMatrixEntry || !Array.isArray(testMatrixEntry) || testMatrixEntry.length === 0) {
98
+ failures.push({
99
+ reasonCode: GATE_REASON.MISSING_TEST_MATRIX,
100
+ message: `Capability "${capabilityId}" has no test matrix entries`,
101
+ });
102
+ } else {
103
+ evidence.inTestMatrix = true;
104
+
105
+ // Check for artifact assertions in test matrix entries
106
+ const hasArtifactAssertions = testMatrixEntry.some(entry => {
107
+ const assertions = entry.expectedAssertions || [];
108
+ return assertions.some(assertion => {
109
+ const assertionLower = assertion.toLowerCase();
110
+ return assertionLower.includes('artifact') ||
111
+ assertionLower.includes('findings.json') ||
112
+ assertionLower.includes('learn.json') ||
113
+ assertionLower.includes('observe.json') ||
114
+ assertionLower.includes('traces') ||
115
+ assertionLower.includes('evidence') ||
116
+ assertionLower.includes('determinism');
117
+ });
118
+ });
119
+
120
+ if (!hasArtifactAssertions && maturity === CAPABILITY_MATURITY.STABLE) {
121
+ failures.push({
122
+ reasonCode: GATE_REASON.MISSING_ARTIFACT_ASSERTIONS,
123
+ message: `Capability "${capabilityId}" (STABLE) has no artifact assertions in test matrix`,
124
+ });
125
+ } else if (hasArtifactAssertions) {
126
+ evidence.hasArtifactAssertions = true;
127
+ }
128
+ }
129
+
130
+ // Gate 2: Fixture (required for PARTIAL and STABLE)
131
+ if (maturity === CAPABILITY_MATURITY.PARTIAL || maturity === CAPABILITY_MATURITY.STABLE) {
132
+ const hasFixture = fixtureIndex.some(fixture => {
133
+ return fixture.capabilities && fixture.capabilities.includes(capabilityId);
134
+ });
135
+
136
+ if (!hasFixture) {
137
+ failures.push({
138
+ reasonCode: GATE_REASON.MISSING_FIXTURE,
139
+ message: `Capability "${capabilityId}" (${maturity}) has no realistic fixture mapping`,
140
+ });
141
+ } else {
142
+ evidence.hasFixture = true;
143
+ }
144
+ }
145
+
146
+ // Gate 3: Docs (required for PARTIAL and STABLE)
147
+ if (maturity === CAPABILITY_MATURITY.PARTIAL || maturity === CAPABILITY_MATURITY.STABLE) {
148
+ const hasDocs = docsIndex.some(doc => {
149
+ return doc.capabilities && doc.capabilities.includes(capabilityId);
150
+ });
151
+
152
+ if (!hasDocs) {
153
+ failures.push({
154
+ reasonCode: GATE_REASON.MISSING_DOCS,
155
+ message: `Capability "${capabilityId}" (${maturity}) has no documentation`,
156
+ });
157
+ } else {
158
+ evidence.hasDocs = true;
159
+ }
160
+ }
161
+
162
+ // Gate 4: Determinism (required for STABLE)
163
+ if (maturity === CAPABILITY_MATURITY.STABLE) {
164
+ const hasDeterminism = determinismTests.some(test => {
165
+ return test.capabilities && test.capabilities.includes(capabilityId);
166
+ });
167
+
168
+ if (!hasDeterminism) {
169
+ failures.push({
170
+ reasonCode: GATE_REASON.MISSING_DETERMINISM,
171
+ message: `Capability "${capabilityId}" (STABLE) has no determinism test coverage`,
172
+ });
173
+ } else {
174
+ evidence.hasDeterminism = true;
175
+ }
176
+ }
177
+
178
+ // Gate 5: Guardrails (required for STABLE in certain categories)
179
+ if (maturity === CAPABILITY_MATURITY.STABLE) {
180
+ const category = capability.category || '';
181
+ const categoryLower = category.toLowerCase();
182
+ const requiresGuardrails = GUARDRAILS_REQUIRED_CATEGORIES.some(reqCat =>
183
+ categoryLower.includes(reqCat)
184
+ );
185
+
186
+ if (requiresGuardrails) {
187
+ // Check if guardrails test exists and covers this category
188
+ const hasGuardrails = guardrailsRules.some(rule => {
189
+ // Check if rule covers this category or capability
190
+ const ruleCategories = rule.capabilities || [];
191
+ return ruleCategories.some(cat =>
192
+ cat.toLowerCase() === categoryLower ||
193
+ cat === capabilityId ||
194
+ categoryLower.includes(cat.toLowerCase())
195
+ );
196
+ });
197
+
198
+ if (!hasGuardrails) {
199
+ failures.push({
200
+ reasonCode: GATE_REASON.MISSING_GUARDRAILS,
201
+ message: `Capability "${capabilityId}" (STABLE, category: ${category}) requires guardrails coverage`,
202
+ });
203
+ } else {
204
+ evidence.hasGuardrails = true;
205
+ }
206
+ } else {
207
+ // Not required for this category
208
+ evidence.hasGuardrails = true; // Mark as satisfied
209
+ }
210
+ }
211
+
212
+ const pass = failures.length === 0;
213
+
214
+ return { pass, failures, warnings, evidence };
215
+ }
216
+
217
+ /**
218
+ * PHASE 19: Evaluate all capability gates
219
+ *
220
+ * @param {Object} context - Context including registry, testMatrix, fixtures, docs, etc.
221
+ * @returns {Object} { pass, summary, perCapability }
222
+ */
223
+ export function evaluateAllCapabilityGates(context) {
224
+ const { capabilityRegistry } = context;
225
+
226
+ const perCapability = {};
227
+ let totalPass = 0;
228
+ let totalFail = 0;
229
+ const allFailures = [];
230
+
231
+ for (const capabilityId of Object.keys(capabilityRegistry)) {
232
+ const result = evaluateCapabilityGates(capabilityId, context);
233
+ perCapability[capabilityId] = result;
234
+
235
+ if (result.pass) {
236
+ totalPass++;
237
+ } else {
238
+ totalFail++;
239
+ allFailures.push({
240
+ capabilityId,
241
+ failures: result.failures,
242
+ warnings: result.warnings,
243
+ });
244
+ }
245
+ }
246
+
247
+ const summary = {
248
+ total: Object.keys(capabilityRegistry).length,
249
+ pass: totalPass,
250
+ fail: totalFail,
251
+ allFailures,
252
+ };
253
+
254
+ const pass = totalFail === 0;
255
+
256
+ return { pass, summary, perCapability };
257
+ }
258
+
259
+ /**
260
+ * PHASE 19: Build context from file system
261
+ *
262
+ * @param {Object} options - Options
263
+ * @returns {Promise<Object>} Context object
264
+ */
265
+ export async function buildGateContext(options = {}) {
266
+ const projectRoot = options.projectRoot || resolve(__dirname, '../../../');
267
+
268
+ // Load capability registry
269
+ const registryModule = await import('./registry.js');
270
+ const capabilityRegistry = registryModule.CAPABILITY_REGISTRY || {};
271
+
272
+ // Load test matrix
273
+ const testMatrixPath = resolve(projectRoot, 'test/test-matrix.js');
274
+ let testMatrix = {};
275
+ if (existsSync(testMatrixPath)) {
276
+ try {
277
+ // Convert to file:// URL for cross-platform compatibility
278
+ const testMatrixUrl = pathToFileURL(testMatrixPath).href;
279
+ const testMatrixModule = await import(testMatrixUrl);
280
+ testMatrix = testMatrixModule.TEST_MATRIX || testMatrixModule.default || {};
281
+ } catch (error) {
282
+ // Test matrix not available - log error for debugging
283
+ console.error('Failed to load test matrix:', error.message);
284
+ }
285
+ }
286
+
287
+ // Build fixture index
288
+ const fixtureIndex = buildFixtureIndex(projectRoot);
289
+
290
+ // Build docs index
291
+ const docsIndex = buildDocsIndex(projectRoot);
292
+
293
+ // Build guardrails rules index
294
+ const guardrailsRules = buildGuardrailsIndex(projectRoot);
295
+
296
+ // Build determinism tests index
297
+ const determinismTests = buildDeterminismTestsIndex(projectRoot);
298
+
299
+ // Load artifacts registry
300
+ const { ARTIFACT_REGISTRY } = await import('../artifacts/registry.js');
301
+
302
+ return {
303
+ capabilityRegistry,
304
+ testMatrix,
305
+ fixtureIndex,
306
+ docsIndex,
307
+ artifactsRegistry: ARTIFACT_REGISTRY,
308
+ guardrailsRules,
309
+ determinismTests,
310
+ };
311
+ }
312
+
313
+ /**
314
+ * Build fixture index by scanning fixtures folder
315
+ */
316
+ function buildFixtureIndex(projectRoot) {
317
+ const fixturesDir = resolve(projectRoot, 'test/fixtures/realistic');
318
+ const index = [];
319
+
320
+ if (!existsSync(fixturesDir)) {
321
+ return index;
322
+ }
323
+
324
+ try {
325
+ const entries = readdirSync(fixturesDir, { withFileTypes: true });
326
+ for (const entry of entries) {
327
+ if (entry.isDirectory()) {
328
+ const fixturePath = join(fixturesDir, entry.name);
329
+ const readmePath = join(fixturePath, 'README.md');
330
+
331
+ let capabilities = [];
332
+ if (existsSync(readmePath)) {
333
+ const readmeContent = readFileSync(readmePath, 'utf-8');
334
+ // Extract capability IDs from README (look for patterns like "capability-id" or "capabilityId")
335
+ // Also check for capability mentions in test matrix format
336
+ const capabilityMatches = readmeContent.match(/(['"])([a-z0-9-]+)(['"])/g);
337
+ if (capabilityMatches) {
338
+ capabilities = capabilityMatches.map(m => {
339
+ const match = m.match(/(['"])([a-z0-9-]+)(['"])/);
340
+ return match ? match[2] : null;
341
+ }).filter(Boolean);
342
+ }
343
+
344
+ // Also look for capability registry format
345
+ const registryMatches = readmeContent.match(/([a-z0-9-]+-[a-z0-9-]+)/g);
346
+ if (registryMatches) {
347
+ capabilities.push(...registryMatches.filter(m => m.includes('-')));
348
+ }
349
+ }
350
+
351
+ index.push({
352
+ name: entry.name,
353
+ path: fixturePath,
354
+ capabilities,
355
+ });
356
+ }
357
+ }
358
+ } catch (error) {
359
+ // Ignore errors
360
+ }
361
+
362
+ return index;
363
+ }
364
+
365
+ /**
366
+ * Build docs index by scanning docs folder
367
+ */
368
+ function buildDocsIndex(projectRoot) {
369
+ const docsDir = resolve(projectRoot, 'docs');
370
+ const index = [];
371
+
372
+ if (!existsSync(docsDir)) {
373
+ return index;
374
+ }
375
+
376
+ try {
377
+ const entries = readdirSync(docsDir, { withFileTypes: true });
378
+ for (const entry of entries) {
379
+ if (entry.isFile() && entry.name.endsWith('.md')) {
380
+ const docPath = join(docsDir, entry.name);
381
+ const docContent = readFileSync(docPath, 'utf-8');
382
+
383
+ // Extract capability IDs from docs (look for patterns)
384
+ const capabilities = [];
385
+ const capabilityMatches = docContent.match(/([a-z0-9-]+-[a-z0-9-]+)/g);
386
+ if (capabilityMatches) {
387
+ // Filter to likely capability IDs (contain hyphens, reasonable length)
388
+ for (const match of capabilityMatches) {
389
+ if (match.includes('-') && match.length > 5 && match.length < 50) {
390
+ capabilities.push(match);
391
+ }
392
+ }
393
+ }
394
+
395
+ index.push({
396
+ name: entry.name,
397
+ path: docPath,
398
+ capabilities: [...new Set(capabilities)], // Deduplicate
399
+ });
400
+ }
401
+ }
402
+ } catch (error) {
403
+ // Ignore errors
404
+ }
405
+
406
+ return index;
407
+ }
408
+
409
+ /**
410
+ * Build guardrails rules index by scanning test files
411
+ */
412
+ function buildGuardrailsIndex(projectRoot) {
413
+ const testDir = resolve(projectRoot, 'test');
414
+ const index = [];
415
+
416
+ if (!existsSync(testDir)) {
417
+ return index;
418
+ }
419
+
420
+ try {
421
+ const entries = readdirSync(testDir, { withFileTypes: true });
422
+ for (const entry of entries) {
423
+ if (entry.isFile() && entry.name.includes('guardrail')) {
424
+ const testPath = join(testDir, entry.name);
425
+ const testContent = readFileSync(testPath, 'utf-8');
426
+
427
+ // Extract capability categories from test content
428
+ const capabilities = [];
429
+ // Look for capability mentions or category mentions
430
+ const categoryMatches = testContent.match(/(network|navigation|routes|ui-feedback|validation)/gi);
431
+ if (categoryMatches) {
432
+ capabilities.push(...categoryMatches.map(m => m.toLowerCase()));
433
+ }
434
+
435
+ index.push({
436
+ name: entry.name,
437
+ path: testPath,
438
+ capabilities: [...new Set(capabilities)],
439
+ });
440
+ }
441
+ }
442
+ } catch (error) {
443
+ // Ignore errors
444
+ }
445
+
446
+ return index;
447
+ }
448
+
449
+ /**
450
+ * Build determinism tests index by scanning test files
451
+ */
452
+ function buildDeterminismTestsIndex(projectRoot) {
453
+ const testDir = resolve(projectRoot, 'test');
454
+ const index = [];
455
+
456
+ if (!existsSync(testDir)) {
457
+ return index;
458
+ }
459
+
460
+ try {
461
+ const entries = readdirSync(testDir, { withFileTypes: true });
462
+ for (const entry of entries) {
463
+ if (entry.isFile() && entry.name.includes('determinism')) {
464
+ const testPath = join(testDir, entry.name);
465
+ const testContent = readFileSync(testPath, 'utf-8');
466
+
467
+ // Extract capability IDs from test content by looking at test matrix references
468
+ const capabilities = [];
469
+ // Look for test matrix references or capability mentions
470
+ const testMatrixMatches = testContent.match(/testMatrix\[['"]([a-z0-9-]+)['"]\]/g);
471
+ if (testMatrixMatches) {
472
+ for (const match of testMatrixMatches) {
473
+ const capabilityMatch = match.match(/['"]([a-z0-9-]+)['"]/);
474
+ if (capabilityMatch) {
475
+ capabilities.push(capabilityMatch[1]);
476
+ }
477
+ }
478
+ }
479
+
480
+ // Also look for capability mentions in test descriptions
481
+ const capabilityMentions = testContent.match(/([a-z0-9-]+-[a-z0-9-]+)/g);
482
+ if (capabilityMentions) {
483
+ capabilities.push(...capabilityMentions.filter(m => m.includes('-')));
484
+ }
485
+
486
+ index.push({
487
+ name: entry.name,
488
+ path: testPath,
489
+ capabilities: [...new Set(capabilities)],
490
+ });
491
+ }
492
+ }
493
+ } catch (error) {
494
+ // Ignore errors
495
+ }
496
+
497
+ return index;
498
+ }
499
+