@tangle-network/browser-agent-driver 0.30.0 → 0.32.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 (252) hide show
  1. package/dist/brain/index.d.ts +12 -0
  2. package/dist/brain/index.d.ts.map +1 -1
  3. package/dist/brain/index.js +36 -8
  4. package/dist/brain/index.js.map +1 -1
  5. package/dist/cli-ack-patch.d.ts +39 -0
  6. package/dist/cli-ack-patch.d.ts.map +1 -0
  7. package/dist/cli-ack-patch.js +47 -0
  8. package/dist/cli-ack-patch.js.map +1 -0
  9. package/dist/cli-design-audit.d.ts +12 -0
  10. package/dist/cli-design-audit.d.ts.map +1 -1
  11. package/dist/cli-design-audit.js +78 -0
  12. package/dist/cli-design-audit.js.map +1 -1
  13. package/dist/cli-jobs.d.ts +13 -0
  14. package/dist/cli-jobs.d.ts.map +1 -0
  15. package/dist/cli-jobs.js +253 -0
  16. package/dist/cli-jobs.js.map +1 -0
  17. package/dist/cli-patterns.d.ts +26 -0
  18. package/dist/cli-patterns.d.ts.map +1 -0
  19. package/dist/cli-patterns.js +49 -0
  20. package/dist/cli-patterns.js.map +1 -0
  21. package/dist/cli-reports.d.ts +12 -0
  22. package/dist/cli-reports.d.ts.map +1 -0
  23. package/dist/cli-reports.js +97 -0
  24. package/dist/cli-reports.js.map +1 -0
  25. package/dist/cli.js +29 -1
  26. package/dist/cli.js.map +1 -1
  27. package/dist/design/audit/attribution/aggregate.d.ts +16 -0
  28. package/dist/design/audit/attribution/aggregate.d.ts.map +1 -0
  29. package/dist/design/audit/attribution/aggregate.js +81 -0
  30. package/dist/design/audit/attribution/aggregate.js.map +1 -0
  31. package/dist/design/audit/attribution/store.d.ts +36 -0
  32. package/dist/design/audit/attribution/store.d.ts.map +1 -0
  33. package/dist/design/audit/attribution/store.js +108 -0
  34. package/dist/design/audit/attribution/store.js.map +1 -0
  35. package/dist/design/audit/attribution/types.d.ts +13 -0
  36. package/dist/design/audit/attribution/types.d.ts.map +1 -0
  37. package/dist/design/audit/attribution/types.js +10 -0
  38. package/dist/design/audit/attribution/types.js.map +1 -0
  39. package/dist/design/audit/build-result.d.ts +68 -0
  40. package/dist/design/audit/build-result.d.ts.map +1 -0
  41. package/dist/design/audit/build-result.js +243 -0
  42. package/dist/design/audit/build-result.js.map +1 -0
  43. package/dist/design/audit/classify-ensemble.d.ts +46 -0
  44. package/dist/design/audit/classify-ensemble.d.ts.map +1 -0
  45. package/dist/design/audit/classify-ensemble.js +207 -0
  46. package/dist/design/audit/classify-ensemble.js.map +1 -0
  47. package/dist/design/audit/ethics/check.d.ts +59 -0
  48. package/dist/design/audit/ethics/check.d.ts.map +1 -0
  49. package/dist/design/audit/ethics/check.js +137 -0
  50. package/dist/design/audit/ethics/check.js.map +1 -0
  51. package/dist/design/audit/ethics/loader.d.ts +21 -0
  52. package/dist/design/audit/ethics/loader.d.ts.map +1 -0
  53. package/dist/design/audit/ethics/loader.js +207 -0
  54. package/dist/design/audit/ethics/loader.js.map +1 -0
  55. package/dist/design/audit/ethics/rules/finance.yaml +37 -0
  56. package/dist/design/audit/ethics/rules/kids.yaml +37 -0
  57. package/dist/design/audit/ethics/rules/legal.yaml +35 -0
  58. package/dist/design/audit/ethics/rules/medical.yaml +36 -0
  59. package/dist/design/audit/evaluate.d.ts.map +1 -1
  60. package/dist/design/audit/evaluate.js +4 -1
  61. package/dist/design/audit/evaluate.js.map +1 -1
  62. package/dist/design/audit/first-principles-mode.d.ts +42 -0
  63. package/dist/design/audit/first-principles-mode.d.ts.map +1 -0
  64. package/dist/design/audit/first-principles-mode.js +77 -0
  65. package/dist/design/audit/first-principles-mode.js.map +1 -0
  66. package/dist/design/audit/modality/android.d.ts +14 -0
  67. package/dist/design/audit/modality/android.d.ts.map +1 -0
  68. package/dist/design/audit/modality/android.js +18 -0
  69. package/dist/design/audit/modality/android.js.map +1 -0
  70. package/dist/design/audit/modality/html.d.ts +22 -0
  71. package/dist/design/audit/modality/html.d.ts.map +1 -0
  72. package/dist/design/audit/modality/html.js +51 -0
  73. package/dist/design/audit/modality/html.js.map +1 -0
  74. package/dist/design/audit/modality/index.d.ts +8 -0
  75. package/dist/design/audit/modality/index.d.ts.map +1 -0
  76. package/dist/design/audit/modality/index.js +15 -0
  77. package/dist/design/audit/modality/index.js.map +1 -0
  78. package/dist/design/audit/modality/ios.d.ts +16 -0
  79. package/dist/design/audit/modality/ios.d.ts.map +1 -0
  80. package/dist/design/audit/modality/ios.js +19 -0
  81. package/dist/design/audit/modality/ios.js.map +1 -0
  82. package/dist/design/audit/modality/types.d.ts +9 -0
  83. package/dist/design/audit/modality/types.d.ts.map +1 -0
  84. package/dist/design/audit/modality/types.js +9 -0
  85. package/dist/design/audit/modality/types.js.map +1 -0
  86. package/dist/design/audit/patches/generate.d.ts +45 -0
  87. package/dist/design/audit/patches/generate.d.ts.map +1 -0
  88. package/dist/design/audit/patches/generate.js +161 -0
  89. package/dist/design/audit/patches/generate.js.map +1 -0
  90. package/dist/design/audit/patches/index.d.ts +8 -0
  91. package/dist/design/audit/patches/index.d.ts.map +1 -0
  92. package/dist/design/audit/patches/index.js +5 -0
  93. package/dist/design/audit/patches/index.js.map +1 -0
  94. package/dist/design/audit/patches/parse.d.ts +29 -0
  95. package/dist/design/audit/patches/parse.d.ts.map +1 -0
  96. package/dist/design/audit/patches/parse.js +153 -0
  97. package/dist/design/audit/patches/parse.js.map +1 -0
  98. package/dist/design/audit/patches/render.d.ts +20 -0
  99. package/dist/design/audit/patches/render.d.ts.map +1 -0
  100. package/dist/design/audit/patches/render.js +55 -0
  101. package/dist/design/audit/patches/render.js.map +1 -0
  102. package/dist/design/audit/patches/severity-enforcement.d.ts +23 -0
  103. package/dist/design/audit/patches/severity-enforcement.d.ts.map +1 -0
  104. package/dist/design/audit/patches/severity-enforcement.js +42 -0
  105. package/dist/design/audit/patches/severity-enforcement.js.map +1 -0
  106. package/dist/design/audit/patches/validate.d.ts +40 -0
  107. package/dist/design/audit/patches/validate.d.ts.map +1 -0
  108. package/dist/design/audit/patches/validate.js +60 -0
  109. package/dist/design/audit/patches/validate.js.map +1 -0
  110. package/dist/design/audit/patterns/match.d.ts +24 -0
  111. package/dist/design/audit/patterns/match.d.ts.map +1 -0
  112. package/dist/design/audit/patterns/match.js +48 -0
  113. package/dist/design/audit/patterns/match.js.map +1 -0
  114. package/dist/design/audit/patterns/mine.d.ts +31 -0
  115. package/dist/design/audit/patterns/mine.d.ts.map +1 -0
  116. package/dist/design/audit/patterns/mine.js +35 -0
  117. package/dist/design/audit/patterns/mine.js.map +1 -0
  118. package/dist/design/audit/patterns/store.d.ts +14 -0
  119. package/dist/design/audit/patterns/store.d.ts.map +1 -0
  120. package/dist/design/audit/patterns/store.js +53 -0
  121. package/dist/design/audit/patterns/store.js.map +1 -0
  122. package/dist/design/audit/patterns/types.d.ts +53 -0
  123. package/dist/design/audit/patterns/types.d.ts.map +1 -0
  124. package/dist/design/audit/patterns/types.js +13 -0
  125. package/dist/design/audit/patterns/types.js.map +1 -0
  126. package/dist/design/audit/pipeline.d.ts +12 -0
  127. package/dist/design/audit/pipeline.d.ts.map +1 -1
  128. package/dist/design/audit/pipeline.js +81 -5
  129. package/dist/design/audit/pipeline.js.map +1 -1
  130. package/dist/design/audit/rubric/anchor-loader.d.ts +44 -0
  131. package/dist/design/audit/rubric/anchor-loader.d.ts.map +1 -0
  132. package/dist/design/audit/rubric/anchor-loader.js +210 -0
  133. package/dist/design/audit/rubric/anchor-loader.js.map +1 -0
  134. package/dist/design/audit/rubric/anchors/blog.yaml +33 -0
  135. package/dist/design/audit/rubric/anchors/dashboard.yaml +35 -0
  136. package/dist/design/audit/rubric/anchors/docs.yaml +35 -0
  137. package/dist/design/audit/rubric/anchors/ecommerce.yaml +33 -0
  138. package/dist/design/audit/rubric/anchors/marketing.yaml +34 -0
  139. package/dist/design/audit/rubric/anchors/saas-app.yaml +38 -0
  140. package/dist/design/audit/rubric/anchors/social.yaml +33 -0
  141. package/dist/design/audit/rubric/anchors/tool.yaml +33 -0
  142. package/dist/design/audit/rubric/anchors/utility.yaml +33 -0
  143. package/dist/design/audit/rubric/fragments/audience-clinician.md +42 -0
  144. package/dist/design/audit/rubric/fragments/audience-developer.md +40 -0
  145. package/dist/design/audit/rubric/fragments/audience-kids.md +35 -0
  146. package/dist/design/audit/rubric/fragments/audience-vulnerability-minor-facing.md +37 -0
  147. package/dist/design/audit/rubric/fragments/first-principles.md +65 -0
  148. package/dist/design/audit/rubric/fragments/modality-mobile.md +39 -0
  149. package/dist/design/audit/rubric/fragments/modality-tablet.md +35 -0
  150. package/dist/design/audit/rubric/fragments/regulatory-coppa.md +32 -0
  151. package/dist/design/audit/rubric/fragments/regulatory-gdpr.md +33 -0
  152. package/dist/design/audit/rubric/fragments/regulatory-hipaa.md +36 -0
  153. package/dist/design/audit/rubric/loader.d.ts +26 -6
  154. package/dist/design/audit/rubric/loader.d.ts.map +1 -1
  155. package/dist/design/audit/rubric/loader.js +45 -26
  156. package/dist/design/audit/rubric/loader.js.map +1 -1
  157. package/dist/design/audit/rubric/rollup-weights.d.ts +25 -0
  158. package/dist/design/audit/rubric/rollup-weights.d.ts.map +1 -0
  159. package/dist/design/audit/rubric/rollup-weights.js +51 -0
  160. package/dist/design/audit/rubric/rollup-weights.js.map +1 -0
  161. package/dist/design/audit/score-types.d.ts +431 -0
  162. package/dist/design/audit/score-types.d.ts.map +1 -0
  163. package/dist/design/audit/score-types.js +26 -0
  164. package/dist/design/audit/score-types.js.map +1 -0
  165. package/dist/design/audit/score.d.ts +49 -0
  166. package/dist/design/audit/score.d.ts.map +1 -0
  167. package/dist/design/audit/score.js +211 -0
  168. package/dist/design/audit/score.js.map +1 -0
  169. package/dist/design/audit/types.d.ts +28 -0
  170. package/dist/design/audit/types.d.ts.map +1 -1
  171. package/dist/discover/index.d.ts +16 -0
  172. package/dist/discover/index.d.ts.map +1 -0
  173. package/dist/discover/index.js +25 -0
  174. package/dist/discover/index.js.map +1 -0
  175. package/dist/discover/wayback.d.ts +49 -0
  176. package/dist/discover/wayback.d.ts.map +1 -0
  177. package/dist/discover/wayback.js +123 -0
  178. package/dist/discover/wayback.js.map +1 -0
  179. package/dist/jobs/anti-bot.d.ts +19 -0
  180. package/dist/jobs/anti-bot.d.ts.map +1 -0
  181. package/dist/jobs/anti-bot.js +64 -0
  182. package/dist/jobs/anti-bot.js.map +1 -0
  183. package/dist/jobs/cost-estimate.d.ts +12 -0
  184. package/dist/jobs/cost-estimate.d.ts.map +1 -0
  185. package/dist/jobs/cost-estimate.js +21 -0
  186. package/dist/jobs/cost-estimate.js.map +1 -0
  187. package/dist/jobs/cost-history.d.ts +19 -0
  188. package/dist/jobs/cost-history.d.ts.map +1 -0
  189. package/dist/jobs/cost-history.js +42 -0
  190. package/dist/jobs/cost-history.js.map +1 -0
  191. package/dist/jobs/index.d.ts +31 -0
  192. package/dist/jobs/index.d.ts.map +1 -0
  193. package/dist/jobs/index.js +37 -0
  194. package/dist/jobs/index.js.map +1 -0
  195. package/dist/jobs/orchestrator.d.ts +42 -0
  196. package/dist/jobs/orchestrator.d.ts.map +1 -0
  197. package/dist/jobs/orchestrator.js +282 -0
  198. package/dist/jobs/orchestrator.js.map +1 -0
  199. package/dist/jobs/queue.d.ts +45 -0
  200. package/dist/jobs/queue.d.ts.map +1 -0
  201. package/dist/jobs/queue.js +114 -0
  202. package/dist/jobs/queue.js.map +1 -0
  203. package/dist/jobs/retry.d.ts +36 -0
  204. package/dist/jobs/retry.d.ts.map +1 -0
  205. package/dist/jobs/retry.js +77 -0
  206. package/dist/jobs/retry.js.map +1 -0
  207. package/dist/jobs/store.d.ts +31 -0
  208. package/dist/jobs/store.d.ts.map +1 -0
  209. package/dist/jobs/store.js +92 -0
  210. package/dist/jobs/store.js.map +1 -0
  211. package/dist/jobs/types.d.ts +106 -0
  212. package/dist/jobs/types.d.ts.map +1 -0
  213. package/dist/jobs/types.js +13 -0
  214. package/dist/jobs/types.js.map +1 -0
  215. package/dist/reports/aggregate.d.ts +38 -0
  216. package/dist/reports/aggregate.d.ts.map +1 -0
  217. package/dist/reports/aggregate.js +145 -0
  218. package/dist/reports/aggregate.js.map +1 -0
  219. package/dist/reports/index.d.ts +21 -0
  220. package/dist/reports/index.d.ts.map +1 -0
  221. package/dist/reports/index.js +15 -0
  222. package/dist/reports/index.js.map +1 -0
  223. package/dist/reports/narrate.d.ts +19 -0
  224. package/dist/reports/narrate.d.ts.map +1 -0
  225. package/dist/reports/narrate.js +40 -0
  226. package/dist/reports/narrate.js.map +1 -0
  227. package/dist/reports/templates.d.ts +43 -0
  228. package/dist/reports/templates.d.ts.map +1 -0
  229. package/dist/reports/templates.js +200 -0
  230. package/dist/reports/templates.js.map +1 -0
  231. package/dist/reports/tokens.d.ts +69 -0
  232. package/dist/reports/tokens.d.ts.map +1 -0
  233. package/dist/reports/tokens.js +74 -0
  234. package/dist/reports/tokens.js.map +1 -0
  235. package/dist/reports/tools.d.ts +76 -0
  236. package/dist/reports/tools.d.ts.map +1 -0
  237. package/dist/reports/tools.js +205 -0
  238. package/dist/reports/tools.js.map +1 -0
  239. package/dist/reports/types.d.ts +51 -0
  240. package/dist/reports/types.d.ts.map +1 -0
  241. package/dist/reports/types.js +9 -0
  242. package/dist/reports/types.js.map +1 -0
  243. package/dist/run-state.d.ts +36 -1
  244. package/dist/run-state.d.ts.map +1 -1
  245. package/dist/run-state.js +36 -1
  246. package/dist/run-state.js.map +1 -1
  247. package/dist/runner/runner.d.ts.map +1 -1
  248. package/dist/runner/runner.js +73 -3
  249. package/dist/runner/runner.js.map +1 -1
  250. package/dist/types.d.ts +7 -0
  251. package/dist/types.d.ts.map +1 -1
  252. package/package.json +5 -1
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Multi-dimensional scoring — prompt builder, parser, and rollup.
3
+ *
4
+ * Pure functions. No I/O, no Brain dependency. The pipeline supplies the
5
+ * inputs (classification, rubric, anchor, measurements) and persists the
6
+ * resulting `Record<Dimension, DimensionScore> + RollupScore`.
7
+ */
8
+ import { DIMENSIONS, } from './score-types.js';
9
+ import { rollupFormula, rollupWeightsFor } from './rubric/rollup-weights.js';
10
+ import { renderAnchor } from './rubric/anchor-loader.js';
11
+ const VALID_CONFIDENCE = ['high', 'medium', 'low'];
12
+ const DEFAULT_OPENER = 'You are a principal product-design auditor. Score this page on five universal dimensions independently, with explicit ranges and confidence. The downstream system aggregates these into a page-type-aware rollup.';
13
+ /**
14
+ * Build the evaluation prompt. Demands per-dim DimensionScore output with
15
+ * range + confidence. Does NOT request the rollup — the rollup is computed
16
+ * deterministically from the per-dim scores using rollup-weights.
17
+ */
18
+ export function buildEvalPrompt(input) {
19
+ const opener = input.systemOpener ?? DEFAULT_OPENER;
20
+ const anchorBlock = input.anchor ? renderAnchor(input.anchor) : '';
21
+ const intentLine = input.intent ? `\nPAGE INTENT (from classifier): ${input.intent}` : '';
22
+ return `${opener}
23
+
24
+ You are auditing a page that has been pre-classified as type=${input.pageType}. Contrast and accessibility measurements have already been counted deterministically — do NOT re-evaluate them. They will be merged with your output.${intentLine}
25
+
26
+ DIMENSIONS — score each one 1-10 (integer) with an explicit uncertainty range and confidence:
27
+
28
+ product_intent — Does the page make its audience, purpose, primary action, and product state obvious within 5 seconds? Empty/loading/error states designed?
29
+ visual_craft — Is the visual system intentional? Typography ramp, spacing rhythm, color tokens, component coherence, polish details. Decorative-but-shallow output is a defect.
30
+ trust_clarity — Are commitments (money, identity, deploy, share, irreversible actions) accompanied by the right trust details (price, fees, permissions, undo path, provenance)?
31
+ workflow — Can a user complete the end-to-end job? State transitions, recovery from failure, action hierarchy match the operational verbs of the system.
32
+ content_ia — Is the copy plain and useful? Are labels and IA tuned to the audience's tasks? Meta-copy that explains the UI is a defect.
33
+
34
+ DETERMINISTIC MEASUREMENTS (do not duplicate):
35
+ ${input.measurementSummary}
36
+
37
+ ${anchorBlock ? anchorBlock + '\n\n' : ''}EVALUATION RUBRIC:
38
+ ${input.rubricBody}
39
+
40
+ OUTPUT REQUIREMENTS:
41
+ - Every dimension MUST have an integer score 1-10.
42
+ - Every dimension MUST have a range [low, high] with low <= score <= high. Range width encodes your uncertainty.
43
+ - Every dimension MUST have confidence in {"high","medium","low"}.
44
+ - Summary is one sentence grounded in observable evidence.
45
+ - primaryFindings is a list of finding ids that drive the score (may be empty if you produce no findings).
46
+
47
+ RESPOND WITH ONLY a JSON object:
48
+ {
49
+ "scores": {
50
+ "product_intent": { "score": 6, "range": [5, 7], "confidence": "medium", "summary": "Hero is clear but action hierarchy is diffuse.", "primaryFindings": [] },
51
+ "visual_craft": { "score": 7, "range": [6, 8], "confidence": "high", "summary": "Spacing rhythm is intentional but type ramp drifts in cards.", "primaryFindings": [] },
52
+ "trust_clarity": { "score": 5, "range": [4, 6], "confidence": "medium", "summary": "Fees disclosed but only at the final step.", "primaryFindings": [] },
53
+ "workflow": { "score": 6, "range": [5, 7], "confidence": "medium", "summary": "Empty state directs the user but error recovery is implicit.", "primaryFindings": [] },
54
+ "content_ia": { "score": 7, "range": [6, 8], "confidence": "high", "summary": "Copy is plain and audience-tuned.", "primaryFindings": [] }
55
+ },
56
+ "summary": "One-sentence overall assessment.",
57
+ "strengths": ["..."],
58
+ "findings": []
59
+ }
60
+
61
+ Score 1-10. Most production apps score 5-7. Only world-class deserves 8+. Be honest.`;
62
+ }
63
+ /**
64
+ * Parse the LLM response. Throws when scores are missing, ranges violate
65
+ * `range[0] <= score <= range[1]`, or score is outside 1..10. The pipeline
66
+ * catches the throw and falls back to v1 mean-of-passes.
67
+ */
68
+ export function parseAuditResponse(raw) {
69
+ const parsed = extractJsonObject(raw);
70
+ if (!parsed)
71
+ throw new Error('parser: no JSON object in response');
72
+ const rawScores = parsed.scores;
73
+ if (!rawScores || typeof rawScores !== 'object') {
74
+ throw new Error('parser: missing scores object');
75
+ }
76
+ const scoreMap = rawScores;
77
+ const out = {};
78
+ for (const dim of DIMENSIONS) {
79
+ const dimRaw = scoreMap[dim];
80
+ if (!dimRaw || typeof dimRaw !== 'object') {
81
+ throw new Error(`parser: dimension ${dim} missing`);
82
+ }
83
+ out[dim] = parseDimensionScore(dim, dimRaw);
84
+ }
85
+ return {
86
+ scores: out,
87
+ summary: typeof parsed.summary === 'string' ? parsed.summary : '',
88
+ strengths: Array.isArray(parsed.strengths)
89
+ ? (parsed.strengths.filter((s) => typeof s === 'string'))
90
+ : [],
91
+ };
92
+ }
93
+ function parseDimensionScore(dim, raw) {
94
+ const score = raw.score;
95
+ if (typeof score !== 'number' || !Number.isFinite(score)) {
96
+ throw new Error(`parser: ${dim}.score must be a number`);
97
+ }
98
+ const integerScore = Math.round(score);
99
+ if (integerScore < 1 || integerScore > 10) {
100
+ throw new Error(`parser: ${dim}.score=${integerScore} outside 1..10`);
101
+ }
102
+ const range = raw.range;
103
+ if (!Array.isArray(range) || range.length !== 2 || typeof range[0] !== 'number' || typeof range[1] !== 'number') {
104
+ throw new Error(`parser: ${dim}.range must be [number, number]`);
105
+ }
106
+ const [low, high] = range;
107
+ if (low > high) {
108
+ throw new Error(`parser: ${dim}.range=[${low},${high}] inverted`);
109
+ }
110
+ if (integerScore < low || integerScore > high) {
111
+ throw new Error(`parser: ${dim}.score=${integerScore} outside range [${low},${high}]`);
112
+ }
113
+ if (low < 1 || high > 10) {
114
+ throw new Error(`parser: ${dim}.range=[${low},${high}] outside 1..10`);
115
+ }
116
+ const confidenceRaw = String(raw.confidence ?? '').toLowerCase();
117
+ const confidence = VALID_CONFIDENCE.includes(confidenceRaw)
118
+ ? confidenceRaw
119
+ : 'medium';
120
+ const summary = typeof raw.summary === 'string' ? raw.summary : '';
121
+ const primaryFindings = Array.isArray(raw.primaryFindings)
122
+ ? raw.primaryFindings.filter((s) => typeof s === 'string')
123
+ : [];
124
+ return { score: integerScore, range: [low, high], confidence, summary, primaryFindings };
125
+ }
126
+ /**
127
+ * Compute the rollup from per-dimension scores using per-page-type weights.
128
+ * Conservative confidence rule: rollup confidence = lowest dim confidence.
129
+ */
130
+ export function computeRollup(scores, pageType) {
131
+ const weights = rollupWeightsFor(pageType);
132
+ let weighted = 0;
133
+ let lowSum = 0;
134
+ let highSum = 0;
135
+ for (const dim of DIMENSIONS) {
136
+ const dimScore = scores[dim];
137
+ const w = weights[dim];
138
+ weighted += dimScore.score * w;
139
+ lowSum += dimScore.range[0] * w;
140
+ highSum += dimScore.range[1] * w;
141
+ }
142
+ const score = Math.round(weighted * 10) / 10;
143
+ const range = [
144
+ Math.round(lowSum * 10) / 10,
145
+ Math.round(highSum * 10) / 10,
146
+ ];
147
+ const confidences = DIMENSIONS.map((d) => scores[d].confidence);
148
+ const confidence = confidences.includes('low')
149
+ ? 'low'
150
+ : confidences.includes('medium')
151
+ ? 'medium'
152
+ : 'high';
153
+ return {
154
+ score,
155
+ range,
156
+ confidence,
157
+ rule: rollupFormula(pageType, weights),
158
+ weights,
159
+ };
160
+ }
161
+ /**
162
+ * Aggregate per-dim scores from N independent passes (mean). Used when the
163
+ * audit runs deep mode and we want one DimensionScore per dimension.
164
+ */
165
+ export function mergeDimensionScoresAcrossPasses(perPass) {
166
+ if (perPass.length === 0) {
167
+ throw new Error('mergeDimensionScoresAcrossPasses: empty input');
168
+ }
169
+ if (perPass.length === 1)
170
+ return perPass[0];
171
+ const out = {};
172
+ for (const dim of DIMENSIONS) {
173
+ const samples = perPass.map((p) => p[dim]);
174
+ const meanScore = samples.reduce((a, s) => a + s.score, 0) / samples.length;
175
+ const meanLow = samples.reduce((a, s) => a + s.range[0], 0) / samples.length;
176
+ const meanHigh = samples.reduce((a, s) => a + s.range[1], 0) / samples.length;
177
+ const conf = samples.map((s) => s.confidence);
178
+ const confidence = conf.includes('low') ? 'low' : conf.includes('medium') ? 'medium' : 'high';
179
+ const allFindings = samples.flatMap((s) => s.primaryFindings);
180
+ const primaryFindings = Array.from(new Set(allFindings)).slice(0, 3);
181
+ const summary = samples.find((s) => s.summary)?.summary ?? '';
182
+ out[dim] = {
183
+ score: Math.round(meanScore),
184
+ range: [
185
+ Math.max(1, Math.floor(meanLow)),
186
+ Math.min(10, Math.ceil(meanHigh)),
187
+ ],
188
+ confidence,
189
+ summary,
190
+ primaryFindings,
191
+ };
192
+ }
193
+ return out;
194
+ }
195
+ function extractJsonObject(raw) {
196
+ try {
197
+ let text = raw.trim();
198
+ if (text.startsWith('```')) {
199
+ text = text.replace(/^```(?:json)?\n?/, '').replace(/\n?```$/, '');
200
+ }
201
+ const start = text.indexOf('{');
202
+ const end = text.lastIndexOf('}');
203
+ if (start < 0 || end <= start)
204
+ return null;
205
+ return JSON.parse(text.slice(start, end + 1));
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ //# sourceMappingURL=score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.js","sourceRoot":"","sources":["../../../src/design/audit/score.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,9 @@
5
5
  * Each stage is a pure transformation; the orchestrator (`pipeline.ts`) wires them.
6
6
  */
7
7
  import type { DesignFinding, DesignSystemScore } from '../../types.js';
8
+ import type { EthicsViolation } from './score-types.js';
8
9
  export type { DesignFinding, DesignSystemScore } from '../../types.js';
10
+ export type { EthicsViolation } from './score-types.js';
9
11
  /**
10
12
  * Page classification — produced by a single cheap LLM call before any scoring.
11
13
  * Drives rubric composition and measurement strategy.
@@ -161,6 +163,32 @@ export interface PageAuditResult {
161
163
  designSystemScore?: DesignSystemScore;
162
164
  screenshotPath?: string;
163
165
  tokensUsed?: number;
166
+ /**
167
+ * Layer 7 — domain ethics violations. When non-empty, `score` is capped by
168
+ * the lowest `rollupCap` across violations until the underlying issue is
169
+ * remediated. Empty when --skip-ethics is set or when no rule fires.
170
+ */
171
+ ethicsViolations?: EthicsViolation[];
172
+ /**
173
+ * The pre-cap score (Layer 7). Set when `ethicsViolations` is non-empty so
174
+ * tooling can show "would have scored X, capped at Y" without losing
175
+ * the LLM's original assessment.
176
+ */
177
+ preEthicsScore?: number;
178
+ /**
179
+ * Layer 1 — multi-dim audit result. Emitted alongside the v1 fields for
180
+ * one release as a backwards-compat bridge. Consumers should migrate to
181
+ * `auditResult` and treat the v1 surface as deprecated.
182
+ *
183
+ * Typed as `unknown` here to avoid pulling score-types.ts into v1 consumers.
184
+ * The concrete shape is `import('./score-types.js').AuditResult`.
185
+ */
186
+ auditResult?: unknown;
187
+ /**
188
+ * Layer 1 — ensemble classification (URL + DOM + LLM). When set, the
189
+ * pipeline used `--audit-passes auto` (the new default).
190
+ */
191
+ ensembleClassification?: unknown;
164
192
  error?: string;
165
193
  }
166
194
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/design/audit/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/design/audit/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Discoverers — turn a job's `discover` spec into a flat list of audit targets.
3
+ *
4
+ * Two sources:
5
+ * list — explicit URLs (passthrough).
6
+ * wayback — expand each URL into N historical snapshots via the CDX API.
7
+ */
8
+ import type { DiscoverSpec, JobTarget } from '../jobs/types.js';
9
+ export { discoverWaybackSnapshots, expandWaybackTargets, snapshotUrl, sampleEvenly, parseCdxRows, cdxStampToIso } from './wayback.js';
10
+ export type { WaybackOptions } from './wayback.js';
11
+ export interface DiscoverOptions {
12
+ /** Injected fetch (tests). */
13
+ fetch?: typeof fetch;
14
+ }
15
+ export declare function discoverTargets(spec: DiscoverSpec, opts?: DiscoverOptions): Promise<JobTarget[]>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/discover/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAG/D,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AACrI,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAElD,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,GAAE,eAAoB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAc1G"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Discoverers — turn a job's `discover` spec into a flat list of audit targets.
3
+ *
4
+ * Two sources:
5
+ * list — explicit URLs (passthrough).
6
+ * wayback — expand each URL into N historical snapshots via the CDX API.
7
+ */
8
+ import { expandWaybackTargets } from './wayback.js';
9
+ export { discoverWaybackSnapshots, expandWaybackTargets, snapshotUrl, sampleEvenly, parseCdxRows, cdxStampToIso } from './wayback.js';
10
+ export async function discoverTargets(spec, opts = {}) {
11
+ if (spec.source === 'list') {
12
+ return spec.urls.map(url => ({ url }));
13
+ }
14
+ if (spec.source === 'wayback') {
15
+ const wb = {
16
+ count: spec.snapshotsPerUrl,
17
+ since: spec.since,
18
+ until: spec.until,
19
+ fetch: opts.fetch,
20
+ };
21
+ return expandWaybackTargets(spec.urls, wb);
22
+ }
23
+ throw new Error(`discover: unsupported source "${spec.source}"`);
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/discover/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,oBAAoB,EAAuB,MAAM,cAAc,CAAA;AAExE,OAAO,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAQrI,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAkB,EAAE,OAAwB,EAAE;IAClF,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;IACxC,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,MAAM,EAAE,GAAmB;YACzB,KAAK,EAAE,IAAI,CAAC,eAAe;YAC3B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAA;QACD,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC5C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,iCAAkC,IAAqB,CAAC,MAAM,GAAG,CAAC,CAAA;AACpF,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Wayback Machine snapshot discoverer (CDX API).
3
+ *
4
+ * Uses archive.org's CDX server to list captures of a URL, then samples
5
+ * `count` snapshots evenly across the time range. The CDX API is rate-limited
6
+ * (~15 req/s) but for the small N we use here we never approach the cap.
7
+ *
8
+ * CDX response shape:
9
+ * [["urlkey","timestamp","original","mimetype","statuscode","digest","length"],
10
+ * ["com,stripe)/", "20100101120000", "https://stripe.com/", "text/html", "200", "...", "1234"],
11
+ * ...]
12
+ *
13
+ * Snapshot URL = `https://web.archive.org/web/<timestamp>/<original>`.
14
+ */
15
+ import type { JobTarget } from '../jobs/types.js';
16
+ export interface WaybackOptions {
17
+ /** Snapshots per URL. Default 5. */
18
+ count?: number;
19
+ /** Lower-bound capture date (ISO 8601 — e.g. "2010-01-01"). */
20
+ since?: string;
21
+ /** Upper-bound capture date. */
22
+ until?: string;
23
+ /** Limit only HTTP 200 captures. Default true — 4xx/5xx snapshots aren't auditable. */
24
+ status200Only?: boolean;
25
+ /** Injected fetch (tests). Defaults to globalThis.fetch (Node 18+). */
26
+ fetch?: typeof fetch;
27
+ }
28
+ interface CdxRow {
29
+ urlkey: string;
30
+ timestamp: string;
31
+ original: string;
32
+ mimetype: string;
33
+ statuscode: string;
34
+ digest: string;
35
+ length: string;
36
+ }
37
+ /** Convert CDX timestamp "20100101120000" to ISO datetime. */
38
+ export declare function cdxStampToIso(stamp: string): string;
39
+ export declare function snapshotUrl(timestamp: string, original: string): string;
40
+ /** Sample `count` evenly-spaced rows from a sorted list. Always includes first and last. */
41
+ export declare function sampleEvenly<T>(rows: T[], count: number): T[];
42
+ /** Parse the CDX JSON response (first row is a header). */
43
+ export declare function parseCdxRows(json: unknown): CdxRow[];
44
+ /** Discover N evenly-spaced wayback snapshots for a URL. */
45
+ export declare function discoverWaybackSnapshots(url: string, opts?: WaybackOptions): Promise<JobTarget[]>;
46
+ /** Expand a list of seed URLs into wayback targets, in parallel. */
47
+ export declare function expandWaybackTargets(urls: string[], opts?: WaybackOptions): Promise<JobTarget[]>;
48
+ export {};
49
+ //# sourceMappingURL=wayback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wayback.d.ts","sourceRoot":"","sources":["../../src/discover/wayback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAIjD,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+DAA+D;IAC/D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uFAAuF;IACvF,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,uEAAuE;IACvE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CACrB;AAED,UAAU,MAAM;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAcD,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASnD;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE,CAU7D;AAED,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAkBpD;AAED,4DAA4D;AAC5D,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAmC3G;AAED,oEAAoE;AACpE,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAG1G"}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Wayback Machine snapshot discoverer (CDX API).
3
+ *
4
+ * Uses archive.org's CDX server to list captures of a URL, then samples
5
+ * `count` snapshots evenly across the time range. The CDX API is rate-limited
6
+ * (~15 req/s) but for the small N we use here we never approach the cap.
7
+ *
8
+ * CDX response shape:
9
+ * [["urlkey","timestamp","original","mimetype","statuscode","digest","length"],
10
+ * ["com,stripe)/", "20100101120000", "https://stripe.com/", "text/html", "200", "...", "1234"],
11
+ * ...]
12
+ *
13
+ * Snapshot URL = `https://web.archive.org/web/<timestamp>/<original>`.
14
+ */
15
+ const CDX_ENDPOINT = 'https://web.archive.org/cdx/search/cdx';
16
+ const DEFAULT_COUNT = 5;
17
+ /** Convert ISO date "2010-01-01" to CDX yyyymmddhhmmss. */
18
+ function isoToCdxStamp(iso, end = false) {
19
+ const d = new Date(iso);
20
+ if (Number.isNaN(d.getTime()))
21
+ throw new Error(`wayback: invalid date "${iso}"`);
22
+ const y = d.getUTCFullYear();
23
+ const m = String(d.getUTCMonth() + 1).padStart(2, '0');
24
+ const day = String(d.getUTCDate()).padStart(2, '0');
25
+ return end ? `${y}${m}${day}235959` : `${y}${m}${day}000000`;
26
+ }
27
+ /** Convert CDX timestamp "20100101120000" to ISO datetime. */
28
+ export function cdxStampToIso(stamp) {
29
+ if (stamp.length < 14)
30
+ throw new Error(`wayback: malformed CDX timestamp "${stamp}"`);
31
+ const y = stamp.slice(0, 4);
32
+ const m = stamp.slice(4, 6);
33
+ const d = stamp.slice(6, 8);
34
+ const hh = stamp.slice(8, 10);
35
+ const mm = stamp.slice(10, 12);
36
+ const ss = stamp.slice(12, 14);
37
+ return `${y}-${m}-${d}T${hh}:${mm}:${ss}Z`;
38
+ }
39
+ export function snapshotUrl(timestamp, original) {
40
+ return `https://web.archive.org/web/${timestamp}/${original}`;
41
+ }
42
+ /** Sample `count` evenly-spaced rows from a sorted list. Always includes first and last. */
43
+ export function sampleEvenly(rows, count) {
44
+ if (rows.length <= count)
45
+ return [...rows];
46
+ if (count <= 0)
47
+ return [];
48
+ if (count === 1)
49
+ return [rows[Math.floor((rows.length - 1) / 2)]];
50
+ const out = [];
51
+ const step = (rows.length - 1) / (count - 1);
52
+ for (let i = 0; i < count; i++) {
53
+ out.push(rows[Math.round(i * step)]);
54
+ }
55
+ return out;
56
+ }
57
+ /** Parse the CDX JSON response (first row is a header). */
58
+ export function parseCdxRows(json) {
59
+ if (!Array.isArray(json) || json.length < 2)
60
+ return [];
61
+ // Skip header row.
62
+ const rows = json.slice(1);
63
+ const out = [];
64
+ for (const r of rows) {
65
+ if (!Array.isArray(r) || r.length < 7)
66
+ continue;
67
+ out.push({
68
+ urlkey: String(r[0]),
69
+ timestamp: String(r[1]),
70
+ original: String(r[2]),
71
+ mimetype: String(r[3]),
72
+ statuscode: String(r[4]),
73
+ digest: String(r[5]),
74
+ length: String(r[6]),
75
+ });
76
+ }
77
+ return out;
78
+ }
79
+ /** Discover N evenly-spaced wayback snapshots for a URL. */
80
+ export async function discoverWaybackSnapshots(url, opts = {}) {
81
+ const fetchImpl = opts.fetch ?? globalThis.fetch;
82
+ if (!fetchImpl)
83
+ throw new Error('wayback: no fetch implementation available');
84
+ const count = opts.count ?? DEFAULT_COUNT;
85
+ const params = new URLSearchParams({
86
+ url,
87
+ output: 'json',
88
+ // collapse=timestamp:6 dedupes to one capture per month (yyyymm = 6 chars).
89
+ // Without this, CDX returns every capture in the window — which for popular
90
+ // sites is tens of thousands and silently skews `sampleEvenly` if combined
91
+ // with a `limit`. With the collapse, the row count is bounded by the
92
+ // window length in months, so we don't need a limit.
93
+ collapse: 'timestamp:6',
94
+ });
95
+ if (opts.since)
96
+ params.set('from', isoToCdxStamp(opts.since));
97
+ if (opts.until)
98
+ params.set('to', isoToCdxStamp(opts.until, true));
99
+ if (opts.status200Only !== false) {
100
+ params.set('filter', 'statuscode:200');
101
+ }
102
+ const resp = await fetchImpl(`${CDX_ENDPOINT}?${params.toString()}`);
103
+ if (!resp.ok) {
104
+ throw new Error(`wayback: CDX returned ${resp.status} for ${url}`);
105
+ }
106
+ const json = await resp.json();
107
+ const rows = parseCdxRows(json);
108
+ if (rows.length === 0)
109
+ return [];
110
+ // CDX returns chronological order by default. Sample evenly across.
111
+ const sampled = sampleEvenly(rows, count);
112
+ return sampled.map(r => ({
113
+ url,
114
+ snapshotUrl: snapshotUrl(r.timestamp, r.original),
115
+ capturedAt: cdxStampToIso(r.timestamp),
116
+ }));
117
+ }
118
+ /** Expand a list of seed URLs into wayback targets, in parallel. */
119
+ export async function expandWaybackTargets(urls, opts = {}) {
120
+ const all = await Promise.all(urls.map(u => discoverWaybackSnapshots(u, opts).catch(() => [])));
121
+ return all.flat();
122
+ }
123
+ //# sourceMappingURL=wayback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wayback.js","sourceRoot":"","sources":["../../src/discover/wayback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Anti-bot / blocked-page detection. Pure pattern match against an audit's
3
+ * report.json — we propagate the existing audit signals rather than re-running
4
+ * inference.
5
+ *
6
+ * Returns a reason string when blocked (so the job can carry it through to
7
+ * the result envelope), else null.
8
+ */
9
+ export interface BlockSignals {
10
+ title?: string;
11
+ intent?: string;
12
+ type?: string;
13
+ ensembleConfidence?: number;
14
+ findingCount?: number;
15
+ }
16
+ /** Check the audit's report.json for anti-bot patterns. Returns the reason or null. */
17
+ export declare function detectBlock(report: unknown): string | null;
18
+ export declare function reasonFor(s: BlockSignals): string | null;
19
+ //# sourceMappingURL=anti-bot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anti-bot.d.ts","sourceRoot":"","sources":["../../src/jobs/anti-bot.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsBH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAc1D;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,IAAI,CAmBxD"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Anti-bot / blocked-page detection. Pure pattern match against an audit's
3
+ * report.json — we propagate the existing audit signals rather than re-running
4
+ * inference.
5
+ *
6
+ * Returns a reason string when blocked (so the job can carry it through to
7
+ * the result envelope), else null.
8
+ */
9
+ const TITLE_PATTERNS = [
10
+ /just a moment\.{3}/i,
11
+ /^attention required/i,
12
+ /access denied/i,
13
+ /verify you are human/i,
14
+ /enable javascript and cookies/i,
15
+ /one more step/i,
16
+ /please complete the security check/i,
17
+ /^cloudflare/i,
18
+ /challenge[- ]page/i,
19
+ ];
20
+ const INTENT_PATTERNS = [
21
+ /cloudflare challenge/i,
22
+ /anti.?bot/i,
23
+ /captcha/i,
24
+ /verify (the )?(human|user|browser)/i,
25
+ /access (denied|restricted|blocked)/i,
26
+ ];
27
+ /** Check the audit's report.json for anti-bot patterns. Returns the reason or null. */
28
+ export function detectBlock(report) {
29
+ const r = report;
30
+ const page = r.pages?.[0];
31
+ if (!page)
32
+ return null;
33
+ const v2cls = page.auditResult?.classification;
34
+ const cls = v2cls ?? page.classification ?? {};
35
+ const signals = {
36
+ title: page.title,
37
+ intent: cls.intent,
38
+ type: cls.type,
39
+ ensembleConfidence: cls.ensembleConfidence,
40
+ findingCount: page.findings?.length ?? 0,
41
+ };
42
+ return reasonFor(signals);
43
+ }
44
+ export function reasonFor(s) {
45
+ const title = (s.title ?? '').trim();
46
+ const intent = (s.intent ?? '').trim();
47
+ if (TITLE_PATTERNS.some(re => re.test(title))) {
48
+ return `blocked: page title looks like an anti-bot challenge ("${title.slice(0, 80)}")`;
49
+ }
50
+ if (INTENT_PATTERNS.some(re => re.test(intent))) {
51
+ return `blocked: classification intent indicates a challenge page ("${intent.slice(0, 80)}")`;
52
+ }
53
+ // Last-resort heuristic: zero findings + very low ensemble confidence + unknown
54
+ // page-type is overwhelmingly an anti-bot or empty page. Leaving it in the
55
+ // leaderboard pollutes rankings.
56
+ if ((s.findingCount ?? 0) === 0
57
+ && typeof s.ensembleConfidence === 'number'
58
+ && s.ensembleConfidence < 0.35
59
+ && s.type === 'unknown') {
60
+ return 'blocked: zero findings, low classifier confidence, unknown type — likely empty/blocked';
61
+ }
62
+ return null;
63
+ }
64
+ //# sourceMappingURL=anti-bot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anti-bot.js","sourceRoot":"","sources":["../../src/jobs/anti-bot.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,cAAc,GAAG;IACrB,qBAAqB;IACrB,sBAAsB;IACtB,gBAAgB;IAChB,uBAAuB;IACvB,gCAAgC;IAChC,gBAAgB;IAChB,qCAAqC;IACrC,cAAc;IACd,oBAAoB;CACrB,CAAA;AAED,MAAM,eAAe,GAAG;IACtB,uBAAuB;IACvB,YAAY;IACZ,UAAU;IACV,qCAAqC;IACrC,qCAAqC;CACtC,CAAA;AAUD,uFAAuF;AACvF,MAAM,UAAU,WAAW,CAAC,MAAe;IACzC,MAAM,CAAC,GAAG,MAA2P,CAAA;IACrQ,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IACzB,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAA;IACtB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAA;IAC9C,MAAM,GAAG,GAAG,KAAK,IAAI,IAAI,CAAC,cAAc,IAAI,EAAE,CAAA;IAC9C,MAAM,OAAO,GAAiB;QAC5B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,kBAAkB,EAAE,GAAG,CAAC,kBAAkB;QAC1C,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;KACzC,CAAA;IACD,OAAO,SAAS,CAAC,OAAO,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAe;IACvC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACpC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACtC,IAAI,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC9C,OAAO,0DAA0D,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;IACzF,CAAC;IACD,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAChD,OAAO,+DAA+D,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;IAC/F,CAAC;IACD,gFAAgF;IAChF,2EAA2E;IAC3E,iCAAiC;IACjC,IAAI,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK,CAAC;WAC1B,OAAO,CAAC,CAAC,kBAAkB,KAAK,QAAQ;WACxC,CAAC,CAAC,kBAAkB,GAAG,IAAI;WAC3B,CAAC,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,wFAAwF,CAAA;IACjG,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Pre-flight cost estimate — refuses to silently spend $1k.
3
+ *
4
+ * The numbers here are deliberately conservative and based on observed
5
+ * production telemetry for `claude-code` provider with sonnet at the time of
6
+ * writing. If the assumptions drift, only one constant changes.
7
+ */
8
+ import type { CostEstimate, JobSpec } from './types.js';
9
+ /** Average USD per single-page audit. Tuned for sonnet via claude-code provider, 1 audit pass. */
10
+ export declare const DEFAULT_PER_AUDIT_USD = 0.4;
11
+ export declare function estimateCost(spec: JobSpec, targetCount: number, perAuditUSD?: number): CostEstimate;
12
+ //# sourceMappingURL=cost-estimate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-estimate.d.ts","sourceRoot":"","sources":["../../src/jobs/cost-estimate.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEvD,kGAAkG;AAClG,eAAO,MAAM,qBAAqB,MAAM,CAAA;AAExC,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,SAAwB,GAAG,YAAY,CAUlH"}