@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,59 @@
1
+ /**
2
+ * Ethics check — Layer 7.
3
+ *
4
+ * Given a page state + classification, evaluate every loaded `EthicsRule` whose
5
+ * `appliesWhen` matches the classification. Each rule produces zero-or-one
6
+ * `EthicsViolation`. Violations enforce a hard floor on the rollup score:
7
+ * `critical-floor → 4`, `major-floor → 6`.
8
+ *
9
+ * Detector kinds:
10
+ * pattern-absent → regex must appear in page text; violation if absent
11
+ * pattern-present → regex must NOT appear in page text; violation if present
12
+ * llm-classifier → ask the LLM the question; violation when answer is yes
13
+ *
14
+ * Pattern matches are case-insensitive. The LLM classifier asks for a
15
+ * single-token yes/no answer to keep latency + cost predictable.
16
+ */
17
+ import type { Brain } from '../../../brain/index.js';
18
+ import type { AppliesWhen, EthicsRule, EthicsViolation, PageClassification, AudienceTag, ModalityTag, RegulatoryContextTag, AudienceVulnerabilityTag } from '../score-types.js';
19
+ export interface EthicsCheckContext {
20
+ /** Lowercased page text used by `pattern-absent` / `pattern-present`. */
21
+ pageText: string;
22
+ /** Page snapshot — passed verbatim to the LLM classifier prompt. */
23
+ snapshot: string;
24
+ /** The page-type / domain / maturity / designSystem classification. */
25
+ classification: PageClassification;
26
+ /** Operator-supplied audience / modality / regulatory hints (Layer 6). */
27
+ audience?: AudienceTag[];
28
+ modality?: ModalityTag[];
29
+ regulatoryContext?: RegulatoryContextTag[];
30
+ audienceVulnerability?: AudienceVulnerabilityTag[];
31
+ }
32
+ export interface EthicsCheckOptions {
33
+ /** When set, llm-classifier rules are evaluated; else skipped (deterministic-only). */
34
+ brain?: Brain;
35
+ /** Optional screenshot URL/path passed alongside snapshot context (unused today). */
36
+ screenshotPath?: string;
37
+ /** Logger override — defaults to console.warn for skipped rules. */
38
+ warn?: (msg: string) => void;
39
+ }
40
+ /**
41
+ * Run every applicable rule against the page. Returns one violation per rule
42
+ * that fires. Rules whose detector is `llm-classifier` are skipped (with a
43
+ * warning) when no `brain` is supplied — the alternative is silent passes,
44
+ * which would hide ethics gaps in offline tests.
45
+ */
46
+ export declare function checkEthics(rules: EthicsRule[], ctx: EthicsCheckContext, opts?: EthicsCheckOptions): Promise<EthicsViolation[]>;
47
+ /**
48
+ * Predicate evaluator — extends the rubric loader's logic with the layered fields
49
+ * (audience / modality / regulatoryContext / audienceVulnerability). All
50
+ * declared predicates are AND-combined.
51
+ */
52
+ export declare function appliesWhenMatches(w: AppliesWhen, ctx: EthicsCheckContext): boolean;
53
+ export declare function runLlmClassifier(brain: Brain, question: string, snapshot: string): Promise<boolean>;
54
+ /** Build the lowercased text blob used by pattern detectors. URL is intentionally excluded — URL path tokens (e.g. "no-dosage") would cause false negatives on pattern-absent rules. */
55
+ export declare function pageTextBlob(snapshot: string, extra?: {
56
+ url?: string;
57
+ title?: string;
58
+ }): string;
59
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../../src/design/audit/ethics/check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,KAAK,EACV,WAAW,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,oBAAoB,EACpB,wBAAwB,EACzB,MAAM,mBAAmB,CAAA;AAG1B,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,cAAc,EAAE,kBAAkB,CAAA;IAClC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IACxB,iBAAiB,CAAC,EAAE,oBAAoB,EAAE,CAAA;IAC1C,qBAAqB,CAAC,EAAE,wBAAwB,EAAE,CAAA;CACnD;AAED,MAAM,WAAW,kBAAkB;IACjC,uFAAuF;IACvF,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oEAAoE;IACpE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,UAAU,EAAE,EACnB,GAAG,EAAE,kBAAkB,EACvB,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,eAAe,EAAE,CAAC,CAS5B;AAaD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAqCnF;AAuCD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED,wLAAwL;AACxL,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAG/F"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Ethics check — Layer 7.
3
+ *
4
+ * Given a page state + classification, evaluate every loaded `EthicsRule` whose
5
+ * `appliesWhen` matches the classification. Each rule produces zero-or-one
6
+ * `EthicsViolation`. Violations enforce a hard floor on the rollup score:
7
+ * `critical-floor → 4`, `major-floor → 6`.
8
+ *
9
+ * Detector kinds:
10
+ * pattern-absent → regex must appear in page text; violation if absent
11
+ * pattern-present → regex must NOT appear in page text; violation if present
12
+ * llm-classifier → ask the LLM the question; violation when answer is yes
13
+ *
14
+ * Pattern matches are case-insensitive. The LLM classifier asks for a
15
+ * single-token yes/no answer to keep latency + cost predictable.
16
+ */
17
+ import { rollupCapFor } from './loader.js';
18
+ /**
19
+ * Run every applicable rule against the page. Returns one violation per rule
20
+ * that fires. Rules whose detector is `llm-classifier` are skipped (with a
21
+ * warning) when no `brain` is supplied — the alternative is silent passes,
22
+ * which would hide ethics gaps in offline tests.
23
+ */
24
+ export async function checkEthics(rules, ctx, opts = {}) {
25
+ const warn = opts.warn ?? ((m) => console.warn(m));
26
+ const violations = [];
27
+ for (const rule of rules) {
28
+ if (!appliesWhenMatches(rule.appliesWhen, ctx))
29
+ continue;
30
+ const fired = await runDetector(rule, ctx, opts.brain, warn);
31
+ if (fired)
32
+ violations.push(toViolation(rule));
33
+ }
34
+ return violations;
35
+ }
36
+ function toViolation(rule) {
37
+ return {
38
+ ruleId: rule.ruleId,
39
+ detected: true,
40
+ severity: rule.severity,
41
+ rollupCap: rollupCapFor(rule.severity),
42
+ remediation: rule.remediation,
43
+ ...(rule.citation ? { citation: rule.citation } : {}),
44
+ };
45
+ }
46
+ /**
47
+ * Predicate evaluator — extends the rubric loader's logic with the layered fields
48
+ * (audience / modality / regulatoryContext / audienceVulnerability). All
49
+ * declared predicates are AND-combined.
50
+ */
51
+ export function appliesWhenMatches(w, ctx) {
52
+ if (w.universal)
53
+ return true;
54
+ const cls = ctx.classification;
55
+ if (w.type?.length && !w.type.includes(cls.type))
56
+ return false;
57
+ if (w.maturity?.length && !w.maturity.includes(cls.maturity))
58
+ return false;
59
+ if (w.designSystem?.length && !w.designSystem.includes(cls.designSystem))
60
+ return false;
61
+ if (w.domain?.length) {
62
+ const domain = (cls.domain ?? '').toLowerCase();
63
+ const ok = w.domain.some(d => domain.includes(d.toLowerCase()));
64
+ if (!ok)
65
+ return false;
66
+ }
67
+ if (w.audience?.length) {
68
+ if (!w.audience.some(a => (ctx.audience ?? []).includes(a)))
69
+ return false;
70
+ }
71
+ if (w.modality?.length) {
72
+ if (!w.modality.some(m => (ctx.modality ?? []).includes(m)))
73
+ return false;
74
+ }
75
+ if (w.regulatoryContext?.length) {
76
+ if (!w.regulatoryContext.some(r => (ctx.regulatoryContext ?? []).includes(r)))
77
+ return false;
78
+ }
79
+ if (w.audienceVulnerability?.length) {
80
+ if (!w.audienceVulnerability.some(v => (ctx.audienceVulnerability ?? []).includes(v)))
81
+ return false;
82
+ }
83
+ // Same conservative behavior as the rubric loader: with no predicates and
84
+ // no `universal: true`, the rule does NOT apply (don't fire blindly).
85
+ const hasPredicate = !!w.type?.length ||
86
+ !!w.maturity?.length ||
87
+ !!w.designSystem?.length ||
88
+ !!w.domain?.length ||
89
+ !!w.audience?.length ||
90
+ !!w.modality?.length ||
91
+ !!w.regulatoryContext?.length ||
92
+ !!w.audienceVulnerability?.length;
93
+ return hasPredicate;
94
+ }
95
+ async function runDetector(rule, ctx, brain, warn) {
96
+ const d = rule.detector;
97
+ if (d.kind === 'pattern-absent') {
98
+ const re = compilePattern(d.pattern);
99
+ return !re.test(ctx.pageText);
100
+ }
101
+ if (d.kind === 'pattern-present') {
102
+ const re = compilePattern(d.pattern);
103
+ return re.test(ctx.pageText);
104
+ }
105
+ if (d.kind === 'llm-classifier') {
106
+ if (!brain) {
107
+ warn(`ethics: skipping llm-classifier rule ${rule.ruleId} — no brain provided`);
108
+ return false;
109
+ }
110
+ return await runLlmClassifier(brain, d.llmCheck, ctx.snapshot);
111
+ }
112
+ return false;
113
+ }
114
+ function compilePattern(pattern) {
115
+ // Allow already-anchored regexes; default is case-insensitive substring.
116
+ try {
117
+ return new RegExp(pattern, 'i');
118
+ }
119
+ catch {
120
+ // Fallback: treat as a literal token if regex compile fails.
121
+ return new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'i');
122
+ }
123
+ }
124
+ const LLM_SYSTEM = `You are an ethics auditor. Answer the user's yes/no question about the page snapshot. Respond with exactly one token — yes or no — followed by an optional one-sentence rationale. Do not hedge. If the evidence is missing, answer no.`;
125
+ export async function runLlmClassifier(brain, question, snapshot) {
126
+ const truncated = snapshot.length > 8000 ? `${snapshot.slice(0, 8000)}\n…[truncated]` : snapshot;
127
+ const user = `QUESTION: ${question}\n\nPAGE SNAPSHOT:\n${truncated}\n\nAnswer yes or no.`;
128
+ const { text } = await brain.complete(LLM_SYSTEM, user, { maxOutputTokens: 80 });
129
+ const first = text.trim().toLowerCase().match(/^[a-z]+/)?.[0] ?? '';
130
+ return first === 'yes';
131
+ }
132
+ /** Build the lowercased text blob used by pattern detectors. URL is intentionally excluded — URL path tokens (e.g. "no-dosage") would cause false negatives on pattern-absent rules. */
133
+ export function pageTextBlob(snapshot, extra) {
134
+ const parts = [snapshot, extra?.title ?? ''];
135
+ return parts.join('\n').toLowerCase();
136
+ }
137
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../../src/design/audit/ethics/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Ethics rule loader — Layer 7.
3
+ *
4
+ * Loads `EthicsRule[]` from `rules/*.yaml`. Idempotent + cached: the in-memory
5
+ * cache keys on directory path so repeated calls (per-page audits) never re-IO.
6
+ *
7
+ * Each YAML file is a list of rule objects. The minimal parser supports the
8
+ * shape used in the RFC: `- key: value` items with nested objects and inline
9
+ * `[a, b]` lists. No external yaml dep — same approach as rubric/loader.ts.
10
+ */
11
+ import type { EthicsRule, EthicsSeverity } from '../score-types.js';
12
+ /** Severity → rollup ceiling. critical-floor caps at 4; major-floor caps at 6. */
13
+ export declare function rollupCapFor(severity: EthicsSeverity): number;
14
+ /**
15
+ * Load every `*.yaml` rule file in `dir`. Cached by absolute path.
16
+ * Returns a stable order (sorted by filename + position within file).
17
+ */
18
+ export declare function loadEthicsRules(dir?: string): EthicsRule[];
19
+ /** Reset cache — test-only. */
20
+ export declare function clearEthicsRuleCache(): void;
21
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../../src/design/audit/ethics/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EACV,UAAU,EAEV,cAAc,EAGf,MAAM,mBAAmB,CAAA;AAO1B,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAE7D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAA0B,GAAG,UAAU,EAAE,CAkB7E;AAED,+BAA+B;AAC/B,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Ethics rule loader — Layer 7.
3
+ *
4
+ * Loads `EthicsRule[]` from `rules/*.yaml`. Idempotent + cached: the in-memory
5
+ * cache keys on directory path so repeated calls (per-page audits) never re-IO.
6
+ *
7
+ * Each YAML file is a list of rule objects. The minimal parser supports the
8
+ * shape used in the RFC: `- key: value` items with nested objects and inline
9
+ * `[a, b]` lists. No external yaml dep — same approach as rubric/loader.ts.
10
+ */
11
+ import * as fs from 'node:fs';
12
+ import * as path from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
15
+ const BUILTIN_RULES_DIR = path.join(__dirname, 'rules');
16
+ const cache = new Map();
17
+ /** Severity → rollup ceiling. critical-floor caps at 4; major-floor caps at 6. */
18
+ export function rollupCapFor(severity) {
19
+ return severity === 'critical-floor' ? 4 : 6;
20
+ }
21
+ /**
22
+ * Load every `*.yaml` rule file in `dir`. Cached by absolute path.
23
+ * Returns a stable order (sorted by filename + position within file).
24
+ */
25
+ export function loadEthicsRules(dir = BUILTIN_RULES_DIR) {
26
+ const abs = path.resolve(dir);
27
+ const cached = cache.get(abs);
28
+ if (cached)
29
+ return cached;
30
+ if (!fs.existsSync(abs)) {
31
+ cache.set(abs, []);
32
+ return [];
33
+ }
34
+ const rules = [];
35
+ const files = fs.readdirSync(abs).filter(f => f.endsWith('.yaml')).sort();
36
+ for (const f of files) {
37
+ const file = path.join(abs, f);
38
+ const raw = fs.readFileSync(file, 'utf-8');
39
+ const parsed = parseRuleList(raw, file);
40
+ for (const r of parsed)
41
+ rules.push(r);
42
+ }
43
+ cache.set(abs, rules);
44
+ return rules;
45
+ }
46
+ /** Reset cache — test-only. */
47
+ export function clearEthicsRuleCache() {
48
+ cache.clear();
49
+ }
50
+ function parseRuleList(text, sourceFile) {
51
+ const items = splitTopLevelItems(text);
52
+ return items.map((block, idx) => parseRule(block, `${sourceFile}#${idx}`));
53
+ }
54
+ /** Split a YAML doc into top-level `- item` blocks (one block per rule). */
55
+ function splitTopLevelItems(text) {
56
+ const lines = text.split('\n');
57
+ const items = [];
58
+ let current = null;
59
+ for (const line of lines) {
60
+ if (/^\s*#/.test(line) || line.trim() === '') {
61
+ if (current)
62
+ current.push(line);
63
+ continue;
64
+ }
65
+ if (line.startsWith('- ')) {
66
+ if (current)
67
+ items.push(current.join('\n'));
68
+ current = [line.slice(2)];
69
+ }
70
+ else if (current) {
71
+ // Indented continuation. Strip 2 leading spaces if present so nesting
72
+ // levels become consistent within the item.
73
+ current.push(line.startsWith(' ') ? line.slice(2) : line);
74
+ }
75
+ }
76
+ if (current)
77
+ items.push(current.join('\n'));
78
+ return items;
79
+ }
80
+ function parseRule(block, ref) {
81
+ const meta = parseYamlBlock(block);
82
+ const ruleId = stringField(meta, 'ruleId', ref);
83
+ const category = stringField(meta, 'category', ref);
84
+ const severity = stringField(meta, 'severity', ref);
85
+ if (severity !== 'critical-floor' && severity !== 'major-floor') {
86
+ throw new Error(`ethics rule ${ruleId} (${ref}): invalid severity ${severity}`);
87
+ }
88
+ const remediation = stringField(meta, 'remediation', ref);
89
+ const appliesWhen = meta.appliesWhen ?? {};
90
+ const detectorRaw = meta.detector ?? {};
91
+ const detector = parseDetector(detectorRaw, ruleId);
92
+ const citation = meta.citation != null ? String(meta.citation) : undefined;
93
+ return {
94
+ ruleId,
95
+ category,
96
+ severity,
97
+ appliesWhen,
98
+ detector,
99
+ remediation,
100
+ ...(citation ? { citation } : {}),
101
+ };
102
+ }
103
+ function parseDetector(d, ruleId) {
104
+ const kind = String(d.kind ?? '');
105
+ if (kind === 'pattern-absent' || kind === 'pattern-present') {
106
+ const pattern = String(d.pattern ?? '');
107
+ if (!pattern)
108
+ throw new Error(`ethics rule ${ruleId}: detector.pattern required for ${kind}`);
109
+ return { kind, pattern };
110
+ }
111
+ if (kind === 'llm-classifier') {
112
+ const llmCheck = String(d.llmCheck ?? '');
113
+ if (!llmCheck)
114
+ throw new Error(`ethics rule ${ruleId}: detector.llmCheck required for llm-classifier`);
115
+ return { kind, llmCheck };
116
+ }
117
+ throw new Error(`ethics rule ${ruleId}: unknown detector.kind ${kind}`);
118
+ }
119
+ function stringField(meta, key, ref) {
120
+ const v = meta[key];
121
+ if (v == null || String(v) === '') {
122
+ throw new Error(`ethics rule (${ref}): missing required field ${key}`);
123
+ }
124
+ return String(v);
125
+ }
126
+ /**
127
+ * YAML block parser supporting:
128
+ * key: scalar
129
+ * key: [a, b]
130
+ * key: | → folded multi-line block (preserves newlines)
131
+ * key: > or just continuation lines indented under the key
132
+ * key:
133
+ * subkey: value
134
+ * listKey: [a, b]
135
+ */
136
+ function parseYamlBlock(text) {
137
+ const lines = text.split('\n');
138
+ const result = {};
139
+ let i = 0;
140
+ while (i < lines.length) {
141
+ const line = lines[i];
142
+ if (!line.trim() || line.trim().startsWith('#')) {
143
+ i++;
144
+ continue;
145
+ }
146
+ const m = line.match(/^([a-zA-Z][\w-]*):\s*(.*)$/);
147
+ if (!m) {
148
+ i++;
149
+ continue;
150
+ }
151
+ const [, key, valueRaw] = m;
152
+ const value = valueRaw.trim();
153
+ if (value === '|' || value === '>') {
154
+ // Folded block: collect indented continuation lines.
155
+ const collected = [];
156
+ i++;
157
+ while (i < lines.length && (lines[i].startsWith(' ') || lines[i].trim() === '')) {
158
+ collected.push(lines[i].replace(/^ {2}/, ''));
159
+ i++;
160
+ }
161
+ result[key] = collected.join(value === '|' ? '\n' : ' ').trim();
162
+ }
163
+ else if (value === '') {
164
+ // Nested object — collect indented lines.
165
+ const nested = {};
166
+ i++;
167
+ while (i < lines.length && (lines[i].startsWith(' ') || lines[i].trim() === '')) {
168
+ if (!lines[i].trim()) {
169
+ i++;
170
+ continue;
171
+ }
172
+ const nm = lines[i].match(/^\s+([a-zA-Z][\w-]*):\s*(.*)$/);
173
+ if (nm) {
174
+ nested[nm[1]] = parseScalarOrList(nm[2].trim());
175
+ }
176
+ i++;
177
+ }
178
+ result[key] = nested;
179
+ }
180
+ else {
181
+ result[key] = parseScalarOrList(value);
182
+ i++;
183
+ }
184
+ }
185
+ return result;
186
+ }
187
+ function parseScalarOrList(value) {
188
+ if (value.startsWith('[') && value.endsWith(']')) {
189
+ return value
190
+ .slice(1, -1)
191
+ .split(',')
192
+ .map(s => s.trim().replace(/^['"]|['"]$/g, ''))
193
+ .filter(Boolean);
194
+ }
195
+ // Strip surrounding quotes for plain scalars.
196
+ if ((value.startsWith("'") && value.endsWith("'")) || (value.startsWith('"') && value.endsWith('"'))) {
197
+ return value.slice(1, -1);
198
+ }
199
+ if (value === 'true')
200
+ return true;
201
+ if (value === 'false')
202
+ return false;
203
+ if (/^-?\d+(\.\d+)?$/.test(value))
204
+ return Number(value);
205
+ return value;
206
+ }
207
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../../src/design/audit/ethics/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ # Financial product ethics rules.
2
+ # Anchored to CFPB Reg E / Reg Z, EU PSD2, and SEC Rule 10b-10 disclosures.
3
+
4
+ - ruleId: finance:fees-disclosed-pre-commitment
5
+ category: finance
6
+ severity: critical-floor
7
+ appliesWhen:
8
+ type: [ecommerce]
9
+ domain: [fintech, finance, banking, payments]
10
+ detector:
11
+ kind: llm-classifier
12
+ llmCheck: Does this checkout page hide, defer, or fail to itemize any fees, taxes, FX, or charges that the user will pay, with the pay/commit button reachable before the totals are fully visible?
13
+ remediation: Surface every line item (fees, taxes, FX) above the pay button.
14
+ citation: CFPB 12 CFR 1026 Reg Z / FTC Junk Fees Rule
15
+
16
+ - ruleId: finance:apr-or-effective-rate-shown
17
+ category: finance
18
+ severity: major-floor
19
+ appliesWhen:
20
+ domain: [fintech, finance, banking, payments, lending]
21
+ detector:
22
+ kind: pattern-absent
23
+ pattern: (APR|annual percentage rate|effective (interest )?rate|finance charge)
24
+ remediation: Display APR or effective interest rate alongside any credit, lending, or yield-bearing offer.
25
+ citation: TILA 15 USC 1638 / CFPB 12 CFR 1026.18
26
+
27
+ - ruleId: finance:risk-disclosure-required
28
+ category: finance
29
+ severity: major-floor
30
+ appliesWhen:
31
+ domain: [fintech, finance, crypto, investing, trading]
32
+ audienceVulnerability: [high-stakes-financial]
33
+ detector:
34
+ kind: llm-classifier
35
+ llmCheck: Does this trading / investing / staking page allow the user to commit funds WITHOUT a clearly visible disclosure of principal-loss, volatility, or non-FDIC-insurance risk above the action button?
36
+ remediation: Show risk-of-loss and insurance-status disclosures above the action button on any investing, trading, or staking surface.
37
+ citation: SEC Rule 10b-10 / FINRA Rule 2210
@@ -0,0 +1,37 @@
1
+ # Kids-targeted product ethics rules.
2
+ # Anchored to COPPA + UK ICO Age Appropriate Design Code (AADC).
3
+
4
+ - ruleId: kids:dark-patterns-prohibited
5
+ category: kids
6
+ severity: critical-floor
7
+ appliesWhen:
8
+ audience: [kids]
9
+ detector:
10
+ kind: llm-classifier
11
+ llmCheck: Does this page use any dark pattern (hidden costs, forced action, fake urgency, confirmshaming, manipulated visual hierarchy) targeting a minor user?
12
+ remediation: Remove all dark patterns. Use clear, age-appropriate, friction-symmetric flows.
13
+ citation: COPPA 16 CFR 312.5 / FTC Dark Patterns Report 2022
14
+
15
+ - ruleId: kids:age-gate-required
16
+ category: kids
17
+ severity: critical-floor
18
+ appliesWhen:
19
+ audience: [kids]
20
+ audienceVulnerability: [minor-facing]
21
+ detector:
22
+ kind: pattern-absent
23
+ pattern: (age|date of birth|verify your age)
24
+ remediation: Implement an age gate before collecting any data or showing user-generated content.
25
+ citation: COPPA 16 CFR 312.5
26
+
27
+ - ruleId: kids:data-minimization-default
28
+ category: kids
29
+ severity: major-floor
30
+ appliesWhen:
31
+ audience: [kids]
32
+ regulatoryContext: [coppa]
33
+ detector:
34
+ kind: llm-classifier
35
+ llmCheck: Does this page request data fields from a child that are NOT strictly necessary for the activity (e.g. unmarked optional fields, profile / social / friend-graph fields, location or contact data not required for the task)?
36
+ remediation: Default to data minimization for child users — collect only what is strictly necessary, mark every optional field, and disable profile/social fields by default.
37
+ citation: ICO AADC Standard 8 / COPPA 16 CFR 312.7
@@ -0,0 +1,35 @@
1
+ # Legal / regulatory consent rules.
2
+ # Anchored to GDPR, ePrivacy Directive, and CCPA/CPRA notice-at-collection.
3
+
4
+ - ruleId: legal:gdpr-cookie-consent
5
+ category: legal
6
+ severity: major-floor
7
+ appliesWhen:
8
+ regulatoryContext: [gdpr]
9
+ detector:
10
+ kind: pattern-absent
11
+ pattern: (cookie|consent|necessary|preferences)
12
+ remediation: Display GDPR-compliant cookie consent banner with granular controls.
13
+ citation: GDPR Art. 7 / ePrivacy Directive 2002/58/EC Art. 5(3)
14
+
15
+ - ruleId: legal:privacy-policy-link-required
16
+ category: legal
17
+ severity: major-floor
18
+ appliesWhen:
19
+ regulatoryContext: [gdpr]
20
+ detector:
21
+ kind: pattern-absent
22
+ pattern: (privacy policy|privacy notice|data protection)
23
+ remediation: Provide a clearly labeled privacy policy / notice link on every page that processes personal data.
24
+ citation: GDPR Art. 13-14
25
+
26
+ - ruleId: legal:ccpa-do-not-sell-link
27
+ category: legal
28
+ severity: major-floor
29
+ appliesWhen:
30
+ regulatoryContext: [gdpr]
31
+ detector:
32
+ kind: pattern-absent
33
+ pattern: (do not sell|do not share|opt.?out|your privacy choices)
34
+ remediation: Provide a "Do Not Sell or Share My Personal Information" / "Your Privacy Choices" link in the global footer.
35
+ citation: CCPA Cal. Civ. Code 1798.135 / CPRA 1798.121
@@ -0,0 +1,36 @@
1
+ # Medical / clinical / pharmacy ethics rules.
2
+ # Anchored to FDA labeling regs, ICH E2 pharmacovigilance, and ONC info-blocking.
3
+
4
+ - ruleId: medical:dosage-warning-required
5
+ category: medical
6
+ severity: critical-floor
7
+ appliesWhen:
8
+ domain: [medical, clinical, pharmacy, health]
9
+ detector:
10
+ kind: pattern-absent
11
+ pattern: (dosage|warning|contraindication|adverse|side effect)
12
+ remediation: Display dosage warnings, contraindications, and adverse-effect summaries before any prescription action.
13
+ citation: FDA 21 CFR 201.57
14
+
15
+ - ruleId: medical:adverse-event-reporting-path
16
+ category: medical
17
+ severity: major-floor
18
+ appliesWhen:
19
+ domain: [medical, clinical, pharmacy, health]
20
+ detector:
21
+ kind: pattern-absent
22
+ pattern: (report.{0,20}(side effect|adverse|reaction)|MedWatch|FDA 1088|pharmacovigilance)
23
+ remediation: Provide a visible adverse-event reporting path (MedWatch link or equivalent) on any prescribing or dispensing surface.
24
+ citation: FDA 21 CFR 314.80 / ICH E2D
25
+
26
+ - ruleId: medical:patient-education-disclosure
27
+ category: medical
28
+ severity: major-floor
29
+ appliesWhen:
30
+ domain: [medical, clinical, pharmacy, health]
31
+ audienceVulnerability: [patient-facing]
32
+ detector:
33
+ kind: llm-classifier
34
+ llmCheck: Does this patient-facing page request a clinical action or health-data submission WITHOUT first presenting plain-language patient education (indications, risks, instructions for use)?
35
+ remediation: Surface plain-language patient education (indications, risks, instructions) ahead of any clinical action a patient can take.
36
+ citation: ONC 45 CFR 170.315(g)(9) Patient Education
@@ -1 +1 @@
1
- {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../src/design/audit/evaluate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,eAAe,EAChB,MAAM,YAAY,CAAA;AAInB,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;IAChB,cAAc,EAAE,kBAAkB,CAAA;IAClC,MAAM,EAAE,cAAc,CAAA;IACtB,YAAY,EAAE,iBAAiB,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAA;CAC3B;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;AAE9F,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,WAAW,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,eAAe,EAAE,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAAA;CAC3E;AAED,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAA;IACzD,wDAAwD;IACxD,cAAc,CAAC,EAAE,CAAC,cAAc,EAAE,kBAAkB,KAAK,MAAM,CAAA;IAC/D;+EAC2E;IAC3E,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;IACtD,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD,sFAAsF;IACtF,oBAAoB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;CAC9F;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAOvC,CAAA;AAED,eAAO,MAAM,4BAA4B;;;CAA4B,CAAA;AAErE,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,WAAW,EAAE,CAYrG,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,CA6D3D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAyEjE,CAAA;AAED,wBAAgB,kBAAkB,CAChC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,EAAE,EACvC,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAAC,SAAS,CAAC,EAAE,cAAc,CAAA;CAAE,GAC5E,WAAW,EAAE,CAaf;AA8CD,wBAAgB,cAAc,CAAC,cAAc,EAAE,kBAAkB,GAAG,MAAM,CAwBzE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAqH7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,iBAAiB,GAAG,aAAa,EAAE,CAuGvF;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,eAAe,CAAC,CAmG1B;AA8ID,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAiC,GACpE,MAAM,CASR"}
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../src/design/audit/evaluate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,eAAe,EAChB,MAAM,YAAY,CAAA;AAInB,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,SAAS,CAAA;IAChB,cAAc,EAAE,kBAAkB,CAAA;IAClC,MAAM,EAAE,cAAc,CAAA;IACtB,YAAY,EAAE,iBAAiB,CAAA;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,WAAW,EAAE,CAAA;IAC3B;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAA;CAC3B;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAA;AAE9F,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,WAAW,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,eAAe,EAAE,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAAA;CAC3E;AAED,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAA;IACzD,wDAAwD;IACxD,cAAc,CAAC,EAAE,CAAC,cAAc,EAAE,kBAAkB,KAAK,MAAM,CAAA;IAC/D;+EAC2E;IAC3E,eAAe,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAA;IACtD,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD,sFAAsF;IACtF,oBAAoB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC,CAAA;CAC9F;AAED,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAOvC,CAAA;AAED,eAAO,MAAM,4BAA4B;;;CAA4B,CAAA;AAErE,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,GAAG,SAAS,EAAE,WAAW,EAAE,CAYrG,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,CA6D3D,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAyEjE,CAAA;AAED,wBAAgB,kBAAkB,CAChC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,EAAE,EACvC,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAAC,SAAS,CAAC,EAAE,cAAc,CAAA;CAAE,GAC5E,WAAW,EAAE,CAgBf;AA8CD,wBAAgB,cAAc,CAAC,cAAc,EAAE,kBAAkB,GAAG,MAAM,CAwBzE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAqH7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,iBAAiB,GAAG,aAAa,EAAE,CAuGvF;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,eAAe,CAAC,CAmG1B;AA8ID,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,GAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAiC,GACpE,MAAM,CASR"}
@@ -175,7 +175,10 @@ export function resolveAuditPasses(value, options) {
175
175
  const raw = value?.trim().toLowerCase();
176
176
  if (!raw || raw === 'standard' || raw === 'single' || raw === 'default')
177
177
  return ['standard'];
178
- if (raw === 'deep' || raw === 'parallel' || raw === 'full') {
178
+ // Layer 1 `auto` is the new default for the canonical path: classification-aware
179
+ // selection mirroring `deep`. The pipeline runs the ensemble classifier
180
+ // first, then this picks the focused pass bundle for that page type.
181
+ if (raw === 'auto' || raw === 'deep' || raw === 'parallel' || raw === 'full') {
179
182
  return deepPassesForClassification(options?.classification, options?.overrides);
180
183
  }
181
184
  if (raw === 'max' || raw === 'exhaustive')