@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.
- package/dist/brain/index.d.ts +12 -0
- package/dist/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +36 -8
- 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 +12 -0
- package/dist/cli-design-audit.d.ts.map +1 -1
- package/dist/cli-design-audit.js +78 -0
- 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 +253 -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.js +29 -1
- package/dist/cli.js.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/build-result.d.ts +68 -0
- package/dist/design/audit/build-result.d.ts.map +1 -0
- package/dist/design/audit/build-result.js +243 -0
- package/dist/design/audit/build-result.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.map +1 -1
- package/dist/design/audit/evaluate.js +4 -1
- 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/generate.d.ts +45 -0
- package/dist/design/audit/patches/generate.d.ts.map +1 -0
- package/dist/design/audit/patches/generate.js +161 -0
- package/dist/design/audit/patches/generate.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 +40 -0
- package/dist/design/audit/patches/validate.d.ts.map +1 -0
- package/dist/design/audit/patches/validate.js +60 -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 +12 -0
- package/dist/design/audit/pipeline.d.ts.map +1 -1
- package/dist/design/audit/pipeline.js +81 -5
- 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/loader.d.ts +26 -6
- package/dist/design/audit/rubric/loader.d.ts.map +1 -1
- package/dist/design/audit/rubric/loader.js +45 -26
- 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/score-types.d.ts +431 -0
- package/dist/design/audit/score-types.d.ts.map +1 -0
- package/dist/design/audit/score-types.js +26 -0
- package/dist/design/audit/score-types.js.map +1 -0
- package/dist/design/audit/score.d.ts +49 -0
- package/dist/design/audit/score.d.ts.map +1 -0
- package/dist/design/audit/score.js +211 -0
- package/dist/design/audit/score.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/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/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 +69 -0
- package/dist/reports/tokens.d.ts.map +1 -0
- package/dist/reports/tokens.js +74 -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/run-state.d.ts +36 -1
- package/dist/run-state.d.ts.map +1 -1
- package/dist/run-state.js +36 -1
- package/dist/run-state.js.map +1 -1
- package/dist/runner/runner.d.ts.map +1 -1
- package/dist/runner/runner.js +73 -3
- package/dist/runner/runner.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anchor loader — Layer 1 of the world-class design-audit architecture.
|
|
3
|
+
*
|
|
4
|
+
* Loads per-page-type calibration anchors from `anchors/<type>.yaml`. Each
|
|
5
|
+
* anchor encodes score-band criteria + reference fixtures so the LLM scores
|
|
6
|
+
* an saas-app like Linear's app, not like Linear's marketing site.
|
|
7
|
+
*
|
|
8
|
+
* Schema:
|
|
9
|
+
* type: <PageType>
|
|
10
|
+
* score_9_10: { criteria: string[], fixtures: string[] }
|
|
11
|
+
* score_7_8: { criteria: string[], fixtures: string[] }
|
|
12
|
+
* score_5_6: { criteria: string[], fixtures: string[] }
|
|
13
|
+
* score_3_4: { criteria: string[], fixtures: string[] }
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const ANCHORS_DIR = path.join(__dirname, 'anchors');
|
|
20
|
+
const REQUIRED_BANDS = ['score_9_10', 'score_7_8', 'score_5_6', 'score_3_4'];
|
|
21
|
+
/**
|
|
22
|
+
* Parse one anchor YAML. Uses a minimal YAML reader that handles the shape:
|
|
23
|
+
* type: saas-app
|
|
24
|
+
* score_9_10:
|
|
25
|
+
* criteria:
|
|
26
|
+
* - line one
|
|
27
|
+
* - line two
|
|
28
|
+
* fixtures:
|
|
29
|
+
* - fixture:linear-app
|
|
30
|
+
*
|
|
31
|
+
* Avoids pulling in a YAML dep for ~9 small files. Throws on malformed input.
|
|
32
|
+
*/
|
|
33
|
+
export function parseAnchorFile(filePath) {
|
|
34
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
35
|
+
const parsed = parseAnchorYaml(raw);
|
|
36
|
+
if (!parsed.type || typeof parsed.type !== 'string') {
|
|
37
|
+
throw new Error(`anchor ${filePath} missing 'type' field`);
|
|
38
|
+
}
|
|
39
|
+
for (const band of REQUIRED_BANDS) {
|
|
40
|
+
const node = parsed[band];
|
|
41
|
+
if (!node || typeof node !== 'object') {
|
|
42
|
+
throw new Error(`anchor ${filePath} missing '${band}' band`);
|
|
43
|
+
}
|
|
44
|
+
const b = node;
|
|
45
|
+
if (!Array.isArray(b.criteria) || b.criteria.length === 0) {
|
|
46
|
+
throw new Error(`anchor ${filePath} '${band}.criteria' must be a non-empty array`);
|
|
47
|
+
}
|
|
48
|
+
if (!Array.isArray(b.fixtures) || b.fixtures.length === 0) {
|
|
49
|
+
throw new Error(`anchor ${filePath} '${band}.fixtures' must be a non-empty array`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
/** Load all anchors from `anchors/` into a map keyed by PageType. */
|
|
55
|
+
export function loadAnchors(dir = ANCHORS_DIR) {
|
|
56
|
+
const out = new Map();
|
|
57
|
+
if (!fs.existsSync(dir))
|
|
58
|
+
return out;
|
|
59
|
+
for (const file of fs.readdirSync(dir)) {
|
|
60
|
+
if (!file.endsWith('.yaml') && !file.endsWith('.yml'))
|
|
61
|
+
continue;
|
|
62
|
+
const anchor = parseAnchorFile(path.join(dir, file));
|
|
63
|
+
out.set(anchor.type, anchor);
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/** Render an anchor as a markdown block for prompt injection. */
|
|
68
|
+
export function renderAnchor(anchor) {
|
|
69
|
+
const band = (label, b) => `${label}\n${b.criteria.map((c) => `- ${c}`).join('\n')}\nReferences: ${b.fixtures.join(', ')}`;
|
|
70
|
+
return [
|
|
71
|
+
`Calibration anchor for ${anchor.type}:`,
|
|
72
|
+
band('Score 9-10:', anchor.score_9_10),
|
|
73
|
+
band('Score 7-8:', anchor.score_7_8),
|
|
74
|
+
band('Score 5-6:', anchor.score_5_6),
|
|
75
|
+
band('Score 3-4:', anchor.score_3_4),
|
|
76
|
+
].join('\n\n');
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Minimal YAML parser scoped to the anchor file shape. Supports:
|
|
80
|
+
* key: scalar
|
|
81
|
+
* key:
|
|
82
|
+
* subkey: scalar
|
|
83
|
+
* subkey:
|
|
84
|
+
* - list item
|
|
85
|
+
*
|
|
86
|
+
* Indentation is normalized to spaces; tabs are not supported.
|
|
87
|
+
*/
|
|
88
|
+
function parseAnchorYaml(text) {
|
|
89
|
+
const lines = text.split('\n').map((l) => l.replace(/\r$/, ''));
|
|
90
|
+
const root = {};
|
|
91
|
+
let i = 0;
|
|
92
|
+
while (i < lines.length) {
|
|
93
|
+
const line = lines[i];
|
|
94
|
+
if (!line.trim() || line.trim().startsWith('#')) {
|
|
95
|
+
i++;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const indent = leadingSpaces(line);
|
|
99
|
+
if (indent !== 0) {
|
|
100
|
+
i++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const m = line.match(/^([a-zA-Z_][\w-]*):\s*(.*)$/);
|
|
104
|
+
if (!m) {
|
|
105
|
+
i++;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const [, key, valueRaw] = m;
|
|
109
|
+
const value = valueRaw.trim();
|
|
110
|
+
if (value === '') {
|
|
111
|
+
const { node, nextIndex } = readBlock(lines, i + 1, 2);
|
|
112
|
+
root[key] = node;
|
|
113
|
+
i = nextIndex;
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
root[key] = parseScalar(value);
|
|
117
|
+
i++;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return root;
|
|
121
|
+
}
|
|
122
|
+
function readBlock(lines, startIndex, baseIndent) {
|
|
123
|
+
// Detect: is this a list ("- item") or a map?
|
|
124
|
+
let i = startIndex;
|
|
125
|
+
while (i < lines.length && !lines[i].trim())
|
|
126
|
+
i++;
|
|
127
|
+
if (i >= lines.length)
|
|
128
|
+
return { node: {}, nextIndex: i };
|
|
129
|
+
const firstIndent = leadingSpaces(lines[i]);
|
|
130
|
+
if (firstIndent < baseIndent)
|
|
131
|
+
return { node: {}, nextIndex: i };
|
|
132
|
+
if (lines[i].trim().startsWith('- ') || lines[i].trim() === '-') {
|
|
133
|
+
const items = [];
|
|
134
|
+
while (i < lines.length) {
|
|
135
|
+
const line = lines[i];
|
|
136
|
+
if (!line.trim()) {
|
|
137
|
+
i++;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const indent = leadingSpaces(line);
|
|
141
|
+
if (indent < baseIndent)
|
|
142
|
+
break;
|
|
143
|
+
const trimmed = line.trim();
|
|
144
|
+
if (!trimmed.startsWith('-'))
|
|
145
|
+
break;
|
|
146
|
+
const item = trimmed.replace(/^-\s*/, '');
|
|
147
|
+
items.push(parseScalar(item));
|
|
148
|
+
i++;
|
|
149
|
+
}
|
|
150
|
+
return { node: items, nextIndex: i };
|
|
151
|
+
}
|
|
152
|
+
const map = {};
|
|
153
|
+
while (i < lines.length) {
|
|
154
|
+
const line = lines[i];
|
|
155
|
+
if (!line.trim() || line.trim().startsWith('#')) {
|
|
156
|
+
i++;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const indent = leadingSpaces(line);
|
|
160
|
+
if (indent < baseIndent)
|
|
161
|
+
break;
|
|
162
|
+
if (indent > baseIndent) {
|
|
163
|
+
i++;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const m = line.match(/^\s*([a-zA-Z_][\w-]*):\s*(.*)$/);
|
|
167
|
+
if (!m) {
|
|
168
|
+
i++;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const [, key, valueRaw] = m;
|
|
172
|
+
const value = valueRaw.trim();
|
|
173
|
+
if (value === '') {
|
|
174
|
+
const { node, nextIndex } = readBlock(lines, i + 1, baseIndent + 2);
|
|
175
|
+
map[key] = node;
|
|
176
|
+
i = nextIndex;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
map[key] = parseScalar(value);
|
|
180
|
+
i++;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { node: map, nextIndex: i };
|
|
184
|
+
}
|
|
185
|
+
function leadingSpaces(line) {
|
|
186
|
+
let n = 0;
|
|
187
|
+
while (n < line.length && line[n] === ' ')
|
|
188
|
+
n++;
|
|
189
|
+
return n;
|
|
190
|
+
}
|
|
191
|
+
function parseScalar(raw) {
|
|
192
|
+
let value = raw.trim();
|
|
193
|
+
if (value === '')
|
|
194
|
+
return '';
|
|
195
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
196
|
+
value = value.slice(1, -1);
|
|
197
|
+
}
|
|
198
|
+
if (value === 'true')
|
|
199
|
+
return true;
|
|
200
|
+
if (value === 'false')
|
|
201
|
+
return false;
|
|
202
|
+
if (value === 'null' || value === '~')
|
|
203
|
+
return null;
|
|
204
|
+
if (/^-?\d+$/.test(value))
|
|
205
|
+
return Number(value);
|
|
206
|
+
if (/^-?\d+\.\d+$/.test(value))
|
|
207
|
+
return Number(value);
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=anchor-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anchor-loader.js","sourceRoot":"","sources":["../../../../src/design/audit/rubric/anchor-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type: blog
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Reading column tuned to 60-75 character measure with deliberate vertical rhythm
|
|
5
|
+
- Typography scale supports headings, body, callouts, code, captions distinctly
|
|
6
|
+
- Author identity and publication date prominent without being chrome
|
|
7
|
+
- Inline media (images, code, embeds) integrate cleanly with text flow
|
|
8
|
+
- Navigation between posts (next, related, archive) supports the reading habit
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:stratechery
|
|
11
|
+
- fixture:substack-post
|
|
12
|
+
- fixture:notion-blog-template
|
|
13
|
+
score_7_8:
|
|
14
|
+
criteria:
|
|
15
|
+
- Strong reading experience but typographic scale is one step shy of intentional
|
|
16
|
+
- Author and date present but visually inconsistent
|
|
17
|
+
- Inline media works but breaks rhythm at boundaries
|
|
18
|
+
fixtures:
|
|
19
|
+
- fixture:medium-default
|
|
20
|
+
score_5_6:
|
|
21
|
+
criteria:
|
|
22
|
+
- Default theme typography (no custom scale, line-height defaults)
|
|
23
|
+
- Heavy chrome (sidebar, social rail) competing with the article
|
|
24
|
+
- Author/date hidden in footer
|
|
25
|
+
fixtures:
|
|
26
|
+
- fixture:default-ghost
|
|
27
|
+
score_3_4:
|
|
28
|
+
criteria:
|
|
29
|
+
- Article copy crammed against gutters; no measure control
|
|
30
|
+
- Inline ads break reading flow every paragraph
|
|
31
|
+
- No publication date — content is unanchored in time
|
|
32
|
+
fixtures:
|
|
33
|
+
- fixture:ad-heavy-article
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type: dashboard
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Real metrics with units, time windows, and comparison baselines visible at first glance
|
|
5
|
+
- Charts use deliberate scales, axis labels, and selective color (not rainbow defaults)
|
|
6
|
+
- Filters, time ranges, and segment selectors are obvious and persistent
|
|
7
|
+
- Empty states preview real data shape (sample rows, last-7-days skeleton)
|
|
8
|
+
- Density tuned to operator workflow — no decorative whitespace where dense data belongs
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:linear-app
|
|
11
|
+
- fixture:figma-file-ui
|
|
12
|
+
- fixture:datadog-dashboard
|
|
13
|
+
- fixture:vercel-dashboard
|
|
14
|
+
score_7_8:
|
|
15
|
+
criteria:
|
|
16
|
+
- Metrics present and useful but lack comparison baselines or time-window controls
|
|
17
|
+
- Charts readable but use default color palette; minor density issues
|
|
18
|
+
- Filters present but discoverability unclear
|
|
19
|
+
fixtures:
|
|
20
|
+
- fixture:grafana-default
|
|
21
|
+
score_5_6:
|
|
22
|
+
criteria:
|
|
23
|
+
- Generic stat cards (4 equal boxes) without context or comparison
|
|
24
|
+
- Charts are rainbow defaults from the component library
|
|
25
|
+
- No filters or time-range affordance
|
|
26
|
+
- Empty states are illustrations + platitudes
|
|
27
|
+
fixtures:
|
|
28
|
+
- fixture:generic-dashboard
|
|
29
|
+
score_3_4:
|
|
30
|
+
criteria:
|
|
31
|
+
- Numbers without units, labels, or context — operator cannot tell good from bad
|
|
32
|
+
- Decorative chart visualizations (donuts, gauges) instead of operational data
|
|
33
|
+
- Equal-weight UI controls; no clear workflow path
|
|
34
|
+
fixtures:
|
|
35
|
+
- fixture:empty-state-noise
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
type: docs
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Quickstart path from landing to a working result is obvious within one viewport
|
|
5
|
+
- Code samples are runnable, copy-button-equipped, and language-tabbed where relevant
|
|
6
|
+
- Reference structure (sidebar, breadcrumbs, search) supports both linear and lookup reading
|
|
7
|
+
- Versioning, deprecation, and last-updated signals are visible
|
|
8
|
+
- Typography scale and line-length tuned for sustained reading
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:stripe-docs
|
|
11
|
+
- fixture:tailwind-docs
|
|
12
|
+
- fixture:mdn-docs
|
|
13
|
+
- fixture:vercel-docs
|
|
14
|
+
score_7_8:
|
|
15
|
+
criteria:
|
|
16
|
+
- Quickstart present but buried; copy is solid but examples are partial
|
|
17
|
+
- Sidebar IA works but search is weak or missing
|
|
18
|
+
- Versioning unclear
|
|
19
|
+
fixtures:
|
|
20
|
+
- fixture:generic-mkdocs
|
|
21
|
+
score_5_6:
|
|
22
|
+
criteria:
|
|
23
|
+
- Wall-of-text reference with no quickstart
|
|
24
|
+
- Code samples without copy buttons or language switching
|
|
25
|
+
- No search, no breadcrumbs, no last-updated metadata
|
|
26
|
+
- Default theme typography (inconsistent line-height, no scale)
|
|
27
|
+
fixtures:
|
|
28
|
+
- fixture:default-docusaurus
|
|
29
|
+
score_3_4:
|
|
30
|
+
criteria:
|
|
31
|
+
- Marketing page disguised as docs (heavy hero, no actual reference)
|
|
32
|
+
- No code samples or syntax highlighting
|
|
33
|
+
- IA broken — "Getting Started" buried under marketing copy
|
|
34
|
+
fixtures:
|
|
35
|
+
- fixture:marketing-as-docs
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type: ecommerce
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Product photography is real, detailed, and honest (not stock or AI-rendered)
|
|
5
|
+
- Price, fees, taxes, shipping, and total are surfaced before the commit button
|
|
6
|
+
- Stock, delivery, and return-policy signals are visible at decision points
|
|
7
|
+
- Cart and checkout flows preserve context — user always knows what they are buying
|
|
8
|
+
- Trust signals (verified payment, secure checkout, real merchant identity) appear where commitment occurs
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:apple-store
|
|
11
|
+
- fixture:shopify-storefront
|
|
12
|
+
- fixture:allbirds-pdp
|
|
13
|
+
score_7_8:
|
|
14
|
+
criteria:
|
|
15
|
+
- Solid PDPs but checkout exposes fees only at the last step
|
|
16
|
+
- Stock and delivery info present but inconsistent across pages
|
|
17
|
+
- Photography mixes real and stock
|
|
18
|
+
fixtures:
|
|
19
|
+
- fixture:generic-shopify
|
|
20
|
+
score_5_6:
|
|
21
|
+
criteria:
|
|
22
|
+
- Fees surfaced only after pressing Pay; no shipping calculator
|
|
23
|
+
- Stock/delivery signals missing on PDPs
|
|
24
|
+
- Generic merchant identity, no trust badges, no return policy summary
|
|
25
|
+
fixtures:
|
|
26
|
+
- fixture:hidden-fees-checkout
|
|
27
|
+
score_3_4:
|
|
28
|
+
criteria:
|
|
29
|
+
- Total never shown until after commitment
|
|
30
|
+
- No merchant identity, no return policy, no trust signals
|
|
31
|
+
- Forced account creation before checkout, dark-pattern upsells
|
|
32
|
+
fixtures:
|
|
33
|
+
- fixture:dark-pattern-checkout
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
type: marketing
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Hero answers product, audience, and outcome within five seconds
|
|
5
|
+
- One dominant CTA, secondary actions clearly subordinate
|
|
6
|
+
- Concrete proof (real customer logos, real metrics, real screenshots) above the fold
|
|
7
|
+
- Visual craft (typography ramp, spacing rhythm, color system) is intentional, not template-default
|
|
8
|
+
- Differentiation is shown, not asserted; copy avoids vague hype
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:stripe-marketing
|
|
11
|
+
- fixture:linear-marketing
|
|
12
|
+
- fixture:vercel-marketing
|
|
13
|
+
- fixture:apple-marketing
|
|
14
|
+
score_7_8:
|
|
15
|
+
criteria:
|
|
16
|
+
- Hero clear, but proof is generic (lorem-style logo cloud) or differentiation thin
|
|
17
|
+
- Visual system coherent but unremarkable; one or two minor rhythm breaks
|
|
18
|
+
- CTA dominant on hero but competes elsewhere
|
|
19
|
+
fixtures:
|
|
20
|
+
- fixture:generic-saas-marketing
|
|
21
|
+
score_5_6:
|
|
22
|
+
criteria:
|
|
23
|
+
- Hero copy explains the product instead of selling the outcome
|
|
24
|
+
- Visual hierarchy works but feels like a Tailwind starter
|
|
25
|
+
- Equal-weight CTAs, vague social proof, stock illustrations
|
|
26
|
+
fixtures:
|
|
27
|
+
- fixture:meta-copy-feature
|
|
28
|
+
score_3_4:
|
|
29
|
+
criteria:
|
|
30
|
+
- No primary message; could swap nouns and apply to any startup
|
|
31
|
+
- No CTA hierarchy; the page is a wall of equal sections
|
|
32
|
+
- Stock photography, generic gradients, default UI kit components
|
|
33
|
+
fixtures:
|
|
34
|
+
- fixture:ambiguous-deploy
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
type: saas-app
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Domain object visible above the fold (tasks, deployments, conversations, files)
|
|
5
|
+
- One visually-dominant primary action per page state
|
|
6
|
+
- Empty states preview real product (sample rows, setup checklists, status timelines), not generic illustrations
|
|
7
|
+
- Action hierarchy = product hierarchy; no decorative buttons competing with workflow
|
|
8
|
+
- Trust details visible where commitment exists (price, permissions, undo, audit trail)
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:linear-app
|
|
11
|
+
- fixture:figma-file-ui
|
|
12
|
+
- fixture:notion-editor
|
|
13
|
+
- fixture:superhuman
|
|
14
|
+
- fixture:github-pr-view
|
|
15
|
+
score_7_8:
|
|
16
|
+
criteria:
|
|
17
|
+
- Most criteria from 9-10 with one or two minor gaps
|
|
18
|
+
- Polish gaps that don't block job completion
|
|
19
|
+
- Domain objects present but action hierarchy slightly diffuse
|
|
20
|
+
fixtures:
|
|
21
|
+
- fixture:airtable-grid
|
|
22
|
+
- fixture:notion-database
|
|
23
|
+
score_5_6:
|
|
24
|
+
criteria:
|
|
25
|
+
- Functional but generic component-library assembly
|
|
26
|
+
- No domain object above the fold OR action hierarchy unclear
|
|
27
|
+
- Empty states show illustrations + platitudes instead of product preview
|
|
28
|
+
- Multiple equal-weight CTAs without a dominant primary
|
|
29
|
+
fixtures:
|
|
30
|
+
- fixture:generic-dashboard
|
|
31
|
+
score_3_4:
|
|
32
|
+
criteria:
|
|
33
|
+
- No primary job inferable from screen
|
|
34
|
+
- Equal-weight CTAs blocking workflow
|
|
35
|
+
- Decorative elements actively distract from product surface
|
|
36
|
+
- Page reads as a marketing/setup stub rather than an operational product
|
|
37
|
+
fixtures:
|
|
38
|
+
- fixture:no-primary-action
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type: social
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Feed prioritizes real content (posts, conversations) over chrome and ads
|
|
5
|
+
- Compose surface is one click away and primary in the layout
|
|
6
|
+
- Identity signals (verified accounts, profile preview, follower counts) consistent and lightweight
|
|
7
|
+
- State transitions (like, reply, repost) feel instant and reversible
|
|
8
|
+
- Empty states preview what the feed will look like with a few followed accounts
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:threads-web
|
|
11
|
+
- fixture:bluesky-web
|
|
12
|
+
- fixture:substack-inline
|
|
13
|
+
score_7_8:
|
|
14
|
+
criteria:
|
|
15
|
+
- Solid feed and compose flow but reply chains are visually flat
|
|
16
|
+
- Identity signals inconsistent across surfaces
|
|
17
|
+
- Empty states use illustrations rather than previewing real content
|
|
18
|
+
fixtures:
|
|
19
|
+
- fixture:generic-microblog
|
|
20
|
+
score_5_6:
|
|
21
|
+
criteria:
|
|
22
|
+
- Feed cluttered with chrome (rails, ads, suggestions) competing with content
|
|
23
|
+
- Compose buried two clicks deep
|
|
24
|
+
- Action affordances (reply, like, share) are equal weight with no clear primary
|
|
25
|
+
fixtures:
|
|
26
|
+
- fixture:cluttered-feed
|
|
27
|
+
score_3_4:
|
|
28
|
+
criteria:
|
|
29
|
+
- Page reads as ad inventory with content squeezed in
|
|
30
|
+
- No clear primary feed; multiple surfaces compete
|
|
31
|
+
- Identity signals fake or absent (anonymous content with no provenance)
|
|
32
|
+
fixtures:
|
|
33
|
+
- fixture:ad-heavy-feed
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type: tool
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Single-purpose surface — the input and output relationship is immediate and obvious
|
|
5
|
+
- Keyboard-first interaction (shortcuts, focus management, paste support)
|
|
6
|
+
- Output is copyable, exportable, and shareable without modal interruption
|
|
7
|
+
- Recent results, history, or undo always available
|
|
8
|
+
- State (input, processing, output, error) handled explicitly with clear transitions
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:linear-command-palette
|
|
11
|
+
- fixture:github-pr-view
|
|
12
|
+
- fixture:raycast
|
|
13
|
+
score_7_8:
|
|
14
|
+
criteria:
|
|
15
|
+
- Tool works well but lacks keyboard affordances or history
|
|
16
|
+
- Output exportable but with extra clicks
|
|
17
|
+
- Error states present but generic
|
|
18
|
+
fixtures:
|
|
19
|
+
- fixture:generic-converter
|
|
20
|
+
score_5_6:
|
|
21
|
+
criteria:
|
|
22
|
+
- Form-and-submit pattern with reload-style output
|
|
23
|
+
- No keyboard shortcuts, no history, no undo
|
|
24
|
+
- Loading and error states use defaults
|
|
25
|
+
fixtures:
|
|
26
|
+
- fixture:basic-tool-form
|
|
27
|
+
score_3_4:
|
|
28
|
+
criteria:
|
|
29
|
+
- Multi-step flow for what should be a single action
|
|
30
|
+
- Output requires manual selection/copy
|
|
31
|
+
- No error handling — failures show generic browser errors
|
|
32
|
+
fixtures:
|
|
33
|
+
- fixture:broken-tool
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type: utility
|
|
2
|
+
score_9_10:
|
|
3
|
+
criteria:
|
|
4
|
+
- Status, configuration, or admin surface that exposes the operational object directly (deploy, build, job, account)
|
|
5
|
+
- Real state (running, succeeded, failed, queued) with timestamps and durations
|
|
6
|
+
- Action affordances (retry, rollback, configure, audit) match the operational verbs of the system
|
|
7
|
+
- Logs, diagnostics, or detail panels are one click from the summary
|
|
8
|
+
- Empty states preview what real activity will look like
|
|
9
|
+
fixtures:
|
|
10
|
+
- fixture:vercel-deployment-status
|
|
11
|
+
- fixture:cloudflare-dashboard
|
|
12
|
+
- fixture:github-actions
|
|
13
|
+
score_7_8:
|
|
14
|
+
criteria:
|
|
15
|
+
- Status surface clear but action affordances are generic (Edit/Save instead of Retry/Rollback)
|
|
16
|
+
- Logs accessible but require navigation
|
|
17
|
+
- Empty states use illustrations rather than previewing activity
|
|
18
|
+
fixtures:
|
|
19
|
+
- fixture:generic-admin
|
|
20
|
+
score_5_6:
|
|
21
|
+
criteria:
|
|
22
|
+
- Status indicators are decorative pills without timestamps or durations
|
|
23
|
+
- Logs and diagnostics buried in modals
|
|
24
|
+
- Forms-of-forms pattern instead of operational verbs
|
|
25
|
+
fixtures:
|
|
26
|
+
- fixture:basic-settings-page
|
|
27
|
+
score_3_4:
|
|
28
|
+
criteria:
|
|
29
|
+
- Status is text only — no visual signal of failure or success
|
|
30
|
+
- No way to retry, rollback, or audit from the surface
|
|
31
|
+
- Settings sprawl with no IA, no search
|
|
32
|
+
fixtures:
|
|
33
|
+
- fixture:settings-sprawl
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: audience-clinician
|
|
3
|
+
title: Clinician Audience
|
|
4
|
+
weight: high
|
|
5
|
+
applies-when:
|
|
6
|
+
audience: [clinician]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
This surface is used by clinical professionals (physicians, nurses, pharmacists,
|
|
10
|
+
therapists) in high-stakes decision-making contexts. Standard consumer-UX
|
|
11
|
+
heuristics are insufficient — apply the following additional lens.
|
|
12
|
+
|
|
13
|
+
INFORMATION DENSITY
|
|
14
|
+
- Clinicians tolerate and often require high information density. Sparse
|
|
15
|
+
consumer-style layouts that hide detail behind progressive disclosure are
|
|
16
|
+
friction, not polish.
|
|
17
|
+
- Data tables, lab result grids, medication lists must be fully visible without
|
|
18
|
+
expand/collapse. If key data is folded, score `content_ia` lower.
|
|
19
|
+
|
|
20
|
+
WORKFLOW EFFICIENCY
|
|
21
|
+
- Clinicians context-switch constantly (patient to patient, chart to EHR to
|
|
22
|
+
order entry). Keyboard navigation, dense primary actions, and minimal
|
|
23
|
+
confirmation dialogs for routine operations are expected.
|
|
24
|
+
- If standard consumer patterns (fat CTAs, step-by-step wizards) dominate
|
|
25
|
+
routine tasks, score `workflow` lower.
|
|
26
|
+
|
|
27
|
+
CRITICAL VALUE FLAGGING
|
|
28
|
+
- Out-of-range lab values, drug interactions, and alert states must be
|
|
29
|
+
immediately visible with high visual contrast — not just color. Include
|
|
30
|
+
icon + text pattern redundancy.
|
|
31
|
+
- Missing or weak critical-value flagging is a major finding in `trust_clarity`.
|
|
32
|
+
|
|
33
|
+
AUDIT TRAIL AND ATTRIBUTION
|
|
34
|
+
- Clinician workflows require visible "who did what, when" — last modified by,
|
|
35
|
+
order placed by, cosigned by. This is both regulatory and practical.
|
|
36
|
+
- If attributable actions lack visible provenance, that is a major finding in
|
|
37
|
+
`trust_clarity`.
|
|
38
|
+
|
|
39
|
+
DO NOT penalize for:
|
|
40
|
+
- Dense information layouts (this is intentional)
|
|
41
|
+
- Lack of illustrations or hero imagery
|
|
42
|
+
- Technical terminology appropriate to the audience
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: audience-developer
|
|
3
|
+
title: Developer Audience
|
|
4
|
+
weight: medium
|
|
5
|
+
applies-when:
|
|
6
|
+
audience: [developer]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
This surface is used by software engineers and technical practitioners.
|
|
10
|
+
|
|
11
|
+
INFORMATION OVER DECORATION
|
|
12
|
+
- Code samples, CLI commands, API endpoints, and technical specifications must
|
|
13
|
+
be immediately accessible — not gated behind tabs, scrolling, or "Request
|
|
14
|
+
Demo" flows. If core technical content requires navigation to find, score
|
|
15
|
+
`content_ia` lower.
|
|
16
|
+
|
|
17
|
+
COPY-PASTE HYGIENE
|
|
18
|
+
- Every code block must have a visible copy button or be selectable without
|
|
19
|
+
capturing surrounding prose. Missing copy affordance is a minor-to-major
|
|
20
|
+
finding in `workflow` depending on frequency.
|
|
21
|
+
|
|
22
|
+
DARK MODE AND TERMINAL AESTHETICS
|
|
23
|
+
- Developers default to dark environments. A light-only surface with no dark
|
|
24
|
+
mode is a `visual_craft` minor finding. A surface that actively breaks
|
|
25
|
+
(illegible code contrast) in dark mode is major.
|
|
26
|
+
|
|
27
|
+
AUTHENTICATION PATHS
|
|
28
|
+
- API keys, tokens, and credentials should be displayed with
|
|
29
|
+
mask-by-default + reveal-on-click. Showing credentials in plaintext by
|
|
30
|
+
default is a critical `trust_clarity` finding.
|
|
31
|
+
|
|
32
|
+
SEARCH AS PRIMARY NAVIGATION
|
|
33
|
+
- Technical docs and reference surfaces must have a prominent, keyboard-
|
|
34
|
+
accessible search. If Cmd/Ctrl-K does not open search, that is a major
|
|
35
|
+
finding in `workflow`.
|
|
36
|
+
|
|
37
|
+
DO NOT penalize for:
|
|
38
|
+
- Dense information layouts
|
|
39
|
+
- Monospace typography sections
|
|
40
|
+
- Minimal illustration or marketing copy
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: audience-kids
|
|
3
|
+
title: Kids Audience
|
|
4
|
+
weight: critical
|
|
5
|
+
applies-when:
|
|
6
|
+
audience: [kids]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
This surface is used by or targeted at minors. Apply the following additional
|
|
10
|
+
lens. Note: ethics rules in Layer 7 enforce hard score floors independently
|
|
11
|
+
of rubric scoring — both layers apply simultaneously.
|
|
12
|
+
|
|
13
|
+
AGE-APPROPRIATE LANGUAGE AND IMAGERY
|
|
14
|
+
- Copy must be readable at the stated age level. Technical jargon, legalese,
|
|
15
|
+
or implicit social pressure ("Your friends are waiting!") are major findings
|
|
16
|
+
in `content_ia`.
|
|
17
|
+
- Imagery should be appropriate for the age group. Mature themes, even subtle
|
|
18
|
+
ones, are critical findings in `trust_clarity`.
|
|
19
|
+
|
|
20
|
+
FRICTION-SYMMETRIC FLOWS
|
|
21
|
+
- Actions that benefit the operator (in-app purchase, data sharing, account
|
|
22
|
+
creation) must have equal or greater friction than their reversal
|
|
23
|
+
(cancellation, data deletion, account closure).
|
|
24
|
+
- Any flow where it is easier to spend money / share data than to undo is a
|
|
25
|
+
critical finding in `workflow`.
|
|
26
|
+
|
|
27
|
+
PARENTAL CONTROLS VISIBILITY
|
|
28
|
+
- If the app collects data from minors, parental consent or control mechanisms
|
|
29
|
+
must be visible without buried navigation. If absent: major finding in
|
|
30
|
+
`trust_clarity`.
|
|
31
|
+
|
|
32
|
+
DO NOT penalize for:
|
|
33
|
+
- Simplified language and larger touch targets
|
|
34
|
+
- Reduced information density appropriate to age
|
|
35
|
+
- Bright color palettes and playful illustration styles
|