jourilo 1.0.1 → 1.2.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.
@@ -0,0 +1,551 @@
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
+ "loadMs": { "type": "number" },
328
+ "metrics": { "type": "array", "items": { "$ref": "#/$defs/metric" } },
329
+ "consoleErrors": { "type": "integer" },
330
+ "failedRequests": { "type": "integer" },
331
+ "inventory": { "$ref": "#/$defs/inventory" }
332
+ }
333
+ },
334
+ "inventory": {
335
+ "description": "Product-facing inventory of a page. Nested ctas, forms and links are loosely described on purpose.",
336
+ "type": "object",
337
+ "required": [
338
+ "lang",
339
+ "h1",
340
+ "headings",
341
+ "landmarks",
342
+ "ctas",
343
+ "forms",
344
+ "links",
345
+ "images",
346
+ "trustSignals",
347
+ "pricingSignals",
348
+ "wordCount",
349
+ "metaDescription",
350
+ "hasViewportMeta"
351
+ ],
352
+ "properties": {
353
+ "lang": { "type": ["string", "null"] },
354
+ "h1": { "type": "array", "items": { "type": "string" } },
355
+ "headings": {
356
+ "type": "array",
357
+ "items": {
358
+ "type": "object",
359
+ "required": ["level", "text"],
360
+ "properties": { "level": { "type": "integer" }, "text": { "type": "string" } }
361
+ }
362
+ },
363
+ "landmarks": { "type": "array", "items": { "type": "string" } },
364
+ "ctas": {
365
+ "type": "array",
366
+ "items": {
367
+ "type": "object",
368
+ "required": ["text", "selector", "href", "rect", "aboveFold", "emphasis"],
369
+ "properties": {
370
+ "text": { "type": "string" },
371
+ "selector": { "type": "string" },
372
+ "href": { "type": ["string", "null"] },
373
+ "rect": { "$ref": "#/$defs/rect" },
374
+ "aboveFold": { "type": "boolean" },
375
+ "emphasis": { "enum": ["primary", "secondary", "link"] }
376
+ }
377
+ }
378
+ },
379
+ "toggles": {
380
+ "description": "Collapsed disclosures (aria-expanded=false) and unpressed toggle buttons (aria-pressed=false), at most 10 per page.",
381
+ "type": "array",
382
+ "items": {
383
+ "type": "object",
384
+ "required": ["selector", "name", "state", "controls"],
385
+ "properties": {
386
+ "selector": { "type": "string" },
387
+ "name": { "type": "string" },
388
+ "state": { "enum": ["expanded", "pressed"] },
389
+ "controls": { "type": ["string", "null"] }
390
+ }
391
+ }
392
+ },
393
+ "forms": {
394
+ "type": "array",
395
+ "items": {
396
+ "type": "object",
397
+ "required": ["selector", "purpose", "action", "method", "fields", "submitText"],
398
+ "properties": {
399
+ "selector": { "type": "string" },
400
+ "purpose": {
401
+ "enum": [
402
+ "signup",
403
+ "login",
404
+ "search",
405
+ "checkout",
406
+ "contact",
407
+ "newsletter",
408
+ "recovery",
409
+ "other"
410
+ ]
411
+ },
412
+ "action": { "type": ["string", "null"] },
413
+ "method": { "type": "string" },
414
+ "fields": {
415
+ "type": "array",
416
+ "items": {
417
+ "type": "object",
418
+ "required": ["selector", "type", "name", "label", "required", "autocomplete"],
419
+ "properties": {
420
+ "selector": { "type": "string" },
421
+ "type": { "type": "string" },
422
+ "name": { "type": ["string", "null"] },
423
+ "label": { "type": ["string", "null"] },
424
+ "placeholder": { "type": ["string", "null"] },
425
+ "required": { "type": "boolean" },
426
+ "autocomplete": { "type": ["string", "null"] }
427
+ }
428
+ }
429
+ },
430
+ "submitText": { "type": ["string", "null"] }
431
+ }
432
+ }
433
+ },
434
+ "links": {
435
+ "type": "array",
436
+ "items": {
437
+ "type": "object",
438
+ "required": ["href", "text", "internal"],
439
+ "properties": {
440
+ "href": { "type": "string" },
441
+ "text": { "type": "string" },
442
+ "internal": { "type": "boolean" }
443
+ }
444
+ }
445
+ },
446
+ "images": {
447
+ "type": "object",
448
+ "required": ["total", "withoutAlt", "withoutDimensions"],
449
+ "properties": {
450
+ "total": { "type": "integer" },
451
+ "withoutAlt": { "type": "integer" },
452
+ "withoutDimensions": { "type": "integer" }
453
+ }
454
+ },
455
+ "trustSignals": { "type": "array", "items": { "type": "string" } },
456
+ "pricingSignals": { "type": "array", "items": { "type": "string" } },
457
+ "wordCount": { "type": "integer" },
458
+ "metaDescription": { "type": ["string", "null"] },
459
+ "hasViewportMeta": { "type": "boolean" }
460
+ }
461
+ },
462
+ "journeyStepResult": {
463
+ "type": "object",
464
+ "required": ["index", "action", "description", "status", "durationMs", "url"],
465
+ "properties": {
466
+ "index": { "type": "integer" },
467
+ "action": { "type": "string" },
468
+ "description": { "type": "string" },
469
+ "status": { "enum": ["passed", "failed", "skipped", "blocked"] },
470
+ "durationMs": { "type": "number" },
471
+ "screenshot": { "type": "string" },
472
+ "url": { "type": "string" },
473
+ "error": { "type": "string" }
474
+ }
475
+ },
476
+ "journeyResult": {
477
+ "type": "object",
478
+ "required": ["id", "name", "viewport", "status", "steps", "successCriteria", "durationMs"],
479
+ "properties": {
480
+ "id": { "type": "string" },
481
+ "name": { "type": "string" },
482
+ "viewport": { "type": "string" },
483
+ "status": { "enum": ["passed", "failed", "blocked"] },
484
+ "steps": { "type": "array", "items": { "$ref": "#/$defs/journeyStepResult" } },
485
+ "successCriteria": {
486
+ "type": "array",
487
+ "items": {
488
+ "type": "object",
489
+ "required": ["description", "met"],
490
+ "properties": {
491
+ "description": { "type": "string" },
492
+ "met": { "type": "boolean" },
493
+ "detail": { "type": "string" }
494
+ }
495
+ }
496
+ },
497
+ "durationMs": { "type": "number" },
498
+ "trace": { "type": "string" },
499
+ "blockedRequests": {
500
+ "type": "array",
501
+ "items": {
502
+ "type": "object",
503
+ "required": ["method", "url", "reason"],
504
+ "properties": {
505
+ "method": { "type": "string" },
506
+ "url": { "type": "string" },
507
+ "reason": { "type": "string" }
508
+ }
509
+ }
510
+ },
511
+ "attempts": {
512
+ "type": "array",
513
+ "items": {
514
+ "type": "object",
515
+ "required": ["status", "durationMs"],
516
+ "properties": {
517
+ "status": { "enum": ["passed", "failed", "blocked"] },
518
+ "durationMs": { "type": "number" }
519
+ }
520
+ }
521
+ },
522
+ "stability": { "enum": ["stable", "flaky"] },
523
+ "role": {
524
+ "const": "setup",
525
+ "description": "The journey ran before the audit to put the site into the audited state."
526
+ }
527
+ }
528
+ },
529
+ "manifest": {
530
+ "description": "manifest.json, written next to run.json: every artifact of the run with its size and sha256.",
531
+ "type": "object",
532
+ "required": ["schemaVersion", "runId", "files"],
533
+ "properties": {
534
+ "schemaVersion": { "const": 1 },
535
+ "runId": { "type": "string" },
536
+ "files": {
537
+ "type": "array",
538
+ "items": {
539
+ "type": "object",
540
+ "required": ["path", "bytes", "sha256"],
541
+ "properties": {
542
+ "path": { "type": "string" },
543
+ "bytes": { "type": "integer" },
544
+ "sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" }
545
+ }
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ }