@tangle-network/browser-agent-driver 0.29.0 → 0.31.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.
- package/dist/brain/index.d.ts +15 -1
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +67 -5
- package/dist/brain/index.js.map +1 -1
- package/dist/cli-ack-patch.d.ts +39 -0
- package/dist/cli-ack-patch.d.ts.map +1 -0
- package/dist/cli-ack-patch.js +47 -0
- package/dist/cli-ack-patch.js.map +1 -0
- package/dist/cli-design-audit.d.ts +16 -0
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +232 -7
- package/dist/cli-design-audit.js.map +1 -1
- package/dist/cli-jobs.d.ts +13 -0
- package/dist/cli-jobs.d.ts.map +1 -0
- package/dist/cli-jobs.js +262 -0
- package/dist/cli-jobs.js.map +1 -0
- package/dist/cli-patterns.d.ts +26 -0
- package/dist/cli-patterns.d.ts.map +1 -0
- package/dist/cli-patterns.js +49 -0
- package/dist/cli-patterns.js.map +1 -0
- package/dist/cli-reports.d.ts +12 -0
- package/dist/cli-reports.d.ts.map +1 -0
- package/dist/cli-reports.js +97 -0
- package/dist/cli-reports.js.map +1 -0
- package/dist/cli-ui.d.ts.map +1 -1
- package/dist/cli-ui.js +5 -1
- package/dist/cli-ui.js.map +1 -1
- package/dist/cli.js +52 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/design/audit/attribution/aggregate.d.ts +16 -0
- package/dist/design/audit/attribution/aggregate.d.ts.map +1 -0
- package/dist/design/audit/attribution/aggregate.js +81 -0
- package/dist/design/audit/attribution/aggregate.js.map +1 -0
- package/dist/design/audit/attribution/store.d.ts +36 -0
- package/dist/design/audit/attribution/store.d.ts.map +1 -0
- package/dist/design/audit/attribution/store.js +108 -0
- package/dist/design/audit/attribution/store.js.map +1 -0
- package/dist/design/audit/attribution/types.d.ts +13 -0
- package/dist/design/audit/attribution/types.d.ts.map +1 -0
- package/dist/design/audit/attribution/types.js +10 -0
- package/dist/design/audit/attribution/types.js.map +1 -0
- package/dist/design/audit/classify-ensemble.d.ts +46 -0
- package/dist/design/audit/classify-ensemble.d.ts.map +1 -0
- package/dist/design/audit/classify-ensemble.js +207 -0
- package/dist/design/audit/classify-ensemble.js.map +1 -0
- package/dist/design/audit/ethics/check.d.ts +59 -0
- package/dist/design/audit/ethics/check.d.ts.map +1 -0
- package/dist/design/audit/ethics/check.js +137 -0
- package/dist/design/audit/ethics/check.js.map +1 -0
- package/dist/design/audit/ethics/loader.d.ts +21 -0
- package/dist/design/audit/ethics/loader.d.ts.map +1 -0
- package/dist/design/audit/ethics/loader.js +207 -0
- package/dist/design/audit/ethics/loader.js.map +1 -0
- package/dist/design/audit/ethics/rules/finance.yaml +37 -0
- package/dist/design/audit/ethics/rules/kids.yaml +37 -0
- package/dist/design/audit/ethics/rules/legal.yaml +35 -0
- package/dist/design/audit/ethics/rules/medical.yaml +36 -0
- package/dist/design/audit/evaluate.d.ts +69 -0
- package/dist/design/audit/evaluate.d.ts.map +1 -1
- package/dist/design/audit/evaluate.js +417 -55
- package/dist/design/audit/evaluate.js.map +1 -1
- package/dist/design/audit/first-principles-mode.d.ts +42 -0
- package/dist/design/audit/first-principles-mode.d.ts.map +1 -0
- package/dist/design/audit/first-principles-mode.js +77 -0
- package/dist/design/audit/first-principles-mode.js.map +1 -0
- package/dist/design/audit/modality/android.d.ts +14 -0
- package/dist/design/audit/modality/android.d.ts.map +1 -0
- package/dist/design/audit/modality/android.js +18 -0
- package/dist/design/audit/modality/android.js.map +1 -0
- package/dist/design/audit/modality/html.d.ts +22 -0
- package/dist/design/audit/modality/html.d.ts.map +1 -0
- package/dist/design/audit/modality/html.js +51 -0
- package/dist/design/audit/modality/html.js.map +1 -0
- package/dist/design/audit/modality/index.d.ts +8 -0
- package/dist/design/audit/modality/index.d.ts.map +1 -0
- package/dist/design/audit/modality/index.js +15 -0
- package/dist/design/audit/modality/index.js.map +1 -0
- package/dist/design/audit/modality/ios.d.ts +16 -0
- package/dist/design/audit/modality/ios.d.ts.map +1 -0
- package/dist/design/audit/modality/ios.js +19 -0
- package/dist/design/audit/modality/ios.js.map +1 -0
- package/dist/design/audit/modality/types.d.ts +9 -0
- package/dist/design/audit/modality/types.d.ts.map +1 -0
- package/dist/design/audit/modality/types.js +9 -0
- package/dist/design/audit/modality/types.js.map +1 -0
- package/dist/design/audit/patches/index.d.ts +8 -0
- package/dist/design/audit/patches/index.d.ts.map +1 -0
- package/dist/design/audit/patches/index.js +5 -0
- package/dist/design/audit/patches/index.js.map +1 -0
- package/dist/design/audit/patches/parse.d.ts +29 -0
- package/dist/design/audit/patches/parse.d.ts.map +1 -0
- package/dist/design/audit/patches/parse.js +153 -0
- package/dist/design/audit/patches/parse.js.map +1 -0
- package/dist/design/audit/patches/render.d.ts +20 -0
- package/dist/design/audit/patches/render.d.ts.map +1 -0
- package/dist/design/audit/patches/render.js +55 -0
- package/dist/design/audit/patches/render.js.map +1 -0
- package/dist/design/audit/patches/severity-enforcement.d.ts +23 -0
- package/dist/design/audit/patches/severity-enforcement.d.ts.map +1 -0
- package/dist/design/audit/patches/severity-enforcement.js +42 -0
- package/dist/design/audit/patches/severity-enforcement.js.map +1 -0
- package/dist/design/audit/patches/validate.d.ts +34 -0
- package/dist/design/audit/patches/validate.d.ts.map +1 -0
- package/dist/design/audit/patches/validate.js +53 -0
- package/dist/design/audit/patches/validate.js.map +1 -0
- package/dist/design/audit/patterns/match.d.ts +24 -0
- package/dist/design/audit/patterns/match.d.ts.map +1 -0
- package/dist/design/audit/patterns/match.js +48 -0
- package/dist/design/audit/patterns/match.js.map +1 -0
- package/dist/design/audit/patterns/mine.d.ts +31 -0
- package/dist/design/audit/patterns/mine.d.ts.map +1 -0
- package/dist/design/audit/patterns/mine.js +35 -0
- package/dist/design/audit/patterns/mine.js.map +1 -0
- package/dist/design/audit/patterns/store.d.ts +14 -0
- package/dist/design/audit/patterns/store.d.ts.map +1 -0
- package/dist/design/audit/patterns/store.js +53 -0
- package/dist/design/audit/patterns/store.js.map +1 -0
- package/dist/design/audit/patterns/types.d.ts +53 -0
- package/dist/design/audit/patterns/types.d.ts.map +1 -0
- package/dist/design/audit/patterns/types.js +13 -0
- package/dist/design/audit/patterns/types.js.map +1 -0
- package/dist/design/audit/pipeline.d.ts +26 -0
- package/dist/design/audit/pipeline.d.ts.map +1 -1
- package/dist/design/audit/pipeline.js +131 -4
- package/dist/design/audit/pipeline.js.map +1 -1
- package/dist/design/audit/rubric/anchor-loader.d.ts +44 -0
- package/dist/design/audit/rubric/anchor-loader.d.ts.map +1 -0
- package/dist/design/audit/rubric/anchor-loader.js +210 -0
- package/dist/design/audit/rubric/anchor-loader.js.map +1 -0
- package/dist/design/audit/rubric/anchors/blog.yaml +33 -0
- package/dist/design/audit/rubric/anchors/dashboard.yaml +35 -0
- package/dist/design/audit/rubric/anchors/docs.yaml +35 -0
- package/dist/design/audit/rubric/anchors/ecommerce.yaml +33 -0
- package/dist/design/audit/rubric/anchors/marketing.yaml +34 -0
- package/dist/design/audit/rubric/anchors/saas-app.yaml +38 -0
- package/dist/design/audit/rubric/anchors/social.yaml +33 -0
- package/dist/design/audit/rubric/anchors/tool.yaml +33 -0
- package/dist/design/audit/rubric/anchors/utility.yaml +33 -0
- package/dist/design/audit/rubric/fragments/audience-clinician.md +42 -0
- package/dist/design/audit/rubric/fragments/audience-developer.md +40 -0
- package/dist/design/audit/rubric/fragments/audience-kids.md +35 -0
- package/dist/design/audit/rubric/fragments/audience-vulnerability-minor-facing.md +37 -0
- package/dist/design/audit/rubric/fragments/first-principles.md +65 -0
- package/dist/design/audit/rubric/fragments/modality-mobile.md +39 -0
- package/dist/design/audit/rubric/fragments/modality-tablet.md +35 -0
- package/dist/design/audit/rubric/fragments/regulatory-coppa.md +32 -0
- package/dist/design/audit/rubric/fragments/regulatory-gdpr.md +33 -0
- package/dist/design/audit/rubric/fragments/regulatory-hipaa.md +36 -0
- package/dist/design/audit/rubric/fragments/universal-product-intent.md +48 -0
- package/dist/design/audit/rubric/loader.d.ts +26 -6
- package/dist/design/audit/rubric/loader.d.ts.map +1 -1
- package/dist/design/audit/rubric/loader.js +77 -27
- package/dist/design/audit/rubric/loader.js.map +1 -1
- package/dist/design/audit/rubric/rollup-weights.d.ts +25 -0
- package/dist/design/audit/rubric/rollup-weights.d.ts.map +1 -0
- package/dist/design/audit/rubric/rollup-weights.js +51 -0
- package/dist/design/audit/rubric/rollup-weights.js.map +1 -0
- package/dist/design/audit/types.d.ts +28 -0
- package/dist/design/audit/types.d.ts.map +1 -1
- package/dist/design/audit/v2/build-result.d.ts +47 -0
- package/dist/design/audit/v2/build-result.d.ts.map +1 -0
- package/dist/design/audit/v2/build-result.js +163 -0
- package/dist/design/audit/v2/build-result.js.map +1 -0
- package/dist/design/audit/v2/score.d.ts +49 -0
- package/dist/design/audit/v2/score.d.ts.map +1 -0
- package/dist/design/audit/v2/score.js +211 -0
- package/dist/design/audit/v2/score.js.map +1 -0
- package/dist/design/audit/v2/types.d.ts +431 -0
- package/dist/design/audit/v2/types.d.ts.map +1 -0
- package/dist/design/audit/v2/types.js +26 -0
- package/dist/design/audit/v2/types.js.map +1 -0
- package/dist/discover/index.d.ts +16 -0
- package/dist/discover/index.d.ts.map +1 -0
- package/dist/discover/index.js +25 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/discover/wayback.d.ts +49 -0
- package/dist/discover/wayback.d.ts.map +1 -0
- package/dist/discover/wayback.js +123 -0
- package/dist/discover/wayback.js.map +1 -0
- package/dist/jobs/anti-bot.d.ts +19 -0
- package/dist/jobs/anti-bot.d.ts.map +1 -0
- package/dist/jobs/anti-bot.js +64 -0
- package/dist/jobs/anti-bot.js.map +1 -0
- package/dist/jobs/cost-estimate.d.ts +12 -0
- package/dist/jobs/cost-estimate.d.ts.map +1 -0
- package/dist/jobs/cost-estimate.js +21 -0
- package/dist/jobs/cost-estimate.js.map +1 -0
- package/dist/jobs/cost-history.d.ts +19 -0
- package/dist/jobs/cost-history.d.ts.map +1 -0
- package/dist/jobs/cost-history.js +42 -0
- package/dist/jobs/cost-history.js.map +1 -0
- package/dist/jobs/index.d.ts +31 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +37 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/orchestrator.d.ts +42 -0
- package/dist/jobs/orchestrator.d.ts.map +1 -0
- package/dist/jobs/orchestrator.js +282 -0
- package/dist/jobs/orchestrator.js.map +1 -0
- package/dist/jobs/queue.d.ts +45 -0
- package/dist/jobs/queue.d.ts.map +1 -0
- package/dist/jobs/queue.js +114 -0
- package/dist/jobs/queue.js.map +1 -0
- package/dist/jobs/retry.d.ts +36 -0
- package/dist/jobs/retry.d.ts.map +1 -0
- package/dist/jobs/retry.js +77 -0
- package/dist/jobs/retry.js.map +1 -0
- package/dist/jobs/store.d.ts +31 -0
- package/dist/jobs/store.d.ts.map +1 -0
- package/dist/jobs/store.js +92 -0
- package/dist/jobs/store.js.map +1 -0
- package/dist/jobs/types.d.ts +106 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +13 -0
- package/dist/jobs/types.js.map +1 -0
- package/dist/provider-defaults.d.ts +1 -1
- package/dist/provider-defaults.d.ts.map +1 -1
- package/dist/provider-defaults.js +8 -0
- package/dist/provider-defaults.js.map +1 -1
- package/dist/reports/aggregate.d.ts +38 -0
- package/dist/reports/aggregate.d.ts.map +1 -0
- package/dist/reports/aggregate.js +145 -0
- package/dist/reports/aggregate.js.map +1 -0
- package/dist/reports/index.d.ts +21 -0
- package/dist/reports/index.d.ts.map +1 -0
- package/dist/reports/index.js +15 -0
- package/dist/reports/index.js.map +1 -0
- package/dist/reports/narrate.d.ts +19 -0
- package/dist/reports/narrate.d.ts.map +1 -0
- package/dist/reports/narrate.js +40 -0
- package/dist/reports/narrate.js.map +1 -0
- package/dist/reports/templates.d.ts +43 -0
- package/dist/reports/templates.d.ts.map +1 -0
- package/dist/reports/templates.js +200 -0
- package/dist/reports/templates.js.map +1 -0
- package/dist/reports/tokens.d.ts +77 -0
- package/dist/reports/tokens.d.ts.map +1 -0
- package/dist/reports/tokens.js +88 -0
- package/dist/reports/tokens.js.map +1 -0
- package/dist/reports/tools.d.ts +76 -0
- package/dist/reports/tools.d.ts.map +1 -0
- package/dist/reports/tools.js +205 -0
- package/dist/reports/tools.js.map +1 -0
- package/dist/reports/types.d.ts +51 -0
- package/dist/reports/types.d.ts.map +1 -0
- package/dist/reports/types.js +9 -0
- package/dist/reports/types.js.map +1 -0
- package/dist/supervisor/critic.d.ts +1 -1
- package/dist/supervisor/critic.d.ts.map +1 -1
- package/dist/supervisor/critic.js +50 -5
- package/dist/supervisor/critic.js.map +1 -1
- package/dist/telemetry/client.d.ts +42 -0
- package/dist/telemetry/client.d.ts.map +1 -0
- package/dist/telemetry/client.js +203 -0
- package/dist/telemetry/client.js.map +1 -0
- package/dist/telemetry/hash.d.ts +4 -0
- package/dist/telemetry/hash.d.ts.map +1 -0
- package/dist/telemetry/hash.js +7 -0
- package/dist/telemetry/hash.js.map +1 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +5 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/schema.d.ts +85 -0
- package/dist/telemetry/schema.d.ts.map +1 -0
- package/dist/telemetry/schema.js +13 -0
- package/dist/telemetry/schema.js.map +1 -0
- package/dist/telemetry/sink.d.ts +46 -0
- package/dist/telemetry/sink.d.ts.map +1 -0
- package/dist/telemetry/sink.js +97 -0
- package/dist/telemetry/sink.js.map +1 -0
- package/dist/types.d.ts +5 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 4 — Append-only JSONL store for PatchApplication records.
|
|
3
|
+
*
|
|
4
|
+
* Layout: `<dir>/applications/<YYYY-MM-DD>.jsonl`
|
|
5
|
+
* Each line is a standalone JSON object — `patchHash` is always set so cross-
|
|
6
|
+
* tenant aggregation can group by patch signature, not per-tenant path.
|
|
7
|
+
*
|
|
8
|
+
* Append-only invariant: never mutate existing lines. Outcome updates are
|
|
9
|
+
* recorded as NEW lines so the JSONL is an event stream, not a state snapshot.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as fsp from 'node:fs/promises';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import * as os from 'node:os';
|
|
15
|
+
import * as crypto from 'node:crypto';
|
|
16
|
+
const DEFAULT_DIR = path.join(os.homedir(), '.bad', 'attribution');
|
|
17
|
+
function applicationsDir(dir) {
|
|
18
|
+
return path.join(dir, 'applications');
|
|
19
|
+
}
|
|
20
|
+
function todayPath(dir) {
|
|
21
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
22
|
+
return path.join(applicationsDir(dir), `${date}.jsonl`);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Stable hash for a patch diff + scope. Same patch content across tenants →
|
|
26
|
+
* same hash, enabling cross-tenant reliability aggregation.
|
|
27
|
+
*/
|
|
28
|
+
export function patchHash(diff, scope) {
|
|
29
|
+
return crypto
|
|
30
|
+
.createHash('sha256')
|
|
31
|
+
.update(`${diff.before}\n---\n${diff.after}\n---\n${scope}`)
|
|
32
|
+
.digest('hex')
|
|
33
|
+
.slice(0, 16);
|
|
34
|
+
}
|
|
35
|
+
/** Append a new PatchApplication record. */
|
|
36
|
+
export async function appendPatchApplication(app, dir = DEFAULT_DIR) {
|
|
37
|
+
await fsp.mkdir(applicationsDir(dir), { recursive: true });
|
|
38
|
+
await fsp.appendFile(todayPath(dir), JSON.stringify(app) + '\n', 'utf-8');
|
|
39
|
+
}
|
|
40
|
+
/** Sync variant for non-async call sites. */
|
|
41
|
+
export function appendPatchApplicationSync(app, dir = DEFAULT_DIR) {
|
|
42
|
+
fs.mkdirSync(applicationsDir(dir), { recursive: true });
|
|
43
|
+
fs.appendFileSync(todayPath(dir), JSON.stringify(app) + '\n', 'utf-8');
|
|
44
|
+
}
|
|
45
|
+
/** Read all PatchApplication records from the last `days` days. */
|
|
46
|
+
export async function readRecentApplications(days = 7, dir = DEFAULT_DIR) {
|
|
47
|
+
const appsDir = applicationsDir(dir);
|
|
48
|
+
if (!fs.existsSync(appsDir))
|
|
49
|
+
return [];
|
|
50
|
+
const results = [];
|
|
51
|
+
for (let d = 0; d < days; d++) {
|
|
52
|
+
const date = new Date(Date.now() - d * 86_400_000).toISOString().slice(0, 10);
|
|
53
|
+
const filePath = path.join(appsDir, `${date}.jsonl`);
|
|
54
|
+
if (!fs.existsSync(filePath))
|
|
55
|
+
continue;
|
|
56
|
+
const lines = fs.readFileSync(filePath, 'utf-8').split('\n').filter(Boolean);
|
|
57
|
+
for (const line of lines) {
|
|
58
|
+
try {
|
|
59
|
+
results.push(JSON.parse(line));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// corrupt line — skip
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Find the most recent pending application for a patchId — one that has no
|
|
70
|
+
* `postAuditRunId` yet. Used when a re-audit lands to attach the outcome.
|
|
71
|
+
*/
|
|
72
|
+
export async function findPendingApplication(patchId, dir = DEFAULT_DIR) {
|
|
73
|
+
const apps = await readRecentApplications(7, dir);
|
|
74
|
+
// Most recent first; pick the newest pending one.
|
|
75
|
+
const pending = apps
|
|
76
|
+
.filter(a => a.patchId === patchId && !a.postAuditRunId)
|
|
77
|
+
.sort((a, b) => b.appliedAt.localeCompare(a.appliedAt));
|
|
78
|
+
return pending[0] ?? null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Append an outcome event for an existing application. Does NOT mutate the
|
|
82
|
+
* original line — appends a new event so the JSONL remains an event stream.
|
|
83
|
+
*/
|
|
84
|
+
export async function updateApplicationOutcome(applicationId, postAuditRunId, observed, dir = DEFAULT_DIR) {
|
|
85
|
+
const apps = await readRecentApplications(7, dir);
|
|
86
|
+
const original = apps.find(a => a.applicationId === applicationId);
|
|
87
|
+
if (!original) {
|
|
88
|
+
throw new Error(`PatchApplication ${applicationId} not found in the last 7 days`);
|
|
89
|
+
}
|
|
90
|
+
const agreementScore = computeAgreementScore(original.predicted, observed);
|
|
91
|
+
const outcome = {
|
|
92
|
+
...original,
|
|
93
|
+
postAuditRunId,
|
|
94
|
+
observed,
|
|
95
|
+
agreementScore,
|
|
96
|
+
};
|
|
97
|
+
await fsp.mkdir(applicationsDir(dir), { recursive: true });
|
|
98
|
+
await fsp.appendFile(todayPath(dir), JSON.stringify(outcome) + '\n', 'utf-8');
|
|
99
|
+
}
|
|
100
|
+
function computeAgreementScore(predicted, observed) {
|
|
101
|
+
if (!predicted || !observed)
|
|
102
|
+
return 0;
|
|
103
|
+
const p = predicted.delta;
|
|
104
|
+
const o = observed.delta;
|
|
105
|
+
const denom = Math.max(Math.abs(p), Math.abs(o), 1);
|
|
106
|
+
return 1 - Math.abs(p - o) / denom;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/design/audit/attribution/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 4 — Outcome attribution type contract.
|
|
3
|
+
*
|
|
4
|
+
* These types are already defined in src/design/audit/v2/types.ts as part of
|
|
5
|
+
* the Phase 0 contract. This module re-exports them so attribution code can
|
|
6
|
+
* import from a single, predictable path. When v2/types.ts is the sole
|
|
7
|
+
* canonical source, update these re-exports accordingly.
|
|
8
|
+
*/
|
|
9
|
+
export type { PatchApplication, PatchReliability, } from '../v2/types.js';
|
|
10
|
+
/** sha256(diff.before + '\n---\n' + diff.after + '\n---\n' + scope).slice(0,16) */
|
|
11
|
+
export type PatchHash = string;
|
|
12
|
+
export type PatchRecommendation = 'recommended' | 'neutral' | 'antipattern';
|
|
13
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/design/audit/attribution/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACV,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AAEvB,mFAAmF;AACnF,MAAM,MAAM,SAAS,GAAG,MAAM,CAAA;AAE9B,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG,SAAS,GAAG,aAAa,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer 4 — Outcome attribution type contract.
|
|
3
|
+
*
|
|
4
|
+
* These types are already defined in src/design/audit/v2/types.ts as part of
|
|
5
|
+
* the Phase 0 contract. This module re-exports them so attribution code can
|
|
6
|
+
* import from a single, predictable path. When v2/types.ts is the sole
|
|
7
|
+
* canonical source, update these re-exports accordingly.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/design/audit/attribution/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensemble classifier — Layer 1 of the world-class design-audit architecture.
|
|
3
|
+
*
|
|
4
|
+
* Three-signal vote (URL pattern + DOM heuristic + LLM) decides the page type
|
|
5
|
+
* and reports an ensemble confidence so downstream layers (first-principles
|
|
6
|
+
* fallback, rubric loader, telemetry) can act on uncertainty honestly.
|
|
7
|
+
*
|
|
8
|
+
* Vote logic:
|
|
9
|
+
* - URL + DOM agree on a type AND combined confidence > 0.7 → accept (skip LLM)
|
|
10
|
+
* - else → run LLM, take majority
|
|
11
|
+
* - if LLM confidence < 0.5 AND signals disagree → return 'unknown' with dissent
|
|
12
|
+
*/
|
|
13
|
+
import type { Brain } from '../../brain/index.js';
|
|
14
|
+
import type { PageState } from '../../types.js';
|
|
15
|
+
import type { PageType } from './types.js';
|
|
16
|
+
import type { ClassifierSignal, DomHeuristics, EnsembleClassification } from './v2/types.js';
|
|
17
|
+
interface UrlPatternRule {
|
|
18
|
+
pattern: RegExp;
|
|
19
|
+
type: PageType;
|
|
20
|
+
confidence: number;
|
|
21
|
+
rationale: string;
|
|
22
|
+
}
|
|
23
|
+
export interface EnsembleClassifyInput {
|
|
24
|
+
brain: Brain;
|
|
25
|
+
state: PageState;
|
|
26
|
+
url: string;
|
|
27
|
+
/** Optional pre-captured DOM heuristics. If absent, we attempt to derive them from the snapshot. */
|
|
28
|
+
domHeuristics?: DomHeuristics;
|
|
29
|
+
}
|
|
30
|
+
/** Public entry point. */
|
|
31
|
+
export declare function classifyEnsemble(input: EnsembleClassifyInput): Promise<EnsembleClassification>;
|
|
32
|
+
export declare function classifyByUrl(url: string): ClassifierSignal | null;
|
|
33
|
+
export declare function classifyByDom(dom: DomHeuristics): ClassifierSignal | null;
|
|
34
|
+
/**
|
|
35
|
+
* Best-effort DOM heuristic derivation from the accessibility-tree snapshot.
|
|
36
|
+
* Pipelines that capture true DOM heuristics via Playwright should pass them
|
|
37
|
+
* in directly; this fallback works against the @ref-snapshot text.
|
|
38
|
+
*/
|
|
39
|
+
export declare function deriveHeuristics(state: PageState): DomHeuristics;
|
|
40
|
+
export declare const ENSEMBLE_INTERNALS: {
|
|
41
|
+
URL_PATTERN_RULES: UrlPatternRule[];
|
|
42
|
+
ENSEMBLE_AGREEMENT_THRESHOLD: number;
|
|
43
|
+
LLM_FALLBACK_CONFIDENCE: number;
|
|
44
|
+
};
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=classify-ensemble.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-ensemble.d.ts","sourceRoot":"","sources":["../../../src/design/audit/classify-ensemble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE/C,OAAO,KAAK,EAAsB,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EACV,gBAAgB,EAEhB,aAAa,EACb,sBAAsB,EACvB,MAAM,eAAe,CAAA;AAEtB,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,QAAQ,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAoBD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,SAAS,CAAA;IAChB,GAAG,EAAE,MAAM,CAAA;IACX,oGAAoG;IACpG,aAAa,CAAC,EAAE,aAAa,CAAA;CAC9B;AAED,0BAA0B;AAC1B,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAgFpG;AA8BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAkBlE;AAID,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,gBAAgB,GAAG,IAAI,CA8BzE;AAQD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,GAAG,aAAa,CAchE;AAYD,eAAO,MAAM,kBAAkB;;;;CAI9B,CAAA"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensemble classifier — Layer 1 of the world-class design-audit architecture.
|
|
3
|
+
*
|
|
4
|
+
* Three-signal vote (URL pattern + DOM heuristic + LLM) decides the page type
|
|
5
|
+
* and reports an ensemble confidence so downstream layers (first-principles
|
|
6
|
+
* fallback, rubric loader, telemetry) can act on uncertainty honestly.
|
|
7
|
+
*
|
|
8
|
+
* Vote logic:
|
|
9
|
+
* - URL + DOM agree on a type AND combined confidence > 0.7 → accept (skip LLM)
|
|
10
|
+
* - else → run LLM, take majority
|
|
11
|
+
* - if LLM confidence < 0.5 AND signals disagree → return 'unknown' with dissent
|
|
12
|
+
*/
|
|
13
|
+
import { classifyPage, defaultClassification } from './classify.js';
|
|
14
|
+
/**
|
|
15
|
+
* URL pattern rules — straight from the RFC. Order matters: more specific
|
|
16
|
+
* patterns first. Each rule's confidence is the URL signal's contribution to
|
|
17
|
+
* the ensemble vote.
|
|
18
|
+
*/
|
|
19
|
+
const URL_PATTERN_RULES = [
|
|
20
|
+
{ pattern: /\/(docs|reference|api|guide|help|faq)(\/|$)/, type: 'docs', confidence: 0.85, rationale: 'URL contains a docs path segment' },
|
|
21
|
+
{ pattern: /\/(checkout|cart|pay|order|billing)(\/|$)/, type: 'ecommerce', confidence: 0.85, rationale: 'URL contains a commerce path segment' },
|
|
22
|
+
{ pattern: /\/(app|dashboard|workspace|admin)(\/|$)/, type: 'saas-app', confidence: 0.75, rationale: 'URL contains an app/dashboard path segment' },
|
|
23
|
+
{ pattern: /\/(login|signup|auth|sign-in)(\/|$)/, type: 'utility', confidence: 0.85, rationale: 'URL contains an auth path segment' },
|
|
24
|
+
{ pattern: /\/(pricing|plans|features|product)(\/|$)/, type: 'marketing', confidence: 0.7, rationale: 'URL contains a marketing path segment' },
|
|
25
|
+
{ pattern: /\/(blog|articles|news|stories)(\/|$)/, type: 'blog', confidence: 0.8, rationale: 'URL contains a blog path segment' },
|
|
26
|
+
{ pattern: /\/$/, type: 'marketing', confidence: 0.4, rationale: 'URL is a root path — weak marketing default' },
|
|
27
|
+
];
|
|
28
|
+
const ENSEMBLE_AGREEMENT_THRESHOLD = 0.7;
|
|
29
|
+
const LLM_FALLBACK_CONFIDENCE = 0.5;
|
|
30
|
+
/** Public entry point. */
|
|
31
|
+
export async function classifyEnsemble(input) {
|
|
32
|
+
const signals = [];
|
|
33
|
+
// ── 1. URL pattern signal ──
|
|
34
|
+
const urlSignal = classifyByUrl(input.url);
|
|
35
|
+
if (urlSignal)
|
|
36
|
+
signals.push(urlSignal);
|
|
37
|
+
// ── 2. DOM heuristic signal ──
|
|
38
|
+
const dom = input.domHeuristics ?? deriveHeuristics(input.state);
|
|
39
|
+
const domSignal = classifyByDom(dom);
|
|
40
|
+
if (domSignal)
|
|
41
|
+
signals.push(domSignal);
|
|
42
|
+
// ── Quick path: URL + DOM agree with combined confidence > threshold ──
|
|
43
|
+
if (urlSignal &&
|
|
44
|
+
domSignal &&
|
|
45
|
+
urlSignal.type === domSignal.type &&
|
|
46
|
+
urlSignal.confidence + domSignal.confidence > ENSEMBLE_AGREEMENT_THRESHOLD) {
|
|
47
|
+
const ensembleConfidence = clamp01(Math.min(1, (urlSignal.confidence + domSignal.confidence) / 1.6));
|
|
48
|
+
return finalize({
|
|
49
|
+
type: urlSignal.type,
|
|
50
|
+
base: defaultClassification(),
|
|
51
|
+
signals,
|
|
52
|
+
ensembleConfidence,
|
|
53
|
+
signalsAgreed: true,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// ── 3. LLM tiebreaker ──
|
|
57
|
+
const llmClass = await classifyPage(input.brain, input.state).catch(() => defaultClassification());
|
|
58
|
+
signals.push({
|
|
59
|
+
source: 'llm',
|
|
60
|
+
type: llmClass.type,
|
|
61
|
+
confidence: llmClass.confidence,
|
|
62
|
+
rationale: llmClass.intent || 'LLM page classification',
|
|
63
|
+
});
|
|
64
|
+
// ── Vote ──
|
|
65
|
+
const tally = new Map();
|
|
66
|
+
for (const sig of signals) {
|
|
67
|
+
tally.set(sig.type, (tally.get(sig.type) ?? 0) + sig.confidence);
|
|
68
|
+
}
|
|
69
|
+
const sortedVotes = [...tally.entries()].sort((a, b) => b[1] - a[1]);
|
|
70
|
+
const winner = sortedVotes[0];
|
|
71
|
+
const winningType = winner ? winner[0] : 'unknown';
|
|
72
|
+
const winningTotal = winner ? winner[1] : 0;
|
|
73
|
+
// Compute aggregate confidence: average over participating signals, weighted by agreement.
|
|
74
|
+
const winningSignals = signals.filter((s) => s.type === winningType);
|
|
75
|
+
const agreementShare = winningSignals.length / signals.length;
|
|
76
|
+
const meanConfidence = winningSignals.reduce((acc, s) => acc + s.confidence, 0) / Math.max(winningSignals.length, 1);
|
|
77
|
+
const ensembleConfidence = clamp01(meanConfidence * agreementShare + 0.05 * (winningTotal - meanConfidence));
|
|
78
|
+
const signalsAgreed = signals.every((s) => s.type === winningType);
|
|
79
|
+
const dissent = signals.filter((s) => s.type !== winningType).map((s) => ({ source: s.source, type: s.type }));
|
|
80
|
+
// ── Low-confidence + disagreement → 'unknown' with dissent ──
|
|
81
|
+
if (!signalsAgreed && llmClass.confidence < LLM_FALLBACK_CONFIDENCE) {
|
|
82
|
+
return finalize({
|
|
83
|
+
type: 'unknown',
|
|
84
|
+
base: llmClass,
|
|
85
|
+
signals,
|
|
86
|
+
ensembleConfidence: Math.min(ensembleConfidence, 0.5),
|
|
87
|
+
signalsAgreed: false,
|
|
88
|
+
dissent,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return finalize({
|
|
92
|
+
type: winningType,
|
|
93
|
+
base: llmClass,
|
|
94
|
+
signals,
|
|
95
|
+
ensembleConfidence,
|
|
96
|
+
signalsAgreed,
|
|
97
|
+
dissent: signalsAgreed ? undefined : dissent,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function finalize(args) {
|
|
101
|
+
const { type, base, signals, ensembleConfidence, signalsAgreed } = args;
|
|
102
|
+
const firstPrinciplesMode = !signalsAgreed || ensembleConfidence < 0.6;
|
|
103
|
+
const out = {
|
|
104
|
+
...base,
|
|
105
|
+
type,
|
|
106
|
+
confidence: ensembleConfidence,
|
|
107
|
+
signals,
|
|
108
|
+
signalsAgreed,
|
|
109
|
+
ensembleConfidence,
|
|
110
|
+
firstPrinciplesMode,
|
|
111
|
+
};
|
|
112
|
+
if (args.dissent && args.dissent.length > 0)
|
|
113
|
+
out.dissent = args.dissent;
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
// ── URL-pattern classifier ──────────────────────────────────────────────────
|
|
117
|
+
export function classifyByUrl(url) {
|
|
118
|
+
let pathname;
|
|
119
|
+
try {
|
|
120
|
+
pathname = new URL(url).pathname || '/';
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
for (const rule of URL_PATTERN_RULES) {
|
|
126
|
+
if (rule.pattern.test(pathname)) {
|
|
127
|
+
return {
|
|
128
|
+
source: 'url-pattern',
|
|
129
|
+
type: rule.type,
|
|
130
|
+
confidence: rule.confidence,
|
|
131
|
+
rationale: `${rule.rationale} (${pathname})`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
// ── DOM-heuristic classifier ────────────────────────────────────────────────
|
|
138
|
+
export function classifyByDom(dom) {
|
|
139
|
+
// docs: lots of paragraphs + code blocks, modest nav
|
|
140
|
+
if (dom.codeBlockCount >= 3 && dom.paragraphCount >= 6) {
|
|
141
|
+
return signal('dom-heuristic', 'docs', 0.7, `code blocks=${dom.codeBlockCount}, paragraphs=${dom.paragraphCount}`);
|
|
142
|
+
}
|
|
143
|
+
// dashboard: many table rows or charts + sidebar
|
|
144
|
+
if ((dom.tableRowCount >= 8 || dom.chartCount >= 2) && dom.hasSidebar) {
|
|
145
|
+
return signal('dom-heuristic', 'dashboard', 0.7, `rows=${dom.tableRowCount}, charts=${dom.chartCount}, sidebar=true`);
|
|
146
|
+
}
|
|
147
|
+
// saas-app: sidebar + multiple forms or many inputs
|
|
148
|
+
if (dom.hasSidebar && (dom.formCount >= 1 || dom.inputCount >= 4)) {
|
|
149
|
+
return signal('dom-heuristic', 'saas-app', 0.65, `sidebar=true, forms=${dom.formCount}, inputs=${dom.inputCount}`);
|
|
150
|
+
}
|
|
151
|
+
// utility: single dominant form, no hero, no sidebar
|
|
152
|
+
if (dom.formCount >= 1 && dom.inputCount >= 2 && !dom.hasHeroSection && !dom.hasSidebar) {
|
|
153
|
+
return signal('dom-heuristic', 'utility', 0.7, `single form, no hero, no sidebar`);
|
|
154
|
+
}
|
|
155
|
+
// ecommerce: forms + many nav items + footer links (storefront chrome)
|
|
156
|
+
if (dom.formCount >= 1 && dom.navItems >= 6 && dom.hasFooterLinks) {
|
|
157
|
+
return signal('dom-heuristic', 'ecommerce', 0.6, `nav=${dom.navItems}, footer-links, form present`);
|
|
158
|
+
}
|
|
159
|
+
// blog: long body of paragraphs without forms or tables
|
|
160
|
+
if (dom.paragraphCount >= 8 && dom.formCount === 0 && dom.tableRowCount === 0) {
|
|
161
|
+
return signal('dom-heuristic', 'blog', 0.65, `paragraphs=${dom.paragraphCount}, no forms or tables`);
|
|
162
|
+
}
|
|
163
|
+
// marketing: hero + footer-link cloud + few paragraphs
|
|
164
|
+
if (dom.hasHeroSection && dom.hasFooterLinks && dom.paragraphCount < 8) {
|
|
165
|
+
return signal('dom-heuristic', 'marketing', 0.6, `hero present, footer-links, paragraphs=${dom.paragraphCount}`);
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
function signal(source, type, confidence, rationale) {
|
|
170
|
+
return { source, type, confidence, rationale };
|
|
171
|
+
}
|
|
172
|
+
// ── DOM heuristic derivation from snapshot ──────────────────────────────────
|
|
173
|
+
/**
|
|
174
|
+
* Best-effort DOM heuristic derivation from the accessibility-tree snapshot.
|
|
175
|
+
* Pipelines that capture true DOM heuristics via Playwright should pass them
|
|
176
|
+
* in directly; this fallback works against the @ref-snapshot text.
|
|
177
|
+
*/
|
|
178
|
+
export function deriveHeuristics(state) {
|
|
179
|
+
const snapshot = state.snapshot ?? '';
|
|
180
|
+
return {
|
|
181
|
+
formCount: countMatches(snapshot, /\bform\b/gi),
|
|
182
|
+
inputCount: countMatches(snapshot, /\b(textbox|searchbox|combobox|spinbutton|input)\b/gi),
|
|
183
|
+
tableRowCount: countMatches(snapshot, /\brow\b/gi),
|
|
184
|
+
chartCount: countMatches(snapshot, /\b(graphics-document|graphics-symbol|figure)\b/gi),
|
|
185
|
+
navItems: countMatches(snapshot, /\bnavigation\b/gi),
|
|
186
|
+
hasFooterLinks: /\bcontentinfo\b/i.test(snapshot),
|
|
187
|
+
hasHeroSection: /\bhero\b/i.test(snapshot) || /\bbanner\b/i.test(snapshot),
|
|
188
|
+
hasSidebar: /\bcomplementary\b/i.test(snapshot) || /\bsidebar\b/i.test(snapshot),
|
|
189
|
+
paragraphCount: countMatches(snapshot, /\bparagraph\b/gi),
|
|
190
|
+
codeBlockCount: countMatches(snapshot, /\bcode\b/gi),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function countMatches(haystack, pattern) {
|
|
194
|
+
const m = haystack.match(pattern);
|
|
195
|
+
return m ? m.length : 0;
|
|
196
|
+
}
|
|
197
|
+
function clamp01(n) {
|
|
198
|
+
if (Number.isNaN(n))
|
|
199
|
+
return 0;
|
|
200
|
+
return Math.max(0, Math.min(1, n));
|
|
201
|
+
}
|
|
202
|
+
export const ENSEMBLE_INTERNALS = {
|
|
203
|
+
URL_PATTERN_RULES,
|
|
204
|
+
ENSEMBLE_AGREEMENT_THRESHOLD,
|
|
205
|
+
LLM_FALLBACK_CONFIDENCE,
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=classify-ensemble.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-ensemble.js","sourceRoot":"","sources":["../../../src/design/audit/classify-ensemble.ts"],"names":[],"mappings":"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"}
|
|
@@ -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 '../v2/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 v2 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,gBAAgB,CAAA;AAGvB,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 v2 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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"}
|