harnery 0.36.0 → 0.37.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 (311) hide show
  1. package/dist/commander.js +4 -0
  2. package/dist/commands/agents.d.ts.map +1 -1
  3. package/dist/commands/agents.js +87 -46
  4. package/dist/commands/artifacts.d.ts.map +1 -1
  5. package/dist/commands/artifacts.js +26 -1
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +11 -0
  8. package/dist/commands/diagnostics.d.ts +4 -0
  9. package/dist/commands/diagnostics.d.ts.map +1 -0
  10. package/dist/commands/diagnostics.js +229 -0
  11. package/dist/commands/files.d.ts +12 -0
  12. package/dist/commands/files.d.ts.map +1 -1
  13. package/dist/commands/files.js +54 -1
  14. package/dist/commands/governor.d.ts.map +1 -1
  15. package/dist/commands/governor.js +4 -0
  16. package/dist/commands/ledger-v3.d.ts.map +1 -1
  17. package/dist/commands/ledger-v3.js +71 -2
  18. package/dist/commands/qa-run.d.ts +4 -0
  19. package/dist/commands/qa-run.d.ts.map +1 -0
  20. package/dist/commands/qa-run.js +141 -0
  21. package/dist/commands/resources.d.ts +4 -0
  22. package/dist/commands/resources.d.ts.map +1 -0
  23. package/dist/commands/resources.js +29 -0
  24. package/dist/commands/supervisor.d.ts +4 -0
  25. package/dist/commands/supervisor.d.ts.map +1 -0
  26. package/dist/commands/supervisor.js +101 -0
  27. package/dist/commands/web.d.ts.map +1 -1
  28. package/dist/commands/web.js +17 -0
  29. package/dist/commands/workflow.d.ts.map +1 -1
  30. package/dist/commands/workflow.js +4 -0
  31. package/dist/core/agents/cli.js +7 -3
  32. package/dist/core/agents/health.d.ts +17 -0
  33. package/dist/core/agents/health.d.ts.map +1 -0
  34. package/dist/core/agents/health.js +109 -0
  35. package/dist/core/agents/mailbox.d.ts +92 -0
  36. package/dist/core/agents/mailbox.d.ts.map +1 -0
  37. package/dist/core/agents/mailbox.js +325 -0
  38. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  39. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  40. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  41. package/dist/core/agents/render/prompt-context.d.ts +5 -0
  42. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  43. package/dist/core/agents/render/prompt-context.js +34 -13
  44. package/dist/core/agents/render/session-context.d.ts +8 -0
  45. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  46. package/dist/core/agents/render/session-context.js +34 -3
  47. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  48. package/dist/core/agents/rules/commit-conflict.js +50 -1
  49. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  50. package/dist/core/agents/rules/stop-hook.js +6 -10
  51. package/dist/core/agents/session-finalizer-v3.js +4 -1
  52. package/dist/core/artifacts/index.d.ts +26 -1
  53. package/dist/core/artifacts/index.d.ts.map +1 -1
  54. package/dist/core/artifacts/index.js +146 -6
  55. package/dist/core/config.d.ts +12 -0
  56. package/dist/core/config.d.ts.map +1 -1
  57. package/dist/core/config.js +43 -0
  58. package/dist/core/diagnostics/advice.d.ts +9 -0
  59. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  60. package/dist/core/diagnostics/advice.js +112 -0
  61. package/dist/core/diagnostics/bundle.d.ts +35 -0
  62. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  63. package/dist/core/diagnostics/bundle.js +874 -0
  64. package/dist/core/diagnostics/comparison.d.ts +5 -0
  65. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  66. package/dist/core/diagnostics/comparison.js +444 -0
  67. package/dist/core/diagnostics/contract.d.ts +245 -0
  68. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  69. package/dist/core/diagnostics/contract.js +18 -0
  70. package/dist/core/diagnostics/identity.d.ts +3 -0
  71. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  72. package/dist/core/diagnostics/identity.js +10 -0
  73. package/dist/core/diagnostics/index.d.ts +8 -0
  74. package/dist/core/diagnostics/index.d.ts.map +1 -0
  75. package/dist/core/diagnostics/index.js +7 -0
  76. package/dist/core/diagnostics/replay.d.ts +8 -0
  77. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  78. package/dist/core/diagnostics/replay.js +213 -0
  79. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  80. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  81. package/dist/core/diagnostics/sanitize.js +84 -0
  82. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  83. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  84. package/dist/core/events/legacy-storage/compression.js +107 -0
  85. package/dist/core/events/legacy-storage/index.d.ts +1 -0
  86. package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
  87. package/dist/core/events/legacy-storage/index.js +1 -0
  88. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  89. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  90. package/dist/core/events/v3/archive-retention.js +195 -0
  91. package/dist/core/events/v3/capabilities.d.ts +1 -1
  92. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  93. package/dist/core/events/v3/capabilities.js +1 -0
  94. package/dist/core/events/v3/index.d.ts +1 -0
  95. package/dist/core/events/v3/index.d.ts.map +1 -1
  96. package/dist/core/events/v3/index.js +1 -0
  97. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  98. package/dist/core/events/v3/live-routing.js +1 -0
  99. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  100. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  101. package/dist/core/events/v3/producers/hook-base.js +13 -2
  102. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  103. package/dist/core/events/v3/producers/intake.js +1 -0
  104. package/dist/core/events/v3/producers/recorder.d.ts +16 -0
  105. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  106. package/dist/core/events/v3/producers/recorder.js +88 -1
  107. package/dist/core/hooks/adapter/output.d.ts +8 -0
  108. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  109. package/dist/core/hooks/adapter/output.js +11 -1
  110. package/dist/core/hooks/cli.js +183 -192
  111. package/dist/core/hooks/health.d.ts +59 -0
  112. package/dist/core/hooks/health.d.ts.map +1 -0
  113. package/dist/core/hooks/health.js +84 -0
  114. package/dist/core/resources/contract.d.ts +90 -0
  115. package/dist/core/resources/contract.d.ts.map +1 -0
  116. package/dist/core/resources/contract.js +2 -0
  117. package/dist/core/resources/index.d.ts +6 -0
  118. package/dist/core/resources/index.d.ts.map +1 -0
  119. package/dist/core/resources/index.js +5 -0
  120. package/dist/core/resources/sampler.d.ts +27 -0
  121. package/dist/core/resources/sampler.d.ts.map +1 -0
  122. package/dist/core/resources/sampler.js +357 -0
  123. package/dist/core/resources/service-status.d.ts +3 -0
  124. package/dist/core/resources/service-status.d.ts.map +1 -0
  125. package/dist/core/resources/service-status.js +48 -0
  126. package/dist/core/resources/service.d.ts +26 -0
  127. package/dist/core/resources/service.d.ts.map +1 -0
  128. package/dist/core/resources/service.js +292 -0
  129. package/dist/core/resources/storage.d.ts +13 -0
  130. package/dist/core/resources/storage.d.ts.map +1 -0
  131. package/dist/core/resources/storage.js +30 -0
  132. package/dist/core/storage/atomic-json.d.ts +3 -0
  133. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  134. package/dist/core/storage/atomic-json.js +15 -0
  135. package/dist/core/storage/builtins.d.ts.map +1 -1
  136. package/dist/core/storage/builtins.js +45 -6
  137. package/dist/core/storage/logger.d.ts +2 -0
  138. package/dist/core/storage/logger.d.ts.map +1 -1
  139. package/dist/core/storage/logger.js +2 -0
  140. package/dist/core/storage/query.d.ts +14 -0
  141. package/dist/core/storage/query.d.ts.map +1 -1
  142. package/dist/core/storage/query.js +51 -0
  143. package/dist/core/supervisor/activity.d.ts +4 -0
  144. package/dist/core/supervisor/activity.d.ts.map +1 -0
  145. package/dist/core/supervisor/activity.js +141 -0
  146. package/dist/core/supervisor/contract.d.ts +268 -0
  147. package/dist/core/supervisor/contract.d.ts.map +1 -0
  148. package/dist/core/supervisor/contract.js +35 -0
  149. package/dist/core/supervisor/explanations.d.ts +4 -0
  150. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  151. package/dist/core/supervisor/explanations.js +71 -0
  152. package/dist/core/supervisor/findings.d.ts +20 -0
  153. package/dist/core/supervisor/findings.d.ts.map +1 -0
  154. package/dist/core/supervisor/findings.js +399 -0
  155. package/dist/core/supervisor/history.d.ts +9 -0
  156. package/dist/core/supervisor/history.d.ts.map +1 -0
  157. package/dist/core/supervisor/history.js +46 -0
  158. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  159. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  160. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  161. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  162. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  163. package/dist/core/supervisor/hook-health-storage.js +24 -0
  164. package/dist/core/supervisor/hook-health.d.ts +72 -0
  165. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  166. package/dist/core/supervisor/hook-health.js +203 -0
  167. package/dist/core/supervisor/hooks.d.ts +10 -0
  168. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  169. package/dist/core/supervisor/hooks.js +28 -0
  170. package/dist/core/supervisor/index.d.ts +15 -0
  171. package/dist/core/supervisor/index.d.ts.map +1 -0
  172. package/dist/core/supervisor/index.js +14 -0
  173. package/dist/core/supervisor/log-feed.d.ts +9 -0
  174. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  175. package/dist/core/supervisor/log-feed.js +103 -0
  176. package/dist/core/supervisor/service.d.ts +29 -0
  177. package/dist/core/supervisor/service.d.ts.map +1 -0
  178. package/dist/core/supervisor/service.js +450 -0
  179. package/dist/core/supervisor/services.d.ts +11 -0
  180. package/dist/core/supervisor/services.d.ts.map +1 -0
  181. package/dist/core/supervisor/services.js +155 -0
  182. package/dist/core/supervisor/status.d.ts +3 -0
  183. package/dist/core/supervisor/status.d.ts.map +1 -0
  184. package/dist/core/supervisor/status.js +48 -0
  185. package/dist/core/supervisor/storage.d.ts +30 -0
  186. package/dist/core/supervisor/storage.d.ts.map +1 -0
  187. package/dist/core/supervisor/storage.js +73 -0
  188. package/dist/core/supervisor/timeline.d.ts +3 -0
  189. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  190. package/dist/core/supervisor/timeline.js +87 -0
  191. package/dist/core/workflow/admission.d.ts +23 -0
  192. package/dist/core/workflow/admission.d.ts.map +1 -0
  193. package/dist/core/workflow/admission.js +136 -0
  194. package/dist/core/workflow/engine.d.ts.map +1 -1
  195. package/dist/core/workflow/engine.js +77 -2
  196. package/dist/core/workflow/index.d.ts +3 -2
  197. package/dist/core/workflow/index.d.ts.map +1 -1
  198. package/dist/core/workflow/index.js +2 -1
  199. package/dist/core/workflow/proof.d.ts +2 -1
  200. package/dist/core/workflow/proof.d.ts.map +1 -1
  201. package/dist/core/workflow/proof.js +39 -1
  202. package/dist/core/workflow/run-state.d.ts +3 -2
  203. package/dist/core/workflow/run-state.d.ts.map +1 -1
  204. package/dist/core/workflow/run-state.js +8 -1
  205. package/dist/core/workflow/types.d.ts +33 -1
  206. package/dist/core/workflow/types.d.ts.map +1 -1
  207. package/dist/core/workflow/types.js +2 -1
  208. package/dist/lib/browser/client.d.ts +5 -0
  209. package/dist/lib/browser/client.d.ts.map +1 -1
  210. package/dist/lib/browser/client.js +1 -0
  211. package/dist/lib/browser/index.d.ts +2 -0
  212. package/dist/lib/browser/index.d.ts.map +1 -1
  213. package/dist/lib/browser/index.js +2 -0
  214. package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
  215. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  216. package/dist/lib/browser/qa-run-contracts.js +226 -0
  217. package/dist/lib/browser/qa-run.d.ts +51 -0
  218. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  219. package/dist/lib/browser/qa-run.js +684 -0
  220. package/dist/lib/coord-root-id.d.ts +9 -0
  221. package/dist/lib/coord-root-id.d.ts.map +1 -0
  222. package/dist/lib/coord-root-id.js +17 -0
  223. package/dist/lib/instructions/apply.d.ts +3 -1
  224. package/dist/lib/instructions/apply.d.ts.map +1 -1
  225. package/dist/lib/instructions/apply.js +74 -3
  226. package/dist/lib/instructions/templates.d.ts.map +1 -1
  227. package/dist/lib/instructions/templates.js +6 -0
  228. package/package.json +12 -1
  229. package/src/commander.ts +26 -0
  230. package/src/commands/agents.ts +102 -49
  231. package/src/commands/artifacts.ts +40 -2
  232. package/src/commands/browse.ts +15 -0
  233. package/src/commands/diagnostics.ts +271 -0
  234. package/src/commands/files.ts +102 -2
  235. package/src/commands/governor.ts +8 -0
  236. package/src/commands/ledger-v3.ts +82 -0
  237. package/src/commands/qa-run.ts +184 -0
  238. package/src/commands/resources.ts +38 -0
  239. package/src/commands/supervisor.ts +141 -0
  240. package/src/commands/web.ts +19 -0
  241. package/src/commands/workflow.ts +8 -0
  242. package/src/core/agents/cli.ts +7 -3
  243. package/src/core/agents/health.ts +142 -0
  244. package/src/core/agents/mailbox.ts +373 -0
  245. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  246. package/src/core/agents/render/prompt-context.ts +42 -12
  247. package/src/core/agents/render/session-context.ts +37 -3
  248. package/src/core/agents/rules/commit-conflict.ts +58 -1
  249. package/src/core/agents/rules/stop-hook.ts +6 -12
  250. package/src/core/agents/session-finalizer-v3.ts +4 -1
  251. package/src/core/artifacts/index.ts +196 -10
  252. package/src/core/config.ts +111 -2
  253. package/src/core/diagnostics/advice.ts +147 -0
  254. package/src/core/diagnostics/bundle.ts +1142 -0
  255. package/src/core/diagnostics/comparison.ts +565 -0
  256. package/src/core/diagnostics/contract.ts +311 -0
  257. package/src/core/diagnostics/identity.ts +11 -0
  258. package/src/core/diagnostics/index.ts +7 -0
  259. package/src/core/diagnostics/replay.ts +314 -0
  260. package/src/core/diagnostics/sanitize.ts +97 -0
  261. package/src/core/events/legacy-storage/compression.ts +130 -0
  262. package/src/core/events/legacy-storage/index.ts +1 -0
  263. package/src/core/events/v3/archive-retention.ts +251 -0
  264. package/src/core/events/v3/capabilities.ts +2 -0
  265. package/src/core/events/v3/index.ts +9 -0
  266. package/src/core/events/v3/live-routing.ts +1 -0
  267. package/src/core/events/v3/producers/hook-base.ts +14 -2
  268. package/src/core/events/v3/producers/intake.ts +1 -0
  269. package/src/core/events/v3/producers/recorder.ts +110 -1
  270. package/src/core/hooks/adapter/output.ts +12 -1
  271. package/src/core/hooks/cli.ts +192 -215
  272. package/src/core/hooks/health.ts +146 -0
  273. package/src/core/resources/contract.ts +98 -0
  274. package/src/core/resources/index.ts +5 -0
  275. package/src/core/resources/sampler.ts +458 -0
  276. package/src/core/resources/service-status.ts +62 -0
  277. package/src/core/resources/service.ts +337 -0
  278. package/src/core/resources/storage.ts +44 -0
  279. package/src/core/storage/atomic-json.ts +15 -0
  280. package/src/core/storage/builtins.ts +62 -6
  281. package/src/core/storage/logger.ts +2 -0
  282. package/src/core/storage/query.ts +58 -0
  283. package/src/core/supervisor/activity.ts +193 -0
  284. package/src/core/supervisor/contract.ts +312 -0
  285. package/src/core/supervisor/explanations.ts +104 -0
  286. package/src/core/supervisor/findings.ts +788 -0
  287. package/src/core/supervisor/history.ts +61 -0
  288. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  289. package/src/core/supervisor/hook-health-storage.ts +25 -0
  290. package/src/core/supervisor/hook-health.ts +301 -0
  291. package/src/core/supervisor/hooks.ts +35 -0
  292. package/src/core/supervisor/index.ts +14 -0
  293. package/src/core/supervisor/log-feed.ts +131 -0
  294. package/src/core/supervisor/service.ts +511 -0
  295. package/src/core/supervisor/services.ts +203 -0
  296. package/src/core/supervisor/status.ts +59 -0
  297. package/src/core/supervisor/storage.ts +126 -0
  298. package/src/core/supervisor/timeline.ts +133 -0
  299. package/src/core/workflow/admission.ts +215 -0
  300. package/src/core/workflow/engine.ts +93 -1
  301. package/src/core/workflow/index.ts +10 -0
  302. package/src/core/workflow/proof.ts +54 -1
  303. package/src/core/workflow/run-state.ts +13 -1
  304. package/src/core/workflow/types.ts +39 -1
  305. package/src/lib/browser/client.ts +6 -0
  306. package/src/lib/browser/index.ts +29 -0
  307. package/src/lib/browser/qa-run-contracts.ts +380 -0
  308. package/src/lib/browser/qa-run.ts +784 -0
  309. package/src/lib/coord-root-id.ts +23 -0
  310. package/src/lib/instructions/apply.ts +81 -2
  311. package/src/lib/instructions/templates.ts +6 -0
@@ -0,0 +1,226 @@
1
+ // Contracts for the qa-run matrix runner: one JSON job in, one JSON result
2
+ // out, with the coverage-merge and verdict rules as pure functions.
3
+ //
4
+ // The runner executes a whole page-QA matrix (planner, deterministic gates,
5
+ // interactions, critique, snapshot) in one process so the driving agent stops
6
+ // paying a model turn per browser command. These contracts are frozen first so
7
+ // the orchestrator, its tests, and downstream consumers build against the same
8
+ // shape.
9
+ //
10
+ // Two rules are load-bearing and enforced here, not in prose:
11
+ // - A job may WIDEN coverage beyond the planner's manifest but can never
12
+ // narrow it below the manifest (mergeCoverage is a union that keeps
13
+ // manifest order first).
14
+ // - A job must not carry credentials. Authentication is referenced through
15
+ // existing browser profiles and cookie stores; validation refuses
16
+ // secret-shaped fields before any browser or model work starts.
17
+ //
18
+ // Toolkit tier: this module must not import src/core (layering check).
19
+ export const QA_RUN_JOB_SCHEMA_VERSION = 1;
20
+ export const QA_RUN_RESULT_SCHEMA_VERSION = 1;
21
+ // ---------------------------------------------------------------------------
22
+ // Job validation
23
+ // ---------------------------------------------------------------------------
24
+ /** Field names that indicate an embedded credential. Matched on any object
25
+ * key anywhere in the job, case-insensitively. */
26
+ const SECRET_KEY_PATTERN = /(password|passwd|secret|token|api[-_]?key|authorization|cookie|credential|bearer)/i;
27
+ /** Value shapes that indicate an embedded credential even under an innocent
28
+ * key: explicit auth headers and long unbroken high-entropy-looking blobs. */
29
+ const SECRET_VALUE_PATTERNS = [/\bBearer\s+[\w.~+/=-]{16,}/i, /\bBasic\s+[A-Za-z0-9+/=]{16,}/];
30
+ function scanForSecrets(value, path, errors) {
31
+ if (typeof value === "string") {
32
+ for (const pattern of SECRET_VALUE_PATTERNS) {
33
+ if (pattern.test(value)) {
34
+ errors.push(`${path}: value looks like a credential — reference a browser profile or cookie store instead`);
35
+ return;
36
+ }
37
+ }
38
+ return;
39
+ }
40
+ if (Array.isArray(value)) {
41
+ value.forEach((item, i) => {
42
+ scanForSecrets(item, `${path}[${i}]`, errors);
43
+ });
44
+ return;
45
+ }
46
+ if (value && typeof value === "object") {
47
+ for (const [key, child] of Object.entries(value)) {
48
+ if (SECRET_KEY_PATTERN.test(key)) {
49
+ errors.push(`${path}.${key}: secret-bearing field names are refused — reference a browser profile or cookie store instead`);
50
+ continue;
51
+ }
52
+ scanForSecrets(child, `${path}.${key}`, errors);
53
+ }
54
+ }
55
+ }
56
+ function isStringArray(value) {
57
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
58
+ }
59
+ /**
60
+ * Validate an untrusted job document. Structural errors and secret-bearing
61
+ * fields are all reported at once so a caller can fix the job in one pass.
62
+ * Validation is deliberately strict: an underspecified job fails here, before
63
+ * any browser or model process starts.
64
+ */
65
+ export function validateQaRunJob(value) {
66
+ const errors = [];
67
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
68
+ return { ok: false, errors: ["job must be a JSON object"] };
69
+ }
70
+ const job = value;
71
+ if (job.schema_version !== QA_RUN_JOB_SCHEMA_VERSION) {
72
+ errors.push(`schema_version must be ${QA_RUN_JOB_SCHEMA_VERSION}`);
73
+ }
74
+ if (typeof job.target !== "string" || job.target.length === 0) {
75
+ errors.push("target is required (URL, file path, or route)");
76
+ }
77
+ if (job.mode !== "signoff" && job.mode !== "review") {
78
+ errors.push('mode must be "signoff" or "review"');
79
+ }
80
+ const ids = new Set();
81
+ if (job.contexts !== undefined) {
82
+ if (!Array.isArray(job.contexts)) {
83
+ errors.push("contexts must be an array");
84
+ }
85
+ else {
86
+ job.contexts.forEach((ctx, i) => {
87
+ const c = ctx;
88
+ if (typeof c?.id !== "string" || c.id.length === 0)
89
+ errors.push(`contexts[${i}].id is required`);
90
+ else if (ids.has(c.id))
91
+ errors.push(`contexts[${i}].id duplicates "${c.id}"`);
92
+ else
93
+ ids.add(c.id);
94
+ if (typeof c?.viewport !== "string" || c.viewport.length === 0) {
95
+ errors.push(`contexts[${i}].viewport is required`);
96
+ }
97
+ if (c?.theme !== "light" && c?.theme !== "dark") {
98
+ errors.push(`contexts[${i}].theme must be "light" or "dark"`);
99
+ }
100
+ if (typeof c?.state !== "string" || c.state.length === 0) {
101
+ errors.push(`contexts[${i}].state is required ("default" for the plain page)`);
102
+ }
103
+ if (c?.args !== undefined && !isStringArray(c.args)) {
104
+ errors.push(`contexts[${i}].args must be an argument array (never a shell string)`);
105
+ }
106
+ });
107
+ }
108
+ }
109
+ if (job.checks !== undefined) {
110
+ if (!Array.isArray(job.checks)) {
111
+ errors.push("checks must be an array");
112
+ }
113
+ else {
114
+ const checkIds = new Set();
115
+ job.checks.forEach((check, i) => {
116
+ const c = check;
117
+ if (typeof c?.id !== "string" || c.id.length === 0)
118
+ errors.push(`checks[${i}].id is required`);
119
+ else if (checkIds.has(c.id))
120
+ errors.push(`checks[${i}].id duplicates "${c.id}"`);
121
+ else
122
+ checkIds.add(c.id);
123
+ if (!isStringArray(c?.args) || c.args.length === 0) {
124
+ errors.push(`checks[${i}].args must be a non-empty argument array (never a shell string)`);
125
+ }
126
+ if (c?.contexts !== undefined && !isStringArray(c.contexts)) {
127
+ errors.push(`checks[${i}].contexts must be an array of context IDs`);
128
+ }
129
+ });
130
+ }
131
+ }
132
+ if (job.interaction_states !== undefined) {
133
+ if (!Array.isArray(job.interaction_states)) {
134
+ errors.push("interaction_states must be an array");
135
+ }
136
+ else {
137
+ job.interaction_states.forEach((state, i) => {
138
+ const s = state;
139
+ if (typeof s?.name !== "string" || s.name.length === 0) {
140
+ errors.push(`interaction_states[${i}].name is required`);
141
+ }
142
+ if (!isStringArray(s?.setup) || s.setup.length === 0) {
143
+ errors.push(`interaction_states[${i}].setup must be a non-empty argument array`);
144
+ }
145
+ if (!isStringArray(s?.assertions) || s.assertions.length === 0) {
146
+ errors.push(`interaction_states[${i}].assertions must name at least one outcome assertion — a click without a proven outcome is not a gate`);
147
+ }
148
+ });
149
+ }
150
+ }
151
+ if (job.policy !== undefined) {
152
+ const p = job.policy;
153
+ if (p?.command_concurrency !== undefined) {
154
+ const n = p.command_concurrency;
155
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1 || n > 8) {
156
+ errors.push("policy.command_concurrency must be an integer between 1 and 8");
157
+ }
158
+ }
159
+ if (p?.command_timeout_ms !== undefined) {
160
+ const n = p.command_timeout_ms;
161
+ if (typeof n !== "number" || !Number.isInteger(n) || n < 1000) {
162
+ errors.push("policy.command_timeout_ms must be an integer ≥ 1000");
163
+ }
164
+ }
165
+ }
166
+ scanForSecrets(job, "job", errors);
167
+ if (errors.length > 0)
168
+ return { ok: false, errors };
169
+ return { ok: true, job: value };
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // Coverage merge — widen-only
173
+ // ---------------------------------------------------------------------------
174
+ export function contextIdFor(context) {
175
+ return `${context.viewport}-${context.theme}-${context.state}`;
176
+ }
177
+ /**
178
+ * Merge planner-manifest coverage with the job's extra contexts. The manifest
179
+ * is the floor: its contexts always run, in manifest order, and a job can only
180
+ * append. The union construction makes narrowing impossible by design; the
181
+ * returned list is what the runner executes and what the result reports.
182
+ */
183
+ export function mergeCoverage(manifest, job) {
184
+ const merged = manifest.contexts.map((context) => ({
185
+ id: contextIdFor(context),
186
+ viewport: context.viewport,
187
+ theme: context.theme,
188
+ state: context.state,
189
+ }));
190
+ const seen = new Set(merged.map((context) => context.id));
191
+ for (const context of job.contexts ?? []) {
192
+ const canonical = contextIdFor(context);
193
+ if (seen.has(canonical) || seen.has(context.id))
194
+ continue;
195
+ seen.add(canonical);
196
+ seen.add(context.id);
197
+ merged.push(context);
198
+ }
199
+ return merged;
200
+ }
201
+ // ---------------------------------------------------------------------------
202
+ // Verdict — fail-closed
203
+ // ---------------------------------------------------------------------------
204
+ /**
205
+ * Compute the terminal verdict from completed evidence. The rules are the
206
+ * existing page-QA signoff contract, fail-closed:
207
+ * - any blocker → incomplete (a blocker is a fact the run could not
208
+ * establish, so a defect cannot be ruled out);
209
+ * - any failed or unknown command/critique outcome → failed when the check
210
+ * completed and found a defect, incomplete when the outcome is unknown;
211
+ * - signoff mode additionally requires the snapshot to have been saved.
212
+ * `passed` is only reachable when every input proves out.
213
+ */
214
+ export function computeVerdict(input) {
215
+ const failed = input.commands.some((command) => command.outcome === "failed") ||
216
+ input.critique.some((entry) => entry.outcome === "failed");
217
+ if (failed)
218
+ return "failed";
219
+ const unknown = input.commands.some((command) => command.outcome === "unknown") ||
220
+ input.critique.some((entry) => entry.outcome === "unknown");
221
+ if (input.blockers.length > 0 || unknown)
222
+ return "incomplete";
223
+ if (input.mode === "signoff" && !input.snapshotSaved)
224
+ return "incomplete";
225
+ return "passed";
226
+ }
@@ -0,0 +1,51 @@
1
+ import { type QaRunJob, type QaRunResult } from "./qa-run-contracts.js";
2
+ /** Set on critique children unless the job permits metered critique: the
3
+ * host's critique provider must stay on subscription-backed headless
4
+ * harnesses and surface exhaustion instead of falling back to a metered API. */
5
+ export declare const QA_RUN_HEADLESS_ONLY_ENV = "HARNERY_CRITIQUE_HEADLESS_ONLY";
6
+ /** Result document written into the run's output directory. */
7
+ export declare const QA_RUN_RESULT_FILENAME = "page-qa-result.json";
8
+ export interface QaRunExecOptions {
9
+ /** Hard per-command timeout in milliseconds. */
10
+ timeoutMs: number;
11
+ /** Complete child environment (already layered by the runner). */
12
+ env: NodeJS.ProcessEnv;
13
+ }
14
+ export interface QaRunExecResult {
15
+ /** Process exit code; null when the command never completed normally. */
16
+ exitCode: number | null;
17
+ stdout: string;
18
+ stderr: string;
19
+ /** Spawn failure / timeout / signal description. Presence means the
20
+ * command's outcome cannot be trusted. */
21
+ error?: string;
22
+ }
23
+ /** Injectable child-process executor. `argv[0]` is the executable. */
24
+ export type QaRunExec = (argv: string[], options: QaRunExecOptions) => Promise<QaRunExecResult>;
25
+ /** Default executor: execFile with argv arrays only (never a shell string),
26
+ * closed stdin, bounded output buffers, and the policy timeout. */
27
+ export declare const defaultQaRunExec: QaRunExec;
28
+ export interface QaRunMatrixOptions {
29
+ /** A validated job (see validateQaRunJob — the runner trusts its shape). */
30
+ job: QaRunJob;
31
+ /** Directory for artifacts and the result document. Created if missing. */
32
+ outDir: string;
33
+ /** argv prefix that reaches the host CLI's browse command, e.g.
34
+ * `[process.execPath, cliScript, "browse"]`. */
35
+ browseArgv: string[];
36
+ /** Injectable executor (tests). Default: execFile via defaultQaRunExec. */
37
+ exec?: QaRunExec;
38
+ /** Extra child-environment overrides layered over process.env. */
39
+ childEnv?: NodeJS.ProcessEnv;
40
+ /** Progress callback for human-facing per-stage lines. */
41
+ onLog?: (message: string) => void;
42
+ }
43
+ /**
44
+ * Execute the whole QA matrix for one validated job and return the result
45
+ * (also written to `<outDir>/page-qa-result.json`). Stages: plan →
46
+ * deterministic gates (bounded pool) → interactions (serial) → critique (one
47
+ * context at a time; the critique provider owns tile concurrency) → snapshot.
48
+ * The verdict is computeVerdict over everything recorded — fail-closed.
49
+ */
50
+ export declare function runQaMatrix(options: QaRunMatrixOptions): Promise<QaRunResult>;
51
+ //# sourceMappingURL=qa-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qa-run.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/qa-run.ts"],"names":[],"mappings":"AAiBA,OAAO,EAQL,KAAK,QAAQ,EACb,KAAK,WAAW,EACjB,MAAM,uBAAuB,CAAC;AAE/B;;gFAEgF;AAChF,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AAEzE,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB,wBAAwB,CAAC;AAiB5D,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf;8CAC0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,sEAAsE;AACtE,MAAM,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;AAEhG;mEACmE;AACnE,eAAO,MAAM,gBAAgB,EAAE,SAyC3B,CAAC;AAEL,MAAM,WAAW,kBAAkB;IACjC,4EAA4E;IAC5E,GAAG,EAAE,QAAQ,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;IACf;oDACgD;IAChD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IAC7B,0DAA0D;IAC1D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AA2JD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CA0enF"}