jourilo 1.1.0 → 1.2.1

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.
@@ -0,0 +1,555 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/cihantopac/jourilo/main/schemas/run.schema.json",
4
+ "title": "Jourilo run",
5
+ "description": "run.json, schemaVersion 1. Within a schemaVersion fields are only added, and added fields are optional, so readers must ignore unknown fields. See docs/RUN-FORMAT.md.",
6
+ "type": "object",
7
+ "required": [
8
+ "schemaVersion",
9
+ "id",
10
+ "tool",
11
+ "mode",
12
+ "target",
13
+ "startedAt",
14
+ "finishedAt",
15
+ "browser",
16
+ "viewports",
17
+ "settings",
18
+ "pages",
19
+ "journeys",
20
+ "findings",
21
+ "summary",
22
+ "limitations"
23
+ ],
24
+ "properties": {
25
+ "$schema": { "type": "string" },
26
+ "schemaVersion": { "const": 1 },
27
+ "id": { "type": "string" },
28
+ "tool": {
29
+ "type": "object",
30
+ "required": ["name", "version"],
31
+ "properties": { "name": { "const": "jourilo" }, "version": { "type": "string" } }
32
+ },
33
+ "mode": { "enum": ["website", "repository"] },
34
+ "target": { "type": "string" },
35
+ "startedAt": { "type": "string", "format": "date-time" },
36
+ "finishedAt": { "type": "string", "format": "date-time" },
37
+ "browser": {
38
+ "type": "object",
39
+ "required": ["name", "version"],
40
+ "properties": { "name": { "type": "string" }, "version": { "type": "string" } }
41
+ },
42
+ "viewports": { "type": "array", "items": { "$ref": "#/$defs/viewport" } },
43
+ "settings": {
44
+ "description": "How the run was configured. Keys vary by version; every key listed here is optional.",
45
+ "type": "object",
46
+ "properties": {
47
+ "maxPages": { "type": "integer" },
48
+ "maxDepth": { "type": "integer" },
49
+ "respectRobots": { "type": "boolean" },
50
+ "keyboard": { "type": "boolean" },
51
+ "throttle": {},
52
+ "runs": { "type": "integer" },
53
+ "setupJourney": { "type": "string", "description": "Id of the journey that ran before the audit." },
54
+ "timezoneId": { "type": "string" },
55
+ "clock": { "type": "string" },
56
+ "evidence": {
57
+ "enum": ["full", "minimal"],
58
+ "description": "Absent means full. minimal: first screens plus the full-page screenshots findings need."
59
+ },
60
+ "axe": { "type": ["string", "null"] },
61
+ "hostClass": { "type": "string" },
62
+ "scope": {
63
+ "type": "object",
64
+ "properties": {
65
+ "urls": { "type": "array", "items": { "type": "string" } },
66
+ "viewports": { "type": "array", "items": { "type": "string" } }
67
+ }
68
+ }
69
+ }
70
+ },
71
+ "pages": { "type": "array", "items": { "$ref": "#/$defs/page" } },
72
+ "journeys": { "type": "array", "items": { "$ref": "#/$defs/journeyResult" } },
73
+ "findings": { "type": "array", "items": { "$ref": "#/$defs/finding" } },
74
+ "summary": { "$ref": "#/$defs/summary" },
75
+ "limitations": {
76
+ "description": "Things Jourilo could not check in this run.",
77
+ "type": "array",
78
+ "items": { "type": "string" }
79
+ },
80
+ "product": { "description": "Product intelligence attached by `discover`." },
81
+ "context": {
82
+ "description": "Brand and search context (jourilo.context/v1) used by this run.",
83
+ "type": "object",
84
+ "properties": {
85
+ "schema": { "type": "string" },
86
+ "brand": { "type": ["object", "null"] },
87
+ "search": { "type": ["object", "null"] },
88
+ "notes": { "type": "array", "items": { "type": "string" } }
89
+ }
90
+ },
91
+ "network": {
92
+ "description": "What the network guard refused or detected during the run.",
93
+ "type": "object",
94
+ "required": ["blocked", "escaped"],
95
+ "properties": {
96
+ "blocked": {
97
+ "type": "array",
98
+ "items": {
99
+ "type": "object",
100
+ "required": ["host", "port", "reason"],
101
+ "properties": {
102
+ "host": { "type": "string" },
103
+ "port": { "type": "integer" },
104
+ "reason": { "type": "string" }
105
+ }
106
+ }
107
+ },
108
+ "escaped": {
109
+ "type": "array",
110
+ "items": {
111
+ "type": "object",
112
+ "required": ["url", "reason"],
113
+ "properties": { "url": { "type": "string" }, "reason": { "type": "string" } }
114
+ }
115
+ }
116
+ }
117
+ },
118
+ "outcome": {
119
+ "description": "`no-page-loaded`: no page got a response. `partial`: the run was stopped early (see stoppedBy). Absent in older runs.",
120
+ "enum": ["complete", "no-page-loaded", "partial"]
121
+ },
122
+ "stoppedBy": {
123
+ "description": "Why a partial run stopped.",
124
+ "enum": ["signal", "max-duration"]
125
+ },
126
+ "dismissed": {
127
+ "description": "Findings a person or agent dismissed. Not counted in summary.",
128
+ "type": "array",
129
+ "items": {
130
+ "allOf": [
131
+ { "$ref": "#/$defs/finding" },
132
+ {
133
+ "type": "object",
134
+ "required": ["dismissal"],
135
+ "properties": { "dismissal": { "$ref": "#/$defs/dismissal" } }
136
+ }
137
+ ]
138
+ }
139
+ }
140
+ },
141
+ "$defs": {
142
+ "severity": { "enum": ["critical", "serious", "moderate", "minor", "info"] },
143
+ "confidence": { "enum": ["high", "medium", "low"] },
144
+ "category": {
145
+ "enum": [
146
+ "accessibility",
147
+ "usability",
148
+ "responsive",
149
+ "performance",
150
+ "conversion",
151
+ "reliability",
152
+ "content",
153
+ "design-system"
154
+ ]
155
+ },
156
+ "kind": { "enum": ["defect", "hypothesis", "needs-review"] },
157
+ "rect": {
158
+ "type": "object",
159
+ "required": ["x", "y", "width", "height"],
160
+ "properties": {
161
+ "x": { "type": "number" },
162
+ "y": { "type": "number" },
163
+ "width": { "type": "number" },
164
+ "height": { "type": "number" }
165
+ }
166
+ },
167
+ "viewport": {
168
+ "type": "object",
169
+ "required": ["name", "width", "height", "deviceScaleFactor", "isMobile", "hasTouch"],
170
+ "properties": {
171
+ "name": { "type": "string" },
172
+ "width": { "type": "number" },
173
+ "height": { "type": "number" },
174
+ "deviceScaleFactor": { "type": "number" },
175
+ "isMobile": { "type": "boolean" },
176
+ "hasTouch": { "type": "boolean" }
177
+ }
178
+ },
179
+ "summary": {
180
+ "type": "object",
181
+ "required": ["pages", "journeys", "findings", "byCategory", "byKind"],
182
+ "properties": {
183
+ "pages": { "type": "integer" },
184
+ "journeys": { "type": "integer" },
185
+ "findings": { "type": "object", "additionalProperties": { "type": "integer" } },
186
+ "byCategory": { "type": "object", "additionalProperties": { "type": "integer" } },
187
+ "byKind": { "type": "object", "additionalProperties": { "type": "integer" } }
188
+ }
189
+ },
190
+ "standardRef": {
191
+ "type": "object",
192
+ "required": ["standard", "id", "title"],
193
+ "properties": {
194
+ "standard": { "type": "string" },
195
+ "id": { "type": "string" },
196
+ "title": { "type": "string" },
197
+ "url": { "type": "string" }
198
+ }
199
+ },
200
+ "evidence": {
201
+ "type": "object",
202
+ "required": ["type"],
203
+ "properties": {
204
+ "type": {
205
+ "enum": [
206
+ "screenshot",
207
+ "element",
208
+ "console",
209
+ "network",
210
+ "metric",
211
+ "axe",
212
+ "step",
213
+ "trace",
214
+ "source",
215
+ "dom"
216
+ ]
217
+ },
218
+ "file": { "type": "string", "description": "Path relative to the run directory." },
219
+ "rect": { "$ref": "#/$defs/rect" },
220
+ "selector": { "type": "string" },
221
+ "snippet": { "type": "string" },
222
+ "data": { "type": "object" },
223
+ "note": { "type": "string" }
224
+ }
225
+ },
226
+ "sourceLocation": {
227
+ "type": "object",
228
+ "required": ["file", "line", "reason", "confidence"],
229
+ "properties": {
230
+ "file": { "type": "string" },
231
+ "line": { "type": "integer" },
232
+ "column": { "type": "integer" },
233
+ "excerpt": { "type": "string" },
234
+ "reason": { "type": "string" },
235
+ "confidence": { "$ref": "#/$defs/confidence" }
236
+ }
237
+ },
238
+ "finding": {
239
+ "type": "object",
240
+ "required": [
241
+ "fingerprint",
242
+ "ruleId",
243
+ "title",
244
+ "category",
245
+ "kind",
246
+ "severity",
247
+ "confidence",
248
+ "provenance",
249
+ "url",
250
+ "description",
251
+ "impact",
252
+ "recommendation",
253
+ "standards",
254
+ "evidence",
255
+ "reproduction",
256
+ "occurrences"
257
+ ],
258
+ "properties": {
259
+ "fingerprint": { "type": "string" },
260
+ "ruleId": { "type": "string" },
261
+ "title": { "type": "string" },
262
+ "category": { "$ref": "#/$defs/category" },
263
+ "kind": { "$ref": "#/$defs/kind" },
264
+ "severity": { "$ref": "#/$defs/severity" },
265
+ "confidence": { "$ref": "#/$defs/confidence" },
266
+ "provenance": { "enum": ["measured", "observed", "heuristic", "inferred", "user"] },
267
+ "url": { "type": "string" },
268
+ "viewport": { "type": "string" },
269
+ "journey": { "type": "string" },
270
+ "description": { "type": "string" },
271
+ "impact": { "type": "string" },
272
+ "recommendation": { "type": "string" },
273
+ "standards": { "type": "array", "items": { "$ref": "#/$defs/standardRef" } },
274
+ "evidence": { "type": "array", "items": { "$ref": "#/$defs/evidence" } },
275
+ "reproduction": { "type": "array", "items": { "type": "string" } },
276
+ "sources": { "type": "array", "items": { "$ref": "#/$defs/sourceLocation" } },
277
+ "occurrences": { "type": "integer" }
278
+ }
279
+ },
280
+ "dismissal": {
281
+ "type": "object",
282
+ "required": ["fingerprint", "ruleId", "url", "reason", "by", "at"],
283
+ "properties": {
284
+ "fingerprint": { "type": "string" },
285
+ "ruleId": { "type": "string" },
286
+ "url": { "type": "string" },
287
+ "reason": { "type": "string" },
288
+ "by": { "enum": ["user", "agent"] },
289
+ "at": { "type": "string" }
290
+ }
291
+ },
292
+ "metric": {
293
+ "type": "object",
294
+ "required": ["name", "value", "unit", "source"],
295
+ "properties": {
296
+ "name": { "type": "string" },
297
+ "value": { "type": "number" },
298
+ "unit": { "enum": ["ms", "score", "bytes", "count"] },
299
+ "source": { "const": "lab" },
300
+ "rating": { "enum": ["good", "needs-improvement", "poor"] },
301
+ "note": { "type": "string" },
302
+ "runs": { "type": "integer" },
303
+ "range": { "type": "array", "items": { "type": "number" }, "minItems": 2, "maxItems": 2 }
304
+ }
305
+ },
306
+ "page": {
307
+ "type": "object",
308
+ "required": [
309
+ "url",
310
+ "finalUrl",
311
+ "status",
312
+ "title",
313
+ "viewport",
314
+ "loadMs",
315
+ "metrics",
316
+ "consoleErrors",
317
+ "failedRequests",
318
+ "inventory"
319
+ ],
320
+ "properties": {
321
+ "url": { "type": "string" },
322
+ "finalUrl": { "type": "string" },
323
+ "status": { "type": ["integer", "null"] },
324
+ "title": { "type": "string" },
325
+ "viewport": { "type": "string" },
326
+ "screenshot": { "type": "string", "description": "Path relative to the run directory." },
327
+ "foldScreenshot": {
328
+ "type": "string",
329
+ "description": "First-screen screenshot, relative to the run directory."
330
+ },
331
+ "loadMs": { "type": "number" },
332
+ "metrics": { "type": "array", "items": { "$ref": "#/$defs/metric" } },
333
+ "consoleErrors": { "type": "integer" },
334
+ "failedRequests": { "type": "integer" },
335
+ "inventory": { "$ref": "#/$defs/inventory" }
336
+ }
337
+ },
338
+ "inventory": {
339
+ "description": "Product-facing inventory of a page. Nested ctas, forms and links are loosely described on purpose.",
340
+ "type": "object",
341
+ "required": [
342
+ "lang",
343
+ "h1",
344
+ "headings",
345
+ "landmarks",
346
+ "ctas",
347
+ "forms",
348
+ "links",
349
+ "images",
350
+ "trustSignals",
351
+ "pricingSignals",
352
+ "wordCount",
353
+ "metaDescription",
354
+ "hasViewportMeta"
355
+ ],
356
+ "properties": {
357
+ "lang": { "type": ["string", "null"] },
358
+ "h1": { "type": "array", "items": { "type": "string" } },
359
+ "headings": {
360
+ "type": "array",
361
+ "items": {
362
+ "type": "object",
363
+ "required": ["level", "text"],
364
+ "properties": { "level": { "type": "integer" }, "text": { "type": "string" } }
365
+ }
366
+ },
367
+ "landmarks": { "type": "array", "items": { "type": "string" } },
368
+ "ctas": {
369
+ "type": "array",
370
+ "items": {
371
+ "type": "object",
372
+ "required": ["text", "selector", "href", "rect", "aboveFold", "emphasis"],
373
+ "properties": {
374
+ "text": { "type": "string" },
375
+ "selector": { "type": "string" },
376
+ "href": { "type": ["string", "null"] },
377
+ "rect": { "$ref": "#/$defs/rect" },
378
+ "aboveFold": { "type": "boolean" },
379
+ "emphasis": { "enum": ["primary", "secondary", "link"] }
380
+ }
381
+ }
382
+ },
383
+ "toggles": {
384
+ "description": "Collapsed disclosures (aria-expanded=false) and unpressed toggle buttons (aria-pressed=false), at most 10 per page.",
385
+ "type": "array",
386
+ "items": {
387
+ "type": "object",
388
+ "required": ["selector", "name", "state", "controls"],
389
+ "properties": {
390
+ "selector": { "type": "string" },
391
+ "name": { "type": "string" },
392
+ "state": { "enum": ["expanded", "pressed"] },
393
+ "controls": { "type": ["string", "null"] }
394
+ }
395
+ }
396
+ },
397
+ "forms": {
398
+ "type": "array",
399
+ "items": {
400
+ "type": "object",
401
+ "required": ["selector", "purpose", "action", "method", "fields", "submitText"],
402
+ "properties": {
403
+ "selector": { "type": "string" },
404
+ "purpose": {
405
+ "enum": [
406
+ "signup",
407
+ "login",
408
+ "search",
409
+ "checkout",
410
+ "contact",
411
+ "newsletter",
412
+ "recovery",
413
+ "other"
414
+ ]
415
+ },
416
+ "action": { "type": ["string", "null"] },
417
+ "method": { "type": "string" },
418
+ "fields": {
419
+ "type": "array",
420
+ "items": {
421
+ "type": "object",
422
+ "required": ["selector", "type", "name", "label", "required", "autocomplete"],
423
+ "properties": {
424
+ "selector": { "type": "string" },
425
+ "type": { "type": "string" },
426
+ "name": { "type": ["string", "null"] },
427
+ "label": { "type": ["string", "null"] },
428
+ "placeholder": { "type": ["string", "null"] },
429
+ "required": { "type": "boolean" },
430
+ "autocomplete": { "type": ["string", "null"] }
431
+ }
432
+ }
433
+ },
434
+ "submitText": { "type": ["string", "null"] }
435
+ }
436
+ }
437
+ },
438
+ "links": {
439
+ "type": "array",
440
+ "items": {
441
+ "type": "object",
442
+ "required": ["href", "text", "internal"],
443
+ "properties": {
444
+ "href": { "type": "string" },
445
+ "text": { "type": "string" },
446
+ "internal": { "type": "boolean" }
447
+ }
448
+ }
449
+ },
450
+ "images": {
451
+ "type": "object",
452
+ "required": ["total", "withoutAlt", "withoutDimensions"],
453
+ "properties": {
454
+ "total": { "type": "integer" },
455
+ "withoutAlt": { "type": "integer" },
456
+ "withoutDimensions": { "type": "integer" }
457
+ }
458
+ },
459
+ "trustSignals": { "type": "array", "items": { "type": "string" } },
460
+ "pricingSignals": { "type": "array", "items": { "type": "string" } },
461
+ "wordCount": { "type": "integer" },
462
+ "metaDescription": { "type": ["string", "null"] },
463
+ "hasViewportMeta": { "type": "boolean" }
464
+ }
465
+ },
466
+ "journeyStepResult": {
467
+ "type": "object",
468
+ "required": ["index", "action", "description", "status", "durationMs", "url"],
469
+ "properties": {
470
+ "index": { "type": "integer" },
471
+ "action": { "type": "string" },
472
+ "description": { "type": "string" },
473
+ "status": { "enum": ["passed", "failed", "skipped", "blocked"] },
474
+ "durationMs": { "type": "number" },
475
+ "screenshot": { "type": "string" },
476
+ "url": { "type": "string" },
477
+ "error": { "type": "string" }
478
+ }
479
+ },
480
+ "journeyResult": {
481
+ "type": "object",
482
+ "required": ["id", "name", "viewport", "status", "steps", "successCriteria", "durationMs"],
483
+ "properties": {
484
+ "id": { "type": "string" },
485
+ "name": { "type": "string" },
486
+ "viewport": { "type": "string" },
487
+ "status": { "enum": ["passed", "failed", "blocked"] },
488
+ "steps": { "type": "array", "items": { "$ref": "#/$defs/journeyStepResult" } },
489
+ "successCriteria": {
490
+ "type": "array",
491
+ "items": {
492
+ "type": "object",
493
+ "required": ["description", "met"],
494
+ "properties": {
495
+ "description": { "type": "string" },
496
+ "met": { "type": "boolean" },
497
+ "detail": { "type": "string" }
498
+ }
499
+ }
500
+ },
501
+ "durationMs": { "type": "number" },
502
+ "trace": { "type": "string" },
503
+ "blockedRequests": {
504
+ "type": "array",
505
+ "items": {
506
+ "type": "object",
507
+ "required": ["method", "url", "reason"],
508
+ "properties": {
509
+ "method": { "type": "string" },
510
+ "url": { "type": "string" },
511
+ "reason": { "type": "string" }
512
+ }
513
+ }
514
+ },
515
+ "attempts": {
516
+ "type": "array",
517
+ "items": {
518
+ "type": "object",
519
+ "required": ["status", "durationMs"],
520
+ "properties": {
521
+ "status": { "enum": ["passed", "failed", "blocked"] },
522
+ "durationMs": { "type": "number" }
523
+ }
524
+ }
525
+ },
526
+ "stability": { "enum": ["stable", "flaky"] },
527
+ "role": {
528
+ "const": "setup",
529
+ "description": "The journey ran before the audit to put the site into the audited state."
530
+ }
531
+ }
532
+ },
533
+ "manifest": {
534
+ "description": "manifest.json, written next to run.json: every artifact of the run with its size and sha256.",
535
+ "type": "object",
536
+ "required": ["schemaVersion", "runId", "files"],
537
+ "properties": {
538
+ "schemaVersion": { "const": 1 },
539
+ "runId": { "type": "string" },
540
+ "files": {
541
+ "type": "array",
542
+ "items": {
543
+ "type": "object",
544
+ "required": ["path", "bytes", "sha256"],
545
+ "properties": {
546
+ "path": { "type": "string" },
547
+ "bytes": { "type": "integer" },
548
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
549
+ }
550
+ }
551
+ }
552
+ }
553
+ }
554
+ }
555
+ }