@agentpulselabs/cli-plugin-pulse 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +69 -32
  2. package/package.json +10 -18
  3. package/src/commands/pulse/doctor.js +14 -0
  4. package/src/commands/pulse/hub-write.js +26 -0
  5. package/src/commands/pulse/install.js +14 -0
  6. package/src/commands/pulse/login.js +20 -0
  7. package/src/commands/pulse/mirror.js +27 -0
  8. package/src/commands/pulse/pair.js +38 -0
  9. package/src/commands/pulse/restart.js +14 -0
  10. package/src/commands/pulse/start.js +6 -18
  11. package/src/commands/pulse/status.js +6 -6
  12. package/src/commands/pulse/stop.js +24 -0
  13. package/src/daemon/main.js +36 -0
  14. package/src/lib/BaseCommand.js +23 -23
  15. package/src/lib/agentSessions.js +279 -0
  16. package/src/lib/application.js +656 -0
  17. package/src/lib/backoff.js +8 -0
  18. package/src/lib/budgets.js +85 -0
  19. package/src/lib/cliDefaults.js +20 -0
  20. package/src/lib/cloudAuth.js +189 -0
  21. package/src/lib/contract.sha256 +2 -0
  22. package/src/lib/daemonComposition.js +338 -0
  23. package/src/lib/daemonLock.js +55 -0
  24. package/src/lib/daemonLoop.js +69 -0
  25. package/src/lib/daemonProcess.js +366 -0
  26. package/src/lib/daemonRuntime.js +820 -0
  27. package/src/lib/drivers.js +280 -0
  28. package/src/lib/errors.js +19 -0
  29. package/src/lib/graphWindows.js +149 -0
  30. package/src/lib/http.js +84 -0
  31. package/src/lib/hubActions.js +74 -0
  32. package/src/lib/identity.js +102 -0
  33. package/src/lib/intents.js +590 -0
  34. package/src/lib/ledger.js +535 -0
  35. package/src/lib/lifecycle.js +123 -0
  36. package/src/lib/localHub.js +217 -0
  37. package/src/lib/localHubWriter.js +69 -0
  38. package/src/lib/mirror-contract.json +4299 -0
  39. package/src/lib/mirrorContract.js +513 -0
  40. package/src/lib/mirrorDaemon.js +127 -0
  41. package/src/lib/mirrorService.js +358 -0
  42. package/src/lib/mirrorSource.js +455 -0
  43. package/src/lib/mirrorSync.js +353 -0
  44. package/src/lib/oauthLogin.js +132 -0
  45. package/src/lib/ownerLock.js +99 -0
  46. package/src/lib/pairedConfig.js +40 -0
  47. package/src/lib/pairingLifecycle.js +179 -0
  48. package/src/lib/pathRedaction.js +89 -0
  49. package/src/lib/planContract.js +141 -0
  50. package/src/lib/priorityLane.js +80 -0
  51. package/src/lib/processOwnership.js +252 -0
  52. package/src/lib/processSupervisor.js +376 -0
  53. package/src/lib/redaction.js +128 -0
  54. package/src/lib/rootPolicy.js +372 -0
  55. package/src/lib/rulePacks.js +162 -0
  56. package/src/lib/secretStore.js +169 -0
  57. package/src/lib/selfRestart.js +261 -0
  58. package/src/lib/serviceManager.js +358 -0
  59. package/src/lib/storage.js +131 -0
  60. package/src/lib/subprocess.js +45 -0
  61. package/src/lib/tokenStore.js +97 -0
  62. package/src/lib/transport.js +286 -0
  63. package/src/lib/transportContract.js +37 -0
  64. package/LICENSE +0 -21
  65. package/src/commands/pulse/gate.js +0 -25
  66. package/src/commands/pulse/next.js +0 -14
  67. package/src/commands/pulse/submit.js +0 -21
  68. package/src/commands/pulse/verify.js +0 -21
  69. package/src/runPulse.js +0 -58
@@ -0,0 +1,4299 @@
1
+ {
2
+ "contractVersion": 2,
3
+ "compatibility": [
4
+ "adding an optional field is a minor change: readers ignore fields they do not know, and the cloud counts them as ignored",
5
+ "removing or retyping a field, adding a kind or tightening a rule is a major change: contractVersion goes up and the cloud widens handshake.accepts first (cloud deploys first)",
6
+ "required fields never grow",
7
+ "scripts/sync-contract.mjs in the connector writes every copy of this file and its sha256 pin; a hand edit fails the pin tests in both repos"
8
+ ],
9
+ "handshake": {
10
+ "requestHeader": "X-Pulse-Contract",
11
+ "responseHeader": "X-Pulse-Contract-Accepts",
12
+ "format": "mirror/<version> on requests, mirror/<min>-<max> on responses; a request without the header is mirror/1",
13
+ "accepts": {
14
+ "min": 1,
15
+ "max": 2
16
+ },
17
+ "refusal": "409 contract_unsupported with { accepts } on the connector session and mirror routes when the version is outside accepts"
18
+ },
19
+ "route": {
20
+ "method": "POST",
21
+ "path": "/api/agent-hub/connector/mirror",
22
+ "scope": "agent-hub:connector:mirror",
23
+ "auth": "Bearer, with the three machine headers of connector-contract.json; an active session and the current policy version"
24
+ },
25
+ "limits": {
26
+ "bodyBytes": 2097152,
27
+ "maxItems": 500,
28
+ "maxItemBytes": 65536,
29
+ "maxRulePackBytes": 524288,
30
+ "maxDepth": 8,
31
+ "maxLiveItemsPerMachine": 50000,
32
+ "requestsPerMinute": 120,
33
+ "burst": 30
34
+ },
35
+ "request": {
36
+ "type": "object",
37
+ "additionalProperties": false,
38
+ "properties": {
39
+ "reset": {
40
+ "type": "boolean",
41
+ "description": "Tombstone every item this machine mirrored before applying items"
42
+ },
43
+ "items": {
44
+ "type": "array",
45
+ "minItems": 0,
46
+ "maxItems": 500,
47
+ "items": {
48
+ "type": "object",
49
+ "additionalProperties": false,
50
+ "required": [
51
+ "kind",
52
+ "externalId",
53
+ "updatedAt"
54
+ ],
55
+ "properties": {
56
+ "kind": {
57
+ "type": "string",
58
+ "enum": [
59
+ "delivery",
60
+ "stream",
61
+ "agent",
62
+ "edge",
63
+ "channel",
64
+ "message",
65
+ "inbox",
66
+ "project",
67
+ "rule_pack",
68
+ "brief",
69
+ "graph_window"
70
+ ]
71
+ },
72
+ "externalId": {
73
+ "type": "string",
74
+ "minLength": 1,
75
+ "maxLength": 300
76
+ },
77
+ "updatedAt": {
78
+ "type": "number",
79
+ "exclusiveMinimum": 0,
80
+ "description": "epoch ms of the source change"
81
+ },
82
+ "data": {
83
+ "type": "object",
84
+ "description": "required unless deleted; the schema of its kind"
85
+ },
86
+ "deleted": {
87
+ "type": "boolean",
88
+ "const": true,
89
+ "description": "a tombstone; carries no data"
90
+ }
91
+ }
92
+ }
93
+ }
94
+ },
95
+ "required": [
96
+ "items"
97
+ ],
98
+ "rules": [
99
+ "items may be empty only when reset is true",
100
+ "data is required and must match kinds[kind] unless deleted is true; a tombstone carries no data",
101
+ "an item whose updatedAt is older than the stored row is skipped as stale; an equal updatedAt applies only when data changed",
102
+ "items are keyed (team, machine, kind, externalId); team and machine come from the authenticated principal, never the body"
103
+ ]
104
+ },
105
+ "kinds": {
106
+ "delivery": {
107
+ "externalId": "the local delivery id",
108
+ "required": [
109
+ "id",
110
+ "title",
111
+ "status",
112
+ "step",
113
+ "lastAt"
114
+ ],
115
+ "properties": {
116
+ "id": {
117
+ "type": "string",
118
+ "maxLength": 120
119
+ },
120
+ "title": {
121
+ "type": "string",
122
+ "maxLength": 300
123
+ },
124
+ "displayTitle": {
125
+ "type": [
126
+ "string",
127
+ "null"
128
+ ],
129
+ "maxLength": 300
130
+ },
131
+ "subtitle": {
132
+ "type": [
133
+ "string",
134
+ "null"
135
+ ],
136
+ "maxLength": 1000
137
+ },
138
+ "projects": {
139
+ "type": "array",
140
+ "maxItems": 50,
141
+ "items": {
142
+ "type": "string",
143
+ "maxLength": 120
144
+ }
145
+ },
146
+ "status": {
147
+ "type": "string",
148
+ "enum": [
149
+ "needs-you",
150
+ "blocked",
151
+ "stuck",
152
+ "on-track",
153
+ "done"
154
+ ]
155
+ },
156
+ "reason": {
157
+ "type": [
158
+ "string",
159
+ "null"
160
+ ],
161
+ "maxLength": 500
162
+ },
163
+ "ask": {
164
+ "type": [
165
+ "object",
166
+ "null"
167
+ ],
168
+ "maxProperties": 16
169
+ },
170
+ "step": {
171
+ "type": [
172
+ "integer",
173
+ "null"
174
+ ],
175
+ "minimum": 0,
176
+ "maximum": 6
177
+ },
178
+ "stepName": {
179
+ "type": [
180
+ "string",
181
+ "null"
182
+ ],
183
+ "maxLength": 40
184
+ },
185
+ "stepCounts": {
186
+ "type": "array",
187
+ "maxItems": 7,
188
+ "items": {
189
+ "type": "integer",
190
+ "minimum": 0
191
+ }
192
+ },
193
+ "done": {
194
+ "type": [
195
+ "integer",
196
+ "null"
197
+ ],
198
+ "minimum": 0,
199
+ "maximum": 10000
200
+ },
201
+ "agents": {
202
+ "type": [
203
+ "integer",
204
+ "null"
205
+ ],
206
+ "minimum": 0,
207
+ "maximum": 10000
208
+ },
209
+ "active": {
210
+ "type": [
211
+ "integer",
212
+ "null"
213
+ ],
214
+ "minimum": 0,
215
+ "maximum": 10000
216
+ },
217
+ "tokens": {
218
+ "type": [
219
+ "number",
220
+ "null"
221
+ ],
222
+ "minimum": 0
223
+ },
224
+ "startedAt": {
225
+ "type": [
226
+ "number",
227
+ "null"
228
+ ],
229
+ "minimum": 0
230
+ },
231
+ "lastAt": {
232
+ "type": "number",
233
+ "minimum": 0
234
+ },
235
+ "sessionState": {
236
+ "type": [
237
+ "string",
238
+ "null"
239
+ ],
240
+ "maxLength": 40
241
+ },
242
+ "acceptedAt": {
243
+ "type": [
244
+ "number",
245
+ "null"
246
+ ],
247
+ "minimum": 0
248
+ }
249
+ }
250
+ },
251
+ "stream": {
252
+ "externalId": "the stream key, <repo>/<channel>",
253
+ "required": [
254
+ "key",
255
+ "channel",
256
+ "step",
257
+ "lastAt"
258
+ ],
259
+ "properties": {
260
+ "key": {
261
+ "type": "string",
262
+ "maxLength": 240
263
+ },
264
+ "deliveryId": {
265
+ "type": [
266
+ "string",
267
+ "null"
268
+ ],
269
+ "maxLength": 120
270
+ },
271
+ "channel": {
272
+ "type": "string",
273
+ "maxLength": 120
274
+ },
275
+ "title": {
276
+ "type": [
277
+ "string",
278
+ "null"
279
+ ],
280
+ "maxLength": 300
281
+ },
282
+ "repo": {
283
+ "type": [
284
+ "string",
285
+ "null"
286
+ ],
287
+ "maxLength": 120
288
+ },
289
+ "project": {
290
+ "type": [
291
+ "string",
292
+ "null"
293
+ ],
294
+ "maxLength": 120
295
+ },
296
+ "branch": {
297
+ "type": [
298
+ "string",
299
+ "null"
300
+ ],
301
+ "maxLength": 200
302
+ },
303
+ "isWorktree": {
304
+ "type": [
305
+ "boolean",
306
+ "null"
307
+ ]
308
+ },
309
+ "step": {
310
+ "type": [
311
+ "integer",
312
+ "null"
313
+ ],
314
+ "minimum": 0,
315
+ "maximum": 6
316
+ },
317
+ "stepName": {
318
+ "type": [
319
+ "string",
320
+ "null"
321
+ ],
322
+ "maxLength": 40
323
+ },
324
+ "round": {
325
+ "type": [
326
+ "integer",
327
+ "null"
328
+ ],
329
+ "minimum": 0,
330
+ "maximum": 10000
331
+ },
332
+ "done": {
333
+ "type": [
334
+ "boolean",
335
+ "null"
336
+ ]
337
+ },
338
+ "failed": {
339
+ "type": [
340
+ "string",
341
+ "null"
342
+ ],
343
+ "maxLength": 2000
344
+ },
345
+ "failedBy": {
346
+ "type": [
347
+ "string",
348
+ "null"
349
+ ],
350
+ "maxLength": 80
351
+ },
352
+ "blockers": {
353
+ "type": "array",
354
+ "maxItems": 20,
355
+ "items": {
356
+ "type": [
357
+ "object",
358
+ "string"
359
+ ],
360
+ "maxProperties": 8,
361
+ "maxLength": 500
362
+ }
363
+ },
364
+ "needsUser": {
365
+ "type": [
366
+ "object",
367
+ "null"
368
+ ],
369
+ "maxProperties": 8
370
+ },
371
+ "openAsks": {
372
+ "type": [
373
+ "integer",
374
+ "null"
375
+ ],
376
+ "minimum": 0,
377
+ "maximum": 1000
378
+ },
379
+ "question": {
380
+ "type": [
381
+ "string",
382
+ "object",
383
+ "null"
384
+ ],
385
+ "maxProperties": 8,
386
+ "maxLength": 2000
387
+ },
388
+ "final": {
389
+ "type": [
390
+ "object",
391
+ "null"
392
+ ],
393
+ "maxProperties": 8
394
+ },
395
+ "evidence": {
396
+ "type": [
397
+ "object",
398
+ "null"
399
+ ],
400
+ "maxProperties": 8
401
+ },
402
+ "ball": {
403
+ "type": [
404
+ "string",
405
+ "null"
406
+ ],
407
+ "maxLength": 40
408
+ },
409
+ "ballAt": {
410
+ "type": [
411
+ "number",
412
+ "null"
413
+ ],
414
+ "minimum": 0
415
+ },
416
+ "ballText": {
417
+ "type": [
418
+ "string",
419
+ "null"
420
+ ],
421
+ "maxLength": 500
422
+ },
423
+ "lastAt": {
424
+ "type": "number",
425
+ "minimum": 0
426
+ },
427
+ "lastPost": {
428
+ "type": [
429
+ "object",
430
+ "null"
431
+ ],
432
+ "maxProperties": 8
433
+ }
434
+ }
435
+ },
436
+ "agent": {
437
+ "externalId": "the local agent id",
438
+ "required": [
439
+ "id",
440
+ "role",
441
+ "status",
442
+ "lastAt"
443
+ ],
444
+ "properties": {
445
+ "id": {
446
+ "type": "string",
447
+ "maxLength": 120
448
+ },
449
+ "role": {
450
+ "type": [
451
+ "string",
452
+ "null"
453
+ ],
454
+ "maxLength": 40
455
+ },
456
+ "label": {
457
+ "type": [
458
+ "string",
459
+ "null"
460
+ ],
461
+ "maxLength": 80
462
+ },
463
+ "task": {
464
+ "type": [
465
+ "string",
466
+ "null"
467
+ ],
468
+ "maxLength": 200
469
+ },
470
+ "deliveryId": {
471
+ "type": [
472
+ "string",
473
+ "null"
474
+ ],
475
+ "maxLength": 120
476
+ },
477
+ "deliveryTitle": {
478
+ "type": [
479
+ "string",
480
+ "null"
481
+ ],
482
+ "maxLength": 300
483
+ },
484
+ "streamKey": {
485
+ "type": [
486
+ "string",
487
+ "null"
488
+ ],
489
+ "maxLength": 240
490
+ },
491
+ "channel": {
492
+ "type": [
493
+ "string",
494
+ "null"
495
+ ],
496
+ "maxLength": 120
497
+ },
498
+ "project": {
499
+ "type": [
500
+ "string",
501
+ "null"
502
+ ],
503
+ "maxLength": 120
504
+ },
505
+ "status": {
506
+ "type": "string",
507
+ "enum": [
508
+ "working",
509
+ "stuck",
510
+ "waiting",
511
+ "idle",
512
+ "done"
513
+ ]
514
+ },
515
+ "waitingOn": {
516
+ "type": [
517
+ "string",
518
+ "null"
519
+ ],
520
+ "maxLength": 80
521
+ },
522
+ "doing": {
523
+ "type": [
524
+ "object",
525
+ "null"
526
+ ],
527
+ "maxProperties": 4
528
+ },
529
+ "lastAt": {
530
+ "type": "number",
531
+ "minimum": 0
532
+ },
533
+ "startedAt": {
534
+ "type": [
535
+ "number",
536
+ "null"
537
+ ],
538
+ "minimum": 0
539
+ },
540
+ "tokensEst": {
541
+ "type": [
542
+ "number",
543
+ "null"
544
+ ],
545
+ "minimum": 0
546
+ },
547
+ "parentId": {
548
+ "type": [
549
+ "string",
550
+ "null"
551
+ ],
552
+ "maxLength": 120
553
+ },
554
+ "provider": {
555
+ "type": [
556
+ "string",
557
+ "null"
558
+ ],
559
+ "maxLength": 40
560
+ },
561
+ "model": {
562
+ "type": [
563
+ "string",
564
+ "null"
565
+ ],
566
+ "maxLength": 80
567
+ },
568
+ "persona": {
569
+ "type": [
570
+ "object",
571
+ "null"
572
+ ],
573
+ "maxProperties": 4
574
+ }
575
+ }
576
+ },
577
+ "edge": {
578
+ "externalId": "<source>><target>:<kind>",
579
+ "required": [
580
+ "source",
581
+ "target",
582
+ "kind",
583
+ "count"
584
+ ],
585
+ "properties": {
586
+ "source": {
587
+ "type": "string",
588
+ "maxLength": 120
589
+ },
590
+ "target": {
591
+ "type": "string",
592
+ "maxLength": 120
593
+ },
594
+ "kind": {
595
+ "type": "string",
596
+ "maxLength": 40
597
+ },
598
+ "count": {
599
+ "type": "integer",
600
+ "minimum": 0,
601
+ "maximum": 1000000
602
+ }
603
+ }
604
+ },
605
+ "channel": {
606
+ "externalId": "the channel id: task:<repo>/<channel>, project:<name>, dm:<agent id>, bus:<a>|<b> (two agent ids, sorted) or bus:<topic> for stream, delivery and manager topics",
607
+ "required": [
608
+ "id",
609
+ "kind"
610
+ ],
611
+ "properties": {
612
+ "id": {
613
+ "type": "string",
614
+ "maxLength": 260,
615
+ "pattern": "^(task|project|dm|bus):[^\\s]+$"
616
+ },
617
+ "kind": {
618
+ "type": "string",
619
+ "enum": [
620
+ "task",
621
+ "project",
622
+ "dm",
623
+ "bus"
624
+ ]
625
+ },
626
+ "members": {
627
+ "type": "array",
628
+ "maxItems": 20,
629
+ "items": {
630
+ "type": "string",
631
+ "maxLength": 120
632
+ }
633
+ },
634
+ "topic": {
635
+ "type": [
636
+ "string",
637
+ "null"
638
+ ],
639
+ "maxLength": 240
640
+ },
641
+ "name": {
642
+ "type": [
643
+ "string",
644
+ "null"
645
+ ],
646
+ "maxLength": 120
647
+ },
648
+ "key": {
649
+ "type": [
650
+ "string",
651
+ "null"
652
+ ],
653
+ "maxLength": 240
654
+ },
655
+ "repo": {
656
+ "type": [
657
+ "string",
658
+ "null"
659
+ ],
660
+ "maxLength": 120
661
+ },
662
+ "project": {
663
+ "type": [
664
+ "string",
665
+ "null"
666
+ ],
667
+ "maxLength": 120
668
+ },
669
+ "title": {
670
+ "type": [
671
+ "string",
672
+ "null"
673
+ ],
674
+ "maxLength": 300
675
+ },
676
+ "lastAt": {
677
+ "type": [
678
+ "number",
679
+ "null"
680
+ ],
681
+ "minimum": 0
682
+ }
683
+ }
684
+ },
685
+ "message": {
686
+ "externalId": "<channelId>#<message id>",
687
+ "required": [
688
+ "channelId",
689
+ "id",
690
+ "at",
691
+ "from",
692
+ "body"
693
+ ],
694
+ "properties": {
695
+ "channelId": {
696
+ "type": "string",
697
+ "maxLength": 260,
698
+ "pattern": "^(task|project|dm|bus):[^\\s]+$"
699
+ },
700
+ "id": {
701
+ "type": "string",
702
+ "maxLength": 120
703
+ },
704
+ "at": {
705
+ "type": "number",
706
+ "minimum": 0
707
+ },
708
+ "from": {
709
+ "type": "string",
710
+ "maxLength": 80
711
+ },
712
+ "fromName": {
713
+ "type": [
714
+ "string",
715
+ "null"
716
+ ],
717
+ "maxLength": 120
718
+ },
719
+ "type": {
720
+ "type": [
721
+ "string",
722
+ "null"
723
+ ],
724
+ "maxLength": 40
725
+ },
726
+ "head": {
727
+ "type": [
728
+ "string",
729
+ "null"
730
+ ],
731
+ "maxLength": 500
732
+ },
733
+ "body": {
734
+ "type": "string",
735
+ "maxLength": 32000
736
+ },
737
+ "replyTo": {
738
+ "type": [
739
+ "string",
740
+ "null"
741
+ ],
742
+ "maxLength": 120
743
+ },
744
+ "stream": {
745
+ "type": [
746
+ "string",
747
+ "null"
748
+ ],
749
+ "maxLength": 240
750
+ },
751
+ "fromId": {
752
+ "type": [
753
+ "string",
754
+ "null"
755
+ ],
756
+ "maxLength": 120
757
+ },
758
+ "to": {
759
+ "type": "array",
760
+ "maxItems": 20,
761
+ "items": {
762
+ "type": "string",
763
+ "maxLength": 120
764
+ }
765
+ },
766
+ "topic": {
767
+ "type": [
768
+ "string",
769
+ "null"
770
+ ],
771
+ "maxLength": 240
772
+ },
773
+ "via": {
774
+ "type": [
775
+ "string",
776
+ "null"
777
+ ],
778
+ "maxLength": 20
779
+ },
780
+ "needsAck": {
781
+ "type": [
782
+ "boolean",
783
+ "null"
784
+ ]
785
+ },
786
+ "ackState": {
787
+ "type": [
788
+ "string",
789
+ "null"
790
+ ],
791
+ "enum": [
792
+ "queued",
793
+ "delivered",
794
+ "acked",
795
+ "unacked",
796
+ "expired",
797
+ null
798
+ ]
799
+ }
800
+ }
801
+ },
802
+ "inbox": {
803
+ "externalId": "the local inbox message id",
804
+ "required": [
805
+ "id",
806
+ "at",
807
+ "from",
808
+ "body"
809
+ ],
810
+ "properties": {
811
+ "id": {
812
+ "type": "string",
813
+ "maxLength": 120
814
+ },
815
+ "at": {
816
+ "type": "number",
817
+ "minimum": 0
818
+ },
819
+ "from": {
820
+ "type": "string",
821
+ "maxLength": 80
822
+ },
823
+ "fromName": {
824
+ "type": [
825
+ "string",
826
+ "null"
827
+ ],
828
+ "maxLength": 120
829
+ },
830
+ "type": {
831
+ "type": [
832
+ "string",
833
+ "null"
834
+ ],
835
+ "maxLength": 40
836
+ },
837
+ "body": {
838
+ "type": "string",
839
+ "maxLength": 2000
840
+ },
841
+ "replyTo": {
842
+ "type": [
843
+ "string",
844
+ "null"
845
+ ],
846
+ "maxLength": 120
847
+ }
848
+ }
849
+ },
850
+ "project": {
851
+ "externalId": "the project display name",
852
+ "required": [
853
+ "name"
854
+ ],
855
+ "properties": {
856
+ "name": {
857
+ "type": "string",
858
+ "maxLength": 120
859
+ },
860
+ "remote": {
861
+ "type": [
862
+ "string",
863
+ "null"
864
+ ],
865
+ "maxLength": 200
866
+ },
867
+ "repos": {
868
+ "type": "array",
869
+ "maxItems": 50,
870
+ "items": {
871
+ "type": "string",
872
+ "maxLength": 120
873
+ }
874
+ },
875
+ "lastAt": {
876
+ "type": [
877
+ "number",
878
+ "null"
879
+ ],
880
+ "minimum": 0
881
+ }
882
+ }
883
+ },
884
+ "rule_pack": {
885
+ "externalId": "workspace, user or repo:<repo display name>",
886
+ "required": [
887
+ "id",
888
+ "name",
889
+ "source",
890
+ "rules"
891
+ ],
892
+ "properties": {
893
+ "id": {
894
+ "type": "string",
895
+ "maxLength": 160
896
+ },
897
+ "name": {
898
+ "type": "string",
899
+ "maxLength": 160
900
+ },
901
+ "source": {
902
+ "type": "string",
903
+ "enum": [
904
+ "workspace",
905
+ "repo",
906
+ "user"
907
+ ]
908
+ },
909
+ "repo": {
910
+ "type": [
911
+ "string",
912
+ "null"
913
+ ],
914
+ "maxLength": 120
915
+ },
916
+ "rules": {
917
+ "type": "array",
918
+ "maxItems": 100,
919
+ "items": {
920
+ "type": "object",
921
+ "additionalProperties": false,
922
+ "required": [
923
+ "name",
924
+ "file",
925
+ "body"
926
+ ],
927
+ "properties": {
928
+ "name": {
929
+ "type": "string",
930
+ "maxLength": 160
931
+ },
932
+ "file": {
933
+ "type": "string",
934
+ "maxLength": 240
935
+ },
936
+ "description": {
937
+ "type": [
938
+ "string",
939
+ "null"
940
+ ],
941
+ "maxLength": 1000
942
+ },
943
+ "alwaysApply": {
944
+ "type": [
945
+ "boolean",
946
+ "null"
947
+ ]
948
+ },
949
+ "globs": {
950
+ "type": "array",
951
+ "maxItems": 50,
952
+ "items": {
953
+ "type": "string",
954
+ "maxLength": 240
955
+ }
956
+ },
957
+ "body": {
958
+ "type": "string",
959
+ "maxLength": 65536
960
+ }
961
+ }
962
+ }
963
+ }
964
+ }
965
+ },
966
+ "brief": {
967
+ "externalId": "the task key, <repo>/<task>",
968
+ "required": [
969
+ "key",
970
+ "sections"
971
+ ],
972
+ "rules": [
973
+ "the local /api/task/brief body for one task key; a task with no brief has no item",
974
+ "read only by the user who paired the machine: briefs come from prompts",
975
+ "truncated is true when a heading, a body or the section list was cut to fit these limits"
976
+ ],
977
+ "properties": {
978
+ "key": {
979
+ "type": "string",
980
+ "maxLength": 240
981
+ },
982
+ "source": {
983
+ "type": [
984
+ "string",
985
+ "null"
986
+ ],
987
+ "maxLength": 40
988
+ },
989
+ "title": {
990
+ "type": [
991
+ "string",
992
+ "null"
993
+ ],
994
+ "maxLength": 300
995
+ },
996
+ "sections": {
997
+ "type": "array",
998
+ "maxItems": 24,
999
+ "items": {
1000
+ "type": "object",
1001
+ "additionalProperties": false,
1002
+ "properties": {
1003
+ "heading": {
1004
+ "type": "string",
1005
+ "maxLength": 200
1006
+ },
1007
+ "body": {
1008
+ "type": "string",
1009
+ "maxLength": 12000
1010
+ }
1011
+ }
1012
+ }
1013
+ },
1014
+ "truncated": {
1015
+ "type": [
1016
+ "boolean",
1017
+ "null"
1018
+ ]
1019
+ }
1020
+ }
1021
+ },
1022
+ "graph_window": {
1023
+ "externalId": "meta/<hours>h for a window, or <section>/<row key>@<hours>h for one row, named after the largest window holding it",
1024
+ "required": [
1025
+ "section"
1026
+ ],
1027
+ "rules": [
1028
+ "one row per item, listing the windows whose projection has exactly this row; a row that differs between windows has one item per variant",
1029
+ "one meta item per window carries totals, manager, its row count per section and the rows it dropped per section",
1030
+ "only changed rows are uploaded; a row in no window is tombstoned, so nothing older than the 168 h window is kept",
1031
+ "rows come back in the local order: deliveries and streams newest first, agents and requests by id, events oldest first"
1032
+ ],
1033
+ "properties": {
1034
+ "section": {
1035
+ "type": "string",
1036
+ "enum": [
1037
+ "meta",
1038
+ "deliveries",
1039
+ "streams",
1040
+ "agents",
1041
+ "nodes",
1042
+ "links",
1043
+ "events",
1044
+ "requests"
1045
+ ]
1046
+ },
1047
+ "hours": {
1048
+ "type": [
1049
+ "integer",
1050
+ "null"
1051
+ ],
1052
+ "enum": [
1053
+ 6,
1054
+ 24,
1055
+ 72,
1056
+ 168,
1057
+ null
1058
+ ]
1059
+ },
1060
+ "windows": {
1061
+ "type": "array",
1062
+ "maxItems": 4,
1063
+ "items": {
1064
+ "type": "integer",
1065
+ "enum": [
1066
+ 6,
1067
+ 24,
1068
+ 72,
1069
+ 168
1070
+ ]
1071
+ }
1072
+ },
1073
+ "totals": {
1074
+ "type": [
1075
+ "object",
1076
+ "null"
1077
+ ],
1078
+ "additionalProperties": false,
1079
+ "properties": {
1080
+ "sessions": {
1081
+ "type": [
1082
+ "integer",
1083
+ "null"
1084
+ ],
1085
+ "minimum": 0,
1086
+ "maximum": 1000000
1087
+ },
1088
+ "agents": {
1089
+ "type": [
1090
+ "integer",
1091
+ "null"
1092
+ ],
1093
+ "minimum": 0,
1094
+ "maximum": 1000000
1095
+ },
1096
+ "active": {
1097
+ "type": [
1098
+ "integer",
1099
+ "null"
1100
+ ],
1101
+ "minimum": 0,
1102
+ "maximum": 1000000
1103
+ },
1104
+ "messages": {
1105
+ "type": [
1106
+ "integer",
1107
+ "null"
1108
+ ],
1109
+ "minimum": 0,
1110
+ "maximum": 1000000000
1111
+ },
1112
+ "tokensEst": {
1113
+ "type": [
1114
+ "number",
1115
+ "null"
1116
+ ],
1117
+ "minimum": 0
1118
+ },
1119
+ "requests": {
1120
+ "type": [
1121
+ "integer",
1122
+ "null"
1123
+ ],
1124
+ "minimum": 0,
1125
+ "maximum": 1000000
1126
+ }
1127
+ }
1128
+ },
1129
+ "manager": {
1130
+ "type": [
1131
+ "object",
1132
+ "null"
1133
+ ],
1134
+ "additionalProperties": false,
1135
+ "properties": {
1136
+ "state": {
1137
+ "type": [
1138
+ "string",
1139
+ "null"
1140
+ ],
1141
+ "maxLength": 40
1142
+ },
1143
+ "error": {
1144
+ "type": [
1145
+ "string",
1146
+ "null"
1147
+ ],
1148
+ "maxLength": 500
1149
+ },
1150
+ "at": {
1151
+ "type": [
1152
+ "number",
1153
+ "null"
1154
+ ],
1155
+ "minimum": 0
1156
+ },
1157
+ "from": {
1158
+ "type": [
1159
+ "string",
1160
+ "null"
1161
+ ],
1162
+ "maxLength": 120
1163
+ },
1164
+ "lastReplyAt": {
1165
+ "type": [
1166
+ "number",
1167
+ "null"
1168
+ ],
1169
+ "minimum": 0
1170
+ },
1171
+ "lastReply": {
1172
+ "type": [
1173
+ "string",
1174
+ "null"
1175
+ ],
1176
+ "maxLength": 2000
1177
+ },
1178
+ "persona": {
1179
+ "type": [
1180
+ "object",
1181
+ "null"
1182
+ ],
1183
+ "additionalProperties": false,
1184
+ "properties": {
1185
+ "name": {
1186
+ "type": [
1187
+ "string",
1188
+ "null"
1189
+ ],
1190
+ "maxLength": 120
1191
+ },
1192
+ "first": {
1193
+ "type": [
1194
+ "string",
1195
+ "null"
1196
+ ],
1197
+ "maxLength": 80
1198
+ },
1199
+ "last": {
1200
+ "type": [
1201
+ "string",
1202
+ "null"
1203
+ ],
1204
+ "maxLength": 80
1205
+ },
1206
+ "username": {
1207
+ "type": [
1208
+ "string",
1209
+ "null"
1210
+ ],
1211
+ "maxLength": 120
1212
+ },
1213
+ "seed": {
1214
+ "type": [
1215
+ "number",
1216
+ "null"
1217
+ ],
1218
+ "minimum": 0
1219
+ },
1220
+ "role": {
1221
+ "type": [
1222
+ "string",
1223
+ "null"
1224
+ ],
1225
+ "maxLength": 40
1226
+ },
1227
+ "personality": {
1228
+ "type": [
1229
+ "object",
1230
+ "null"
1231
+ ],
1232
+ "additionalProperties": false,
1233
+ "properties": {
1234
+ "temperament": {
1235
+ "type": [
1236
+ "string",
1237
+ "null"
1238
+ ],
1239
+ "maxLength": 200
1240
+ },
1241
+ "voice": {
1242
+ "type": [
1243
+ "string",
1244
+ "null"
1245
+ ],
1246
+ "maxLength": 200
1247
+ },
1248
+ "emoji": {
1249
+ "type": "array",
1250
+ "maxItems": 8,
1251
+ "items": {
1252
+ "type": "string",
1253
+ "maxLength": 16
1254
+ }
1255
+ },
1256
+ "habit": {
1257
+ "type": [
1258
+ "string",
1259
+ "null"
1260
+ ],
1261
+ "maxLength": 200
1262
+ }
1263
+ }
1264
+ }
1265
+ }
1266
+ },
1267
+ "online": {
1268
+ "type": [
1269
+ "boolean",
1270
+ "null"
1271
+ ]
1272
+ },
1273
+ "pending": {
1274
+ "type": [
1275
+ "integer",
1276
+ "null"
1277
+ ],
1278
+ "minimum": 0,
1279
+ "maximum": 100000
1280
+ }
1281
+ }
1282
+ },
1283
+ "counts": {
1284
+ "type": [
1285
+ "object",
1286
+ "null"
1287
+ ],
1288
+ "additionalProperties": false,
1289
+ "properties": {
1290
+ "deliveries": {
1291
+ "type": [
1292
+ "integer",
1293
+ "null"
1294
+ ],
1295
+ "minimum": 0,
1296
+ "maximum": 1000000
1297
+ },
1298
+ "streams": {
1299
+ "type": [
1300
+ "integer",
1301
+ "null"
1302
+ ],
1303
+ "minimum": 0,
1304
+ "maximum": 1000000
1305
+ },
1306
+ "agents": {
1307
+ "type": [
1308
+ "integer",
1309
+ "null"
1310
+ ],
1311
+ "minimum": 0,
1312
+ "maximum": 1000000
1313
+ },
1314
+ "nodes": {
1315
+ "type": [
1316
+ "integer",
1317
+ "null"
1318
+ ],
1319
+ "minimum": 0,
1320
+ "maximum": 1000000
1321
+ },
1322
+ "links": {
1323
+ "type": [
1324
+ "integer",
1325
+ "null"
1326
+ ],
1327
+ "minimum": 0,
1328
+ "maximum": 1000000
1329
+ },
1330
+ "events": {
1331
+ "type": [
1332
+ "integer",
1333
+ "null"
1334
+ ],
1335
+ "minimum": 0,
1336
+ "maximum": 1000000
1337
+ },
1338
+ "requests": {
1339
+ "type": [
1340
+ "integer",
1341
+ "null"
1342
+ ],
1343
+ "minimum": 0,
1344
+ "maximum": 1000000
1345
+ }
1346
+ }
1347
+ },
1348
+ "dropped": {
1349
+ "type": [
1350
+ "object",
1351
+ "null"
1352
+ ],
1353
+ "additionalProperties": false,
1354
+ "properties": {
1355
+ "deliveries": {
1356
+ "type": [
1357
+ "integer",
1358
+ "null"
1359
+ ],
1360
+ "minimum": 0,
1361
+ "maximum": 1000000
1362
+ },
1363
+ "streams": {
1364
+ "type": [
1365
+ "integer",
1366
+ "null"
1367
+ ],
1368
+ "minimum": 0,
1369
+ "maximum": 1000000
1370
+ },
1371
+ "agents": {
1372
+ "type": [
1373
+ "integer",
1374
+ "null"
1375
+ ],
1376
+ "minimum": 0,
1377
+ "maximum": 1000000
1378
+ },
1379
+ "nodes": {
1380
+ "type": [
1381
+ "integer",
1382
+ "null"
1383
+ ],
1384
+ "minimum": 0,
1385
+ "maximum": 1000000
1386
+ },
1387
+ "links": {
1388
+ "type": [
1389
+ "integer",
1390
+ "null"
1391
+ ],
1392
+ "minimum": 0,
1393
+ "maximum": 1000000
1394
+ },
1395
+ "events": {
1396
+ "type": [
1397
+ "integer",
1398
+ "null"
1399
+ ],
1400
+ "minimum": 0,
1401
+ "maximum": 1000000
1402
+ },
1403
+ "requests": {
1404
+ "type": [
1405
+ "integer",
1406
+ "null"
1407
+ ],
1408
+ "minimum": 0,
1409
+ "maximum": 1000000
1410
+ }
1411
+ }
1412
+ },
1413
+ "deliveries": {
1414
+ "type": [
1415
+ "object",
1416
+ "null"
1417
+ ],
1418
+ "additionalProperties": false,
1419
+ "properties": {
1420
+ "id": {
1421
+ "type": "string",
1422
+ "maxLength": 120
1423
+ },
1424
+ "key": {
1425
+ "type": [
1426
+ "string",
1427
+ "null"
1428
+ ],
1429
+ "maxLength": 120
1430
+ },
1431
+ "title": {
1432
+ "type": [
1433
+ "string",
1434
+ "null"
1435
+ ],
1436
+ "maxLength": 300
1437
+ },
1438
+ "name": {
1439
+ "type": [
1440
+ "string",
1441
+ "null"
1442
+ ],
1443
+ "maxLength": 300
1444
+ },
1445
+ "displayTitle": {
1446
+ "type": [
1447
+ "string",
1448
+ "null"
1449
+ ],
1450
+ "maxLength": 300
1451
+ },
1452
+ "subtitle": {
1453
+ "type": [
1454
+ "string",
1455
+ "null"
1456
+ ],
1457
+ "maxLength": 1000
1458
+ },
1459
+ "projects": {
1460
+ "type": "array",
1461
+ "maxItems": 50,
1462
+ "items": {
1463
+ "type": "string",
1464
+ "maxLength": 120
1465
+ }
1466
+ },
1467
+ "step": {
1468
+ "type": [
1469
+ "integer",
1470
+ "null"
1471
+ ],
1472
+ "minimum": 0,
1473
+ "maximum": 6
1474
+ },
1475
+ "stepName": {
1476
+ "type": [
1477
+ "string",
1478
+ "null"
1479
+ ],
1480
+ "maxLength": 40
1481
+ },
1482
+ "stepCounts": {
1483
+ "type": "array",
1484
+ "maxItems": 7,
1485
+ "items": {
1486
+ "type": "integer",
1487
+ "minimum": 0
1488
+ }
1489
+ },
1490
+ "done": {
1491
+ "type": [
1492
+ "integer",
1493
+ "null"
1494
+ ],
1495
+ "minimum": 0,
1496
+ "maximum": 10000
1497
+ },
1498
+ "status": {
1499
+ "type": "string",
1500
+ "enum": [
1501
+ "needs-you",
1502
+ "blocked",
1503
+ "stuck",
1504
+ "on-track",
1505
+ "done"
1506
+ ]
1507
+ },
1508
+ "reason": {
1509
+ "type": [
1510
+ "string",
1511
+ "null"
1512
+ ],
1513
+ "maxLength": 500
1514
+ },
1515
+ "ask": {
1516
+ "type": [
1517
+ "object",
1518
+ "null"
1519
+ ],
1520
+ "additionalProperties": false,
1521
+ "properties": {
1522
+ "kind": {
1523
+ "type": [
1524
+ "string",
1525
+ "null"
1526
+ ],
1527
+ "maxLength": 20
1528
+ },
1529
+ "label": {
1530
+ "type": [
1531
+ "string",
1532
+ "null"
1533
+ ],
1534
+ "maxLength": 80
1535
+ },
1536
+ "decide": {
1537
+ "type": [
1538
+ "string",
1539
+ "null"
1540
+ ],
1541
+ "maxLength": 2000
1542
+ },
1543
+ "full": {
1544
+ "type": [
1545
+ "string",
1546
+ "null"
1547
+ ],
1548
+ "maxLength": 4000
1549
+ },
1550
+ "options": {
1551
+ "type": "array",
1552
+ "maxItems": 20,
1553
+ "items": {
1554
+ "type": "string",
1555
+ "maxLength": 300
1556
+ }
1557
+ },
1558
+ "more": {
1559
+ "type": [
1560
+ "integer",
1561
+ "null"
1562
+ ],
1563
+ "minimum": 0,
1564
+ "maximum": 1000
1565
+ },
1566
+ "then": {
1567
+ "type": [
1568
+ "string",
1569
+ "null"
1570
+ ],
1571
+ "maxLength": 500
1572
+ },
1573
+ "stream": {
1574
+ "type": [
1575
+ "string",
1576
+ "null"
1577
+ ],
1578
+ "maxLength": 120
1579
+ },
1580
+ "key": {
1581
+ "type": [
1582
+ "string",
1583
+ "null"
1584
+ ],
1585
+ "maxLength": 240
1586
+ },
1587
+ "ref": {
1588
+ "type": [
1589
+ "string",
1590
+ "null"
1591
+ ],
1592
+ "maxLength": 120
1593
+ },
1594
+ "at": {
1595
+ "type": [
1596
+ "number",
1597
+ "null"
1598
+ ],
1599
+ "minimum": 0
1600
+ },
1601
+ "proof": {
1602
+ "type": "array",
1603
+ "maxItems": 12,
1604
+ "items": {
1605
+ "type": "string",
1606
+ "maxLength": 500
1607
+ }
1608
+ }
1609
+ }
1610
+ },
1611
+ "agents": {
1612
+ "type": [
1613
+ "integer",
1614
+ "null"
1615
+ ],
1616
+ "minimum": 0,
1617
+ "maximum": 100000
1618
+ },
1619
+ "active": {
1620
+ "type": [
1621
+ "integer",
1622
+ "null"
1623
+ ],
1624
+ "minimum": 0,
1625
+ "maximum": 100000
1626
+ },
1627
+ "tokens": {
1628
+ "type": [
1629
+ "number",
1630
+ "null"
1631
+ ],
1632
+ "minimum": 0
1633
+ },
1634
+ "startedAt": {
1635
+ "type": [
1636
+ "number",
1637
+ "null"
1638
+ ],
1639
+ "minimum": 0
1640
+ },
1641
+ "lastAt": {
1642
+ "type": [
1643
+ "number",
1644
+ "null"
1645
+ ],
1646
+ "minimum": 0
1647
+ },
1648
+ "sessionState": {
1649
+ "type": [
1650
+ "string",
1651
+ "null"
1652
+ ],
1653
+ "maxLength": 40
1654
+ },
1655
+ "acceptedAt": {
1656
+ "type": [
1657
+ "number",
1658
+ "null"
1659
+ ],
1660
+ "minimum": 0
1661
+ },
1662
+ "override": {
1663
+ "type": [
1664
+ "object",
1665
+ "null"
1666
+ ],
1667
+ "additionalProperties": false,
1668
+ "properties": {
1669
+ "status": {
1670
+ "type": "string",
1671
+ "enum": [
1672
+ "done",
1673
+ "blocked",
1674
+ "stopped",
1675
+ "handed-over",
1676
+ "working"
1677
+ ]
1678
+ },
1679
+ "reason": {
1680
+ "type": [
1681
+ "string",
1682
+ "null"
1683
+ ],
1684
+ "maxLength": 500
1685
+ },
1686
+ "to": {
1687
+ "type": [
1688
+ "string",
1689
+ "null"
1690
+ ],
1691
+ "maxLength": 120
1692
+ },
1693
+ "by": {
1694
+ "type": [
1695
+ "string",
1696
+ "null"
1697
+ ],
1698
+ "maxLength": 120
1699
+ },
1700
+ "at": {
1701
+ "type": [
1702
+ "number",
1703
+ "null"
1704
+ ],
1705
+ "minimum": 0
1706
+ }
1707
+ }
1708
+ }
1709
+ }
1710
+ },
1711
+ "streams": {
1712
+ "type": [
1713
+ "object",
1714
+ "null"
1715
+ ],
1716
+ "additionalProperties": false,
1717
+ "properties": {
1718
+ "deliveryId": {
1719
+ "type": "string",
1720
+ "maxLength": 120
1721
+ },
1722
+ "key": {
1723
+ "type": "string",
1724
+ "maxLength": 240
1725
+ },
1726
+ "channel": {
1727
+ "type": [
1728
+ "string",
1729
+ "null"
1730
+ ],
1731
+ "maxLength": 120
1732
+ },
1733
+ "title": {
1734
+ "type": [
1735
+ "string",
1736
+ "null"
1737
+ ],
1738
+ "maxLength": 300
1739
+ },
1740
+ "repo": {
1741
+ "type": [
1742
+ "string",
1743
+ "null"
1744
+ ],
1745
+ "maxLength": 120
1746
+ },
1747
+ "project": {
1748
+ "type": [
1749
+ "string",
1750
+ "null"
1751
+ ],
1752
+ "maxLength": 120
1753
+ },
1754
+ "git": {
1755
+ "type": [
1756
+ "object",
1757
+ "null"
1758
+ ],
1759
+ "additionalProperties": false,
1760
+ "properties": {
1761
+ "branch": {
1762
+ "type": [
1763
+ "string",
1764
+ "null"
1765
+ ],
1766
+ "maxLength": 200
1767
+ },
1768
+ "isWorktree": {
1769
+ "type": [
1770
+ "boolean",
1771
+ "null"
1772
+ ]
1773
+ },
1774
+ "exists": {
1775
+ "type": [
1776
+ "boolean",
1777
+ "null"
1778
+ ]
1779
+ },
1780
+ "here": {
1781
+ "type": [
1782
+ "boolean",
1783
+ "null"
1784
+ ]
1785
+ },
1786
+ "channelBranch": {
1787
+ "type": [
1788
+ "string",
1789
+ "null"
1790
+ ],
1791
+ "maxLength": 200
1792
+ }
1793
+ }
1794
+ },
1795
+ "step": {
1796
+ "type": [
1797
+ "integer",
1798
+ "null"
1799
+ ],
1800
+ "minimum": 0,
1801
+ "maximum": 6
1802
+ },
1803
+ "stepName": {
1804
+ "type": [
1805
+ "string",
1806
+ "null"
1807
+ ],
1808
+ "maxLength": 40
1809
+ },
1810
+ "round": {
1811
+ "type": [
1812
+ "integer",
1813
+ "null"
1814
+ ],
1815
+ "minimum": 0,
1816
+ "maximum": 10000
1817
+ },
1818
+ "done": {
1819
+ "type": [
1820
+ "boolean",
1821
+ "null"
1822
+ ]
1823
+ },
1824
+ "failed": {
1825
+ "type": [
1826
+ "string",
1827
+ "null"
1828
+ ],
1829
+ "maxLength": 2000
1830
+ },
1831
+ "failedBy": {
1832
+ "type": [
1833
+ "string",
1834
+ "null"
1835
+ ],
1836
+ "maxLength": 80
1837
+ },
1838
+ "blockers": {
1839
+ "type": "array",
1840
+ "maxItems": 20,
1841
+ "items": {
1842
+ "type": "object",
1843
+ "additionalProperties": false,
1844
+ "properties": {
1845
+ "id": {
1846
+ "type": [
1847
+ "string",
1848
+ "integer",
1849
+ "null"
1850
+ ],
1851
+ "maxLength": 40
1852
+ },
1853
+ "role": {
1854
+ "type": [
1855
+ "string",
1856
+ "null"
1857
+ ],
1858
+ "maxLength": 40
1859
+ },
1860
+ "at": {
1861
+ "type": [
1862
+ "number",
1863
+ "null"
1864
+ ],
1865
+ "minimum": 0
1866
+ },
1867
+ "text": {
1868
+ "type": [
1869
+ "string",
1870
+ "null"
1871
+ ],
1872
+ "maxLength": 500
1873
+ }
1874
+ }
1875
+ }
1876
+ },
1877
+ "needsUser": {
1878
+ "type": [
1879
+ "object",
1880
+ "null"
1881
+ ],
1882
+ "additionalProperties": false,
1883
+ "properties": {
1884
+ "at": {
1885
+ "type": [
1886
+ "number",
1887
+ "null"
1888
+ ],
1889
+ "minimum": 0
1890
+ },
1891
+ "text": {
1892
+ "type": [
1893
+ "string",
1894
+ "null"
1895
+ ],
1896
+ "maxLength": 4000
1897
+ },
1898
+ "ref": {
1899
+ "type": [
1900
+ "string",
1901
+ "null"
1902
+ ],
1903
+ "maxLength": 120
1904
+ }
1905
+ }
1906
+ },
1907
+ "openAsks": {
1908
+ "type": [
1909
+ "integer",
1910
+ "null"
1911
+ ],
1912
+ "minimum": 0,
1913
+ "maximum": 1000
1914
+ },
1915
+ "question": {
1916
+ "type": [
1917
+ "object",
1918
+ "null"
1919
+ ],
1920
+ "additionalProperties": false,
1921
+ "properties": {
1922
+ "at": {
1923
+ "type": [
1924
+ "number",
1925
+ "null"
1926
+ ],
1927
+ "minimum": 0
1928
+ },
1929
+ "text": {
1930
+ "type": [
1931
+ "string",
1932
+ "null"
1933
+ ],
1934
+ "maxLength": 500
1935
+ }
1936
+ }
1937
+ },
1938
+ "final": {
1939
+ "type": [
1940
+ "object",
1941
+ "null"
1942
+ ],
1943
+ "additionalProperties": false,
1944
+ "properties": {
1945
+ "at": {
1946
+ "type": [
1947
+ "number",
1948
+ "null"
1949
+ ],
1950
+ "minimum": 0
1951
+ },
1952
+ "text": {
1953
+ "type": [
1954
+ "string",
1955
+ "null"
1956
+ ],
1957
+ "maxLength": 500
1958
+ }
1959
+ }
1960
+ },
1961
+ "evidence": {
1962
+ "type": [
1963
+ "object",
1964
+ "null"
1965
+ ],
1966
+ "additionalProperties": false,
1967
+ "properties": {
1968
+ "at": {
1969
+ "type": [
1970
+ "number",
1971
+ "null"
1972
+ ],
1973
+ "minimum": 0
1974
+ },
1975
+ "text": {
1976
+ "type": [
1977
+ "string",
1978
+ "null"
1979
+ ],
1980
+ "maxLength": 500
1981
+ }
1982
+ }
1983
+ },
1984
+ "ball": {
1985
+ "type": [
1986
+ "string",
1987
+ "null"
1988
+ ],
1989
+ "maxLength": 40
1990
+ },
1991
+ "ballAt": {
1992
+ "type": [
1993
+ "number",
1994
+ "null"
1995
+ ],
1996
+ "minimum": 0
1997
+ },
1998
+ "ballText": {
1999
+ "type": [
2000
+ "string",
2001
+ "null"
2002
+ ],
2003
+ "maxLength": 500
2004
+ },
2005
+ "lastAt": {
2006
+ "type": [
2007
+ "number",
2008
+ "null"
2009
+ ],
2010
+ "minimum": 0
2011
+ },
2012
+ "lastPost": {
2013
+ "type": [
2014
+ "object",
2015
+ "null"
2016
+ ],
2017
+ "additionalProperties": false,
2018
+ "properties": {
2019
+ "role": {
2020
+ "type": [
2021
+ "string",
2022
+ "null"
2023
+ ],
2024
+ "maxLength": 40
2025
+ },
2026
+ "type": {
2027
+ "type": [
2028
+ "string",
2029
+ "null"
2030
+ ],
2031
+ "maxLength": 40
2032
+ },
2033
+ "text": {
2034
+ "type": [
2035
+ "string",
2036
+ "null"
2037
+ ],
2038
+ "maxLength": 500
2039
+ },
2040
+ "at": {
2041
+ "type": [
2042
+ "number",
2043
+ "null"
2044
+ ],
2045
+ "minimum": 0
2046
+ }
2047
+ }
2048
+ },
2049
+ "override": {
2050
+ "type": [
2051
+ "object",
2052
+ "null"
2053
+ ],
2054
+ "additionalProperties": false,
2055
+ "properties": {
2056
+ "step": {
2057
+ "type": "string",
2058
+ "enum": [
2059
+ "research",
2060
+ "design",
2061
+ "mockup",
2062
+ "build",
2063
+ "review",
2064
+ "checks",
2065
+ "proof"
2066
+ ]
2067
+ },
2068
+ "by": {
2069
+ "type": [
2070
+ "string",
2071
+ "null"
2072
+ ],
2073
+ "maxLength": 120
2074
+ },
2075
+ "at": {
2076
+ "type": [
2077
+ "number",
2078
+ "null"
2079
+ ],
2080
+ "minimum": 0
2081
+ }
2082
+ }
2083
+ }
2084
+ }
2085
+ },
2086
+ "agents": {
2087
+ "type": [
2088
+ "object",
2089
+ "null"
2090
+ ],
2091
+ "additionalProperties": false,
2092
+ "properties": {
2093
+ "id": {
2094
+ "type": "string",
2095
+ "maxLength": 120
2096
+ },
2097
+ "key": {
2098
+ "type": [
2099
+ "string",
2100
+ "null"
2101
+ ],
2102
+ "maxLength": 120
2103
+ },
2104
+ "role": {
2105
+ "type": [
2106
+ "string",
2107
+ "null"
2108
+ ],
2109
+ "maxLength": 40
2110
+ },
2111
+ "label": {
2112
+ "type": [
2113
+ "string",
2114
+ "null"
2115
+ ],
2116
+ "maxLength": 120
2117
+ },
2118
+ "isArchitect": {
2119
+ "type": [
2120
+ "boolean",
2121
+ "null"
2122
+ ]
2123
+ },
2124
+ "task": {
2125
+ "type": [
2126
+ "string",
2127
+ "null"
2128
+ ],
2129
+ "maxLength": 300
2130
+ },
2131
+ "code": {
2132
+ "type": [
2133
+ "string",
2134
+ "null"
2135
+ ],
2136
+ "maxLength": 120
2137
+ },
2138
+ "deliveryId": {
2139
+ "type": [
2140
+ "string",
2141
+ "null"
2142
+ ],
2143
+ "maxLength": 120
2144
+ },
2145
+ "deliveryTitle": {
2146
+ "type": [
2147
+ "string",
2148
+ "null"
2149
+ ],
2150
+ "maxLength": 300
2151
+ },
2152
+ "streamKey": {
2153
+ "type": [
2154
+ "string",
2155
+ "null"
2156
+ ],
2157
+ "maxLength": 240
2158
+ },
2159
+ "channel": {
2160
+ "type": [
2161
+ "string",
2162
+ "null"
2163
+ ],
2164
+ "maxLength": 120
2165
+ },
2166
+ "project": {
2167
+ "type": [
2168
+ "string",
2169
+ "null"
2170
+ ],
2171
+ "maxLength": 120
2172
+ },
2173
+ "status": {
2174
+ "type": [
2175
+ "string",
2176
+ "null"
2177
+ ],
2178
+ "maxLength": 20
2179
+ },
2180
+ "waitingOn": {
2181
+ "type": [
2182
+ "string",
2183
+ "null"
2184
+ ],
2185
+ "maxLength": 120
2186
+ },
2187
+ "doing": {
2188
+ "type": [
2189
+ "object",
2190
+ "null"
2191
+ ],
2192
+ "additionalProperties": false,
2193
+ "properties": {
2194
+ "type": {
2195
+ "type": [
2196
+ "string",
2197
+ "null"
2198
+ ],
2199
+ "maxLength": 40
2200
+ },
2201
+ "text": {
2202
+ "type": [
2203
+ "string",
2204
+ "null"
2205
+ ],
2206
+ "maxLength": 500
2207
+ },
2208
+ "at": {
2209
+ "type": [
2210
+ "number",
2211
+ "null"
2212
+ ],
2213
+ "minimum": 0
2214
+ }
2215
+ }
2216
+ },
2217
+ "lastAt": {
2218
+ "type": [
2219
+ "number",
2220
+ "null"
2221
+ ],
2222
+ "minimum": 0
2223
+ },
2224
+ "startedAt": {
2225
+ "type": [
2226
+ "number",
2227
+ "null"
2228
+ ],
2229
+ "minimum": 0
2230
+ },
2231
+ "tokensEst": {
2232
+ "type": [
2233
+ "number",
2234
+ "null"
2235
+ ],
2236
+ "minimum": 0
2237
+ },
2238
+ "seenOnlyInChannel": {
2239
+ "type": [
2240
+ "boolean",
2241
+ "null"
2242
+ ]
2243
+ },
2244
+ "persona": {
2245
+ "type": [
2246
+ "object",
2247
+ "null"
2248
+ ],
2249
+ "additionalProperties": false,
2250
+ "properties": {
2251
+ "name": {
2252
+ "type": [
2253
+ "string",
2254
+ "null"
2255
+ ],
2256
+ "maxLength": 120
2257
+ },
2258
+ "first": {
2259
+ "type": [
2260
+ "string",
2261
+ "null"
2262
+ ],
2263
+ "maxLength": 80
2264
+ },
2265
+ "last": {
2266
+ "type": [
2267
+ "string",
2268
+ "null"
2269
+ ],
2270
+ "maxLength": 80
2271
+ },
2272
+ "username": {
2273
+ "type": [
2274
+ "string",
2275
+ "null"
2276
+ ],
2277
+ "maxLength": 120
2278
+ },
2279
+ "seed": {
2280
+ "type": [
2281
+ "number",
2282
+ "null"
2283
+ ],
2284
+ "minimum": 0
2285
+ },
2286
+ "role": {
2287
+ "type": [
2288
+ "string",
2289
+ "null"
2290
+ ],
2291
+ "maxLength": 40
2292
+ },
2293
+ "personality": {
2294
+ "type": [
2295
+ "object",
2296
+ "null"
2297
+ ],
2298
+ "additionalProperties": false,
2299
+ "properties": {
2300
+ "temperament": {
2301
+ "type": [
2302
+ "string",
2303
+ "null"
2304
+ ],
2305
+ "maxLength": 200
2306
+ },
2307
+ "voice": {
2308
+ "type": [
2309
+ "string",
2310
+ "null"
2311
+ ],
2312
+ "maxLength": 200
2313
+ },
2314
+ "emoji": {
2315
+ "type": "array",
2316
+ "maxItems": 8,
2317
+ "items": {
2318
+ "type": "string",
2319
+ "maxLength": 16
2320
+ }
2321
+ },
2322
+ "habit": {
2323
+ "type": [
2324
+ "string",
2325
+ "null"
2326
+ ],
2327
+ "maxLength": 200
2328
+ }
2329
+ }
2330
+ }
2331
+ }
2332
+ },
2333
+ "parentId": {
2334
+ "type": [
2335
+ "string",
2336
+ "null"
2337
+ ],
2338
+ "maxLength": 120
2339
+ },
2340
+ "displayTitle": {
2341
+ "type": [
2342
+ "string",
2343
+ "null"
2344
+ ],
2345
+ "maxLength": 300
2346
+ },
2347
+ "override": {
2348
+ "type": [
2349
+ "object",
2350
+ "null"
2351
+ ],
2352
+ "additionalProperties": false,
2353
+ "properties": {
2354
+ "status": {
2355
+ "type": "string",
2356
+ "enum": [
2357
+ "done",
2358
+ "blocked",
2359
+ "stopped",
2360
+ "handed-over",
2361
+ "working"
2362
+ ]
2363
+ },
2364
+ "reason": {
2365
+ "type": [
2366
+ "string",
2367
+ "null"
2368
+ ],
2369
+ "maxLength": 500
2370
+ },
2371
+ "to": {
2372
+ "type": [
2373
+ "string",
2374
+ "null"
2375
+ ],
2376
+ "maxLength": 120
2377
+ },
2378
+ "by": {
2379
+ "type": [
2380
+ "string",
2381
+ "null"
2382
+ ],
2383
+ "maxLength": 120
2384
+ },
2385
+ "at": {
2386
+ "type": [
2387
+ "number",
2388
+ "null"
2389
+ ],
2390
+ "minimum": 0
2391
+ }
2392
+ }
2393
+ },
2394
+ "reach": {
2395
+ "type": [
2396
+ "object",
2397
+ "null"
2398
+ ],
2399
+ "additionalProperties": false,
2400
+ "properties": {
2401
+ "streamKey": {
2402
+ "type": [
2403
+ "string",
2404
+ "null"
2405
+ ],
2406
+ "maxLength": 240
2407
+ },
2408
+ "channel": {
2409
+ "type": [
2410
+ "string",
2411
+ "null"
2412
+ ],
2413
+ "maxLength": 120
2414
+ },
2415
+ "state": {
2416
+ "type": [
2417
+ "string",
2418
+ "null"
2419
+ ],
2420
+ "maxLength": 40
2421
+ },
2422
+ "lastAt": {
2423
+ "type": [
2424
+ "number",
2425
+ "null"
2426
+ ],
2427
+ "minimum": 0
2428
+ },
2429
+ "chat": {
2430
+ "type": [
2431
+ "string",
2432
+ "null"
2433
+ ],
2434
+ "maxLength": 300
2435
+ },
2436
+ "workspace": {
2437
+ "type": [
2438
+ "string",
2439
+ "null"
2440
+ ],
2441
+ "maxLength": 120
2442
+ },
2443
+ "chatInbox": {
2444
+ "type": [
2445
+ "boolean",
2446
+ "null"
2447
+ ]
2448
+ },
2449
+ "hubRun": {
2450
+ "type": [
2451
+ "string",
2452
+ "null"
2453
+ ],
2454
+ "maxLength": 40
2455
+ },
2456
+ "live": {
2457
+ "type": [
2458
+ "object",
2459
+ "null"
2460
+ ],
2461
+ "additionalProperties": false,
2462
+ "properties": {
2463
+ "at": {
2464
+ "type": [
2465
+ "number",
2466
+ "null"
2467
+ ],
2468
+ "minimum": 0
2469
+ },
2470
+ "event": {
2471
+ "type": [
2472
+ "string",
2473
+ "null"
2474
+ ],
2475
+ "maxLength": 40
2476
+ },
2477
+ "tool": {
2478
+ "type": [
2479
+ "string",
2480
+ "null"
2481
+ ],
2482
+ "maxLength": 80
2483
+ }
2484
+ }
2485
+ }
2486
+ }
2487
+ },
2488
+ "hubRun": {
2489
+ "type": [
2490
+ "object",
2491
+ "null"
2492
+ ],
2493
+ "additionalProperties": false,
2494
+ "properties": {
2495
+ "driver": {
2496
+ "type": [
2497
+ "string",
2498
+ "null"
2499
+ ],
2500
+ "maxLength": 40
2501
+ },
2502
+ "state": {
2503
+ "type": [
2504
+ "string",
2505
+ "null"
2506
+ ],
2507
+ "maxLength": 40
2508
+ },
2509
+ "turns": {
2510
+ "type": [
2511
+ "integer",
2512
+ "null"
2513
+ ],
2514
+ "minimum": 0,
2515
+ "maximum": 1000000
2516
+ },
2517
+ "costUsd": {
2518
+ "type": [
2519
+ "number",
2520
+ "null"
2521
+ ],
2522
+ "minimum": 0
2523
+ },
2524
+ "lastError": {
2525
+ "type": [
2526
+ "string",
2527
+ "null"
2528
+ ],
2529
+ "maxLength": 500
2530
+ }
2531
+ }
2532
+ }
2533
+ }
2534
+ },
2535
+ "nodes": {
2536
+ "type": [
2537
+ "object",
2538
+ "null"
2539
+ ],
2540
+ "additionalProperties": false,
2541
+ "properties": {
2542
+ "id": {
2543
+ "type": "string",
2544
+ "maxLength": 120
2545
+ },
2546
+ "kind": {
2547
+ "type": [
2548
+ "string",
2549
+ "null"
2550
+ ],
2551
+ "maxLength": 20
2552
+ },
2553
+ "node_type": {
2554
+ "type": [
2555
+ "string",
2556
+ "null"
2557
+ ],
2558
+ "maxLength": 40
2559
+ },
2560
+ "role": {
2561
+ "type": [
2562
+ "string",
2563
+ "null"
2564
+ ],
2565
+ "maxLength": 40
2566
+ },
2567
+ "label": {
2568
+ "type": [
2569
+ "string",
2570
+ "null"
2571
+ ],
2572
+ "maxLength": 300
2573
+ },
2574
+ "title": {
2575
+ "type": [
2576
+ "string",
2577
+ "null"
2578
+ ],
2579
+ "maxLength": 300
2580
+ },
2581
+ "chatTitle": {
2582
+ "type": [
2583
+ "string",
2584
+ "null"
2585
+ ],
2586
+ "maxLength": 300
2587
+ },
2588
+ "displayTitle": {
2589
+ "type": [
2590
+ "string",
2591
+ "null"
2592
+ ],
2593
+ "maxLength": 300
2594
+ },
2595
+ "parent": {
2596
+ "type": [
2597
+ "string",
2598
+ "null"
2599
+ ],
2600
+ "maxLength": 120
2601
+ },
2602
+ "deliveryId": {
2603
+ "type": [
2604
+ "string",
2605
+ "null"
2606
+ ],
2607
+ "maxLength": 120
2608
+ },
2609
+ "deliveryTitle": {
2610
+ "type": [
2611
+ "string",
2612
+ "null"
2613
+ ],
2614
+ "maxLength": 300
2615
+ },
2616
+ "channelKey": {
2617
+ "type": [
2618
+ "string",
2619
+ "null"
2620
+ ],
2621
+ "maxLength": 240
2622
+ },
2623
+ "channel": {
2624
+ "type": [
2625
+ "string",
2626
+ "null"
2627
+ ],
2628
+ "maxLength": 120
2629
+ },
2630
+ "repo": {
2631
+ "type": [
2632
+ "string",
2633
+ "null"
2634
+ ],
2635
+ "maxLength": 120
2636
+ },
2637
+ "project": {
2638
+ "type": [
2639
+ "string",
2640
+ "null"
2641
+ ],
2642
+ "maxLength": 120
2643
+ },
2644
+ "taskTitle": {
2645
+ "type": [
2646
+ "string",
2647
+ "null"
2648
+ ],
2649
+ "maxLength": 300
2650
+ },
2651
+ "startedAt": {
2652
+ "type": [
2653
+ "number",
2654
+ "null"
2655
+ ],
2656
+ "minimum": 0
2657
+ },
2658
+ "lastAt": {
2659
+ "type": [
2660
+ "number",
2661
+ "null"
2662
+ ],
2663
+ "minimum": 0
2664
+ },
2665
+ "status": {
2666
+ "type": [
2667
+ "string",
2668
+ "null"
2669
+ ],
2670
+ "maxLength": 20
2671
+ },
2672
+ "tokensEst": {
2673
+ "type": [
2674
+ "number",
2675
+ "null"
2676
+ ],
2677
+ "minimum": 0
2678
+ },
2679
+ "msgsIn": {
2680
+ "type": [
2681
+ "integer",
2682
+ "null"
2683
+ ],
2684
+ "minimum": 0,
2685
+ "maximum": 100000000
2686
+ },
2687
+ "msgsOut": {
2688
+ "type": [
2689
+ "integer",
2690
+ "null"
2691
+ ],
2692
+ "minimum": 0,
2693
+ "maximum": 100000000
2694
+ },
2695
+ "persona": {
2696
+ "type": [
2697
+ "object",
2698
+ "null"
2699
+ ],
2700
+ "additionalProperties": false,
2701
+ "properties": {
2702
+ "name": {
2703
+ "type": [
2704
+ "string",
2705
+ "null"
2706
+ ],
2707
+ "maxLength": 120
2708
+ },
2709
+ "first": {
2710
+ "type": [
2711
+ "string",
2712
+ "null"
2713
+ ],
2714
+ "maxLength": 80
2715
+ },
2716
+ "last": {
2717
+ "type": [
2718
+ "string",
2719
+ "null"
2720
+ ],
2721
+ "maxLength": 80
2722
+ },
2723
+ "username": {
2724
+ "type": [
2725
+ "string",
2726
+ "null"
2727
+ ],
2728
+ "maxLength": 120
2729
+ },
2730
+ "seed": {
2731
+ "type": [
2732
+ "number",
2733
+ "null"
2734
+ ],
2735
+ "minimum": 0
2736
+ },
2737
+ "role": {
2738
+ "type": [
2739
+ "string",
2740
+ "null"
2741
+ ],
2742
+ "maxLength": 40
2743
+ },
2744
+ "personality": {
2745
+ "type": [
2746
+ "object",
2747
+ "null"
2748
+ ],
2749
+ "additionalProperties": false,
2750
+ "properties": {
2751
+ "temperament": {
2752
+ "type": [
2753
+ "string",
2754
+ "null"
2755
+ ],
2756
+ "maxLength": 200
2757
+ },
2758
+ "voice": {
2759
+ "type": [
2760
+ "string",
2761
+ "null"
2762
+ ],
2763
+ "maxLength": 200
2764
+ },
2765
+ "emoji": {
2766
+ "type": "array",
2767
+ "maxItems": 8,
2768
+ "items": {
2769
+ "type": "string",
2770
+ "maxLength": 16
2771
+ }
2772
+ },
2773
+ "habit": {
2774
+ "type": [
2775
+ "string",
2776
+ "null"
2777
+ ],
2778
+ "maxLength": 200
2779
+ }
2780
+ }
2781
+ }
2782
+ }
2783
+ },
2784
+ "busAddress": {
2785
+ "type": [
2786
+ "string",
2787
+ "null"
2788
+ ],
2789
+ "maxLength": 120
2790
+ },
2791
+ "busOnline": {
2792
+ "type": [
2793
+ "boolean",
2794
+ "null"
2795
+ ]
2796
+ },
2797
+ "synthetic": {
2798
+ "type": [
2799
+ "boolean",
2800
+ "null"
2801
+ ]
2802
+ }
2803
+ }
2804
+ },
2805
+ "links": {
2806
+ "type": [
2807
+ "object",
2808
+ "null"
2809
+ ],
2810
+ "additionalProperties": false,
2811
+ "properties": {
2812
+ "source": {
2813
+ "type": "string",
2814
+ "maxLength": 120
2815
+ },
2816
+ "target": {
2817
+ "type": "string",
2818
+ "maxLength": 120
2819
+ },
2820
+ "kind": {
2821
+ "type": "string",
2822
+ "maxLength": 40
2823
+ },
2824
+ "count": {
2825
+ "type": "integer",
2826
+ "minimum": 0,
2827
+ "maximum": 100000000
2828
+ }
2829
+ }
2830
+ },
2831
+ "events": {
2832
+ "type": [
2833
+ "object",
2834
+ "null"
2835
+ ],
2836
+ "additionalProperties": false,
2837
+ "properties": {
2838
+ "at": {
2839
+ "type": [
2840
+ "number",
2841
+ "null"
2842
+ ],
2843
+ "minimum": 0
2844
+ },
2845
+ "from": {
2846
+ "type": [
2847
+ "string",
2848
+ "null"
2849
+ ],
2850
+ "maxLength": 120
2851
+ },
2852
+ "to": {
2853
+ "type": [
2854
+ "string",
2855
+ "null"
2856
+ ],
2857
+ "maxLength": 120
2858
+ },
2859
+ "type": {
2860
+ "type": [
2861
+ "string",
2862
+ "null"
2863
+ ],
2864
+ "maxLength": 40
2865
+ },
2866
+ "text": {
2867
+ "type": [
2868
+ "string",
2869
+ "null"
2870
+ ],
2871
+ "maxLength": 4000
2872
+ },
2873
+ "messageId": {
2874
+ "type": [
2875
+ "string",
2876
+ "null"
2877
+ ],
2878
+ "maxLength": 120
2879
+ },
2880
+ "topic": {
2881
+ "type": [
2882
+ "string",
2883
+ "null"
2884
+ ],
2885
+ "maxLength": 240
2886
+ },
2887
+ "bus": {
2888
+ "type": [
2889
+ "boolean",
2890
+ "null"
2891
+ ]
2892
+ },
2893
+ "channel": {
2894
+ "type": [
2895
+ "string",
2896
+ "null"
2897
+ ],
2898
+ "maxLength": 260
2899
+ }
2900
+ }
2901
+ },
2902
+ "requests": {
2903
+ "type": [
2904
+ "object",
2905
+ "null"
2906
+ ],
2907
+ "additionalProperties": false,
2908
+ "properties": {
2909
+ "key": {
2910
+ "type": [
2911
+ "string",
2912
+ "null"
2913
+ ],
2914
+ "maxLength": 260
2915
+ },
2916
+ "id": {
2917
+ "type": "string",
2918
+ "maxLength": 260
2919
+ },
2920
+ "title": {
2921
+ "type": [
2922
+ "string",
2923
+ "null"
2924
+ ],
2925
+ "maxLength": 300
2926
+ },
2927
+ "kind": {
2928
+ "type": [
2929
+ "string",
2930
+ "null"
2931
+ ],
2932
+ "maxLength": 40
2933
+ },
2934
+ "from": {
2935
+ "type": "array",
2936
+ "maxItems": 20,
2937
+ "items": {
2938
+ "type": "string",
2939
+ "maxLength": 120
2940
+ }
2941
+ },
2942
+ "status": {
2943
+ "type": [
2944
+ "string",
2945
+ "null"
2946
+ ],
2947
+ "maxLength": 40
2948
+ },
2949
+ "at": {
2950
+ "type": [
2951
+ "number",
2952
+ "null"
2953
+ ],
2954
+ "minimum": 0
2955
+ },
2956
+ "channel": {
2957
+ "type": [
2958
+ "string",
2959
+ "null"
2960
+ ],
2961
+ "maxLength": 120
2962
+ }
2963
+ }
2964
+ }
2965
+ }
2966
+ }
2967
+ },
2968
+ "privacy": {
2969
+ "rejectPathPattern": "(^|[\\s\"'`(=:,\\[]|file://)(/Users/|/Volumes/|/home/|/private/|/tmp/|~/|[A-Za-z]:\\\\)",
2970
+ "rejectKeys": [
2971
+ "file",
2972
+ "path",
2973
+ "cwd",
2974
+ "worktreePath",
2975
+ "mainRepo",
2976
+ "channelCheckout",
2977
+ "transcript",
2978
+ "transcriptPath",
2979
+ "diff",
2980
+ "patch",
2981
+ "token",
2982
+ "secret",
2983
+ "password"
2984
+ ],
2985
+ "note": "rule files carry a pack-relative file name in rules[].file; every other path is redacted before upload",
2986
+ "secrets": [
2987
+ {
2988
+ "id": "pem-private-key",
2989
+ "regex": "-----BEGIN [A-Z0-9 ]{0,40}PRIVATE KEY[A-Z ]{0,10}-----(?:[\\s\\S]{0,16000}?(?:-----END [A-Z0-9 ]{0,40}PRIVATE KEY[A-Z ]{0,10}-----|$|(?=-----BEGIN ))|)",
2990
+ "flags": "g",
2991
+ "replacement": "[redacted:pem-private-key]",
2992
+ "note": "the whole block, up to 16000 characters; a block cut short is redacted to the end of the text or the next BEGIN, and a longer one loses at least its header",
2993
+ "samples": {
2994
+ "positive": [
2995
+ "-----BEGIN RSA PRIVATE KEY-----\nMIIEFAKEFAKEFAKEFAKE\n-----END RSA PRIVATE KEY-----",
2996
+ "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktFAKE cut short",
2997
+ "-----BEGIN PGP PRIVATE KEY BLOCK-----\nlQOYBFAKE\n-----END PGP PRIVATE KEY BLOCK-----",
2998
+ "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEFAKE\n-----END EC PRIVATE KEY-----"
2999
+ ],
3000
+ "negative": [
3001
+ "-----BEGIN PUBLIC KEY-----",
3002
+ "-----BEGIN CERTIFICATE-----",
3003
+ "the private key lives in the keychain"
3004
+ ]
3005
+ }
3006
+ },
3007
+ {
3008
+ "id": "aws-access-key-id",
3009
+ "regex": "\\bAKIA[A-Z0-9]{16}\\b",
3010
+ "flags": "g",
3011
+ "replacement": "[redacted:aws-access-key-id]",
3012
+ "samples": {
3013
+ "positive": [
3014
+ "AKIAEXAMPLEFAKE00001",
3015
+ "aws_access_key_id = AKIAEXAMPLEFAKE00003"
3016
+ ],
3017
+ "negative": [
3018
+ "AKIA is the prefix of an access key id",
3019
+ "akiaexamplefake00001",
3020
+ "AKIAEXAMPLEFAKE0000123456"
3021
+ ]
3022
+ }
3023
+ },
3024
+ {
3025
+ "id": "aws-temporary-key-id",
3026
+ "regex": "\\bASIA[A-Z0-9]{16}\\b",
3027
+ "flags": "g",
3028
+ "replacement": "[redacted:aws-temporary-key-id]",
3029
+ "samples": {
3030
+ "positive": [
3031
+ "ASIAEXAMPLEFAKE00002",
3032
+ "\"AccessKeyId\": \"ASIAEXAMPLEFAKE00004\""
3033
+ ],
3034
+ "negative": [
3035
+ "ASIA is the prefix of a temporary key id",
3036
+ "ASIAN markets",
3037
+ "ASIAEXAMPLEFAKE0000123456"
3038
+ ]
3039
+ }
3040
+ },
3041
+ {
3042
+ "id": "aws-secret-access-key",
3043
+ "regex": "\\b(?:aws_?)?secret_?access_?key[\"']?\\s{0,5}[:=]\\s{0,5}[\"']?[A-Za-z0-9/+=]{40}(?![A-Za-z0-9/+=])",
3044
+ "flags": "gi",
3045
+ "replacement": "[redacted:aws-secret-access-key]",
3046
+ "samples": {
3047
+ "positive": [
3048
+ "aws_secret_access_key = FAKEfakeFAKEfakeFAKEfakeFAKEfakeFAKEfake",
3049
+ "AWS_SECRET_ACCESS_KEY=\"FAKE/fake+FAKEfakeFAKEfakeFAKEfakeFAKEfa\"",
3050
+ "\"SecretAccessKey\": \"FAKEfakeFAKEfakeFAKEfakeFAKEfakeFAKEfake\"",
3051
+ "secret_access_key: FAKEfakeFAKEfakeFAKEfakeFAKEfakeFAKEfake"
3052
+ ],
3053
+ "negative": [
3054
+ "aws_secret_access_key is read from the environment",
3055
+ "aws_secret_access_key = short",
3056
+ "6ae00f8b34b7920e693f8a81c8227fa5e00b1f9c",
3057
+ "commit 6ae00f8b34b7920e693f8a81c8227fa5e00b1f9c"
3058
+ ]
3059
+ }
3060
+ },
3061
+ {
3062
+ "id": "slack-token",
3063
+ "regex": "\\bxox[abposr]-[A-Za-z0-9-]{10,250}",
3064
+ "flags": "g",
3065
+ "replacement": "[redacted:slack-token]",
3066
+ "samples": {
3067
+ "positive": [
3068
+ "xoxb-000000000000-0000000000000-FAKEfakeFAKEfake",
3069
+ "xoxp-1111111111-FAKE",
3070
+ "xoxa-2-FAKEfake0000",
3071
+ "xoxs-0000000000-FAKE"
3072
+ ],
3073
+ "negative": [
3074
+ "xoxo and hugs",
3075
+ "xoxb- alone",
3076
+ "xoxb-short"
3077
+ ]
3078
+ }
3079
+ },
3080
+ {
3081
+ "id": "slack-webhook",
3082
+ "regex": "https://hooks\\.slack\\.com/(?:services|workflows|triggers)/[A-Za-z0-9/_-]{8,300}",
3083
+ "flags": "g",
3084
+ "replacement": "[redacted:slack-webhook]",
3085
+ "samples": {
3086
+ "positive": [
3087
+ "https://hooks.slack.com/services/T00000000/B00000000/FAKEfakeFAKEfakeFAKEfake",
3088
+ "https://hooks.slack.com/workflows/T00000000/A00000000/FAKE0000"
3089
+ ],
3090
+ "negative": [
3091
+ "https://hooks.slack.com/",
3092
+ "https://api.slack.com/messaging/webhooks"
3093
+ ]
3094
+ }
3095
+ },
3096
+ {
3097
+ "id": "stripe-secret-key",
3098
+ "regex": "\\bsk_(?:live|test)_[A-Za-z0-9]{16,250}",
3099
+ "flags": "g",
3100
+ "replacement": "[redacted:stripe-secret-key]",
3101
+ "samples": {
3102
+ "positive": [
3103
+ "sk_live_FAKEfakeFAKEfake0000",
3104
+ "sk_test_FAKEfakeFAKEfake0000"
3105
+ ],
3106
+ "negative": [
3107
+ "sk_live_ is the live-mode prefix",
3108
+ "pk_live_FAKEfakeFAKEfake0000",
3109
+ "sk_live_short"
3110
+ ]
3111
+ }
3112
+ },
3113
+ {
3114
+ "id": "stripe-restricted-key",
3115
+ "regex": "\\brk_(?:live|test)_[A-Za-z0-9]{16,250}",
3116
+ "flags": "g",
3117
+ "replacement": "[redacted:stripe-restricted-key]",
3118
+ "samples": {
3119
+ "positive": [
3120
+ "rk_live_FAKEfakeFAKEfake0000",
3121
+ "rk_test_FAKEfakeFAKEfake0000"
3122
+ ],
3123
+ "negative": [
3124
+ "rk_live_ is the restricted-key prefix",
3125
+ "rk_test_short"
3126
+ ]
3127
+ }
3128
+ },
3129
+ {
3130
+ "id": "google-api-key",
3131
+ "regex": "\\bAIza[0-9A-Za-z_-]{35}",
3132
+ "flags": "g",
3133
+ "replacement": "[redacted:google-api-key]",
3134
+ "samples": {
3135
+ "positive": [
3136
+ "AIzaFAKEfakeFAKEfakeFAKEfakeFAKEfake000",
3137
+ "key=AIzaSyFAKE-fake_FAKEfakeFAKEfakeFAKE000"
3138
+ ],
3139
+ "negative": [
3140
+ "AIza is the prefix of a Google API key",
3141
+ "AIzaTooShort"
3142
+ ]
3143
+ }
3144
+ },
3145
+ {
3146
+ "id": "github-token",
3147
+ "regex": "\\bgh[pousr]_[A-Za-z0-9]{20,250}",
3148
+ "flags": "g",
3149
+ "replacement": "[redacted:github-token]",
3150
+ "samples": {
3151
+ "positive": [
3152
+ "ghp_FAKEfakeFAKEfakeFAKEfake0000",
3153
+ "gho_FAKEfakeFAKEfakeFAKEfake0000",
3154
+ "ghu_FAKEfakeFAKEfakeFAKEfake0000",
3155
+ "ghs_FAKEfakeFAKEfakeFAKEfake0000",
3156
+ "ghr_FAKEfakeFAKEfakeFAKEfake0000"
3157
+ ],
3158
+ "negative": [
3159
+ "ghp_short",
3160
+ "the gh_ prefix",
3161
+ "ghx_FAKEfakeFAKEfakeFAKEfake0000"
3162
+ ]
3163
+ }
3164
+ },
3165
+ {
3166
+ "id": "github-pat",
3167
+ "regex": "\\bgithub_pat_[A-Za-z0-9_]{20,250}",
3168
+ "flags": "g",
3169
+ "replacement": "[redacted:github-pat]",
3170
+ "samples": {
3171
+ "positive": [
3172
+ "github_pat_11FAKEFAKE0_FAKEfakeFAKEfakeFAKE"
3173
+ ],
3174
+ "negative": [
3175
+ "github_pat_ is the fine-grained token prefix",
3176
+ "github_pat_short"
3177
+ ]
3178
+ }
3179
+ },
3180
+ {
3181
+ "id": "provider-api-key",
3182
+ "regex": "\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,250}",
3183
+ "flags": "g",
3184
+ "replacement": "[redacted:provider-api-key]",
3185
+ "note": "OpenAI and Anthropic keys",
3186
+ "samples": {
3187
+ "positive": [
3188
+ "sk-ant-api03-FAKEfakeFAKEfake0000",
3189
+ "sk-proj-FAKEfakeFAKEfake0000",
3190
+ "sk-FAKEfakeFAKEfakeFAKE"
3191
+ ],
3192
+ "negative": [
3193
+ "task-runner-for-everything-here",
3194
+ "sk-short"
3195
+ ]
3196
+ }
3197
+ },
3198
+ {
3199
+ "id": "jwt",
3200
+ "regex": "\\beyJ[A-Za-z0-9_-]{8,4000}\\.[A-Za-z0-9_-]{8,4000}\\.[A-Za-z0-9_-]{8,4000}",
3201
+ "flags": "g",
3202
+ "replacement": "[redacted:jwt]",
3203
+ "samples": {
3204
+ "positive": [
3205
+ "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmYWtlIn0.FAKEfakeFAKEfake"
3206
+ ],
3207
+ "negative": [
3208
+ "eyJ alone",
3209
+ "eyJhbGciOiJIUzI1NiJ9 without a payload",
3210
+ "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmYWtlIn0."
3211
+ ]
3212
+ }
3213
+ },
3214
+ {
3215
+ "id": "bearer",
3216
+ "regex": "\\bBearer\\s{1,5}[A-Za-z0-9._~+/=-]{16,4000}",
3217
+ "flags": "gi",
3218
+ "replacement": "[redacted:bearer]",
3219
+ "samples": {
3220
+ "positive": [
3221
+ "Authorization: Bearer FAKEfakeFAKEfake0000",
3222
+ "bearer FAKEfakeFAKEfake0000"
3223
+ ],
3224
+ "negative": [
3225
+ "Bearer authentication",
3226
+ "a bearer token is required",
3227
+ "Bearer tokens expire",
3228
+ "Bearer ${TOKEN}"
3229
+ ]
3230
+ }
3231
+ },
3232
+ {
3233
+ "id": "basic-auth",
3234
+ "regex": "\\bAuthorization[\"']?\\s{0,5}[:=]\\s{0,5}[\"']?Basic\\s{1,5}[A-Za-z0-9+/]{8,4000}={0,2}(?![A-Za-z0-9+/=])",
3235
+ "flags": "gi",
3236
+ "replacement": "[redacted:basic-auth]",
3237
+ "samples": {
3238
+ "positive": [
3239
+ "Authorization: Basic dXNlcjpGQUtFcGFzcw==",
3240
+ "curl -H \"Authorization: Basic dXNlcjpwYXNz\" https://x",
3241
+ "{\"Authorization\": \"Basic dXNlcjpGQUtF\"}"
3242
+ ],
3243
+ "negative": [
3244
+ "Authorization: Basic realm=\"api\"",
3245
+ "the Authorization header uses Basic auth",
3246
+ "Authorization: Basic ${CREDS}",
3247
+ "Basic dXNlcjpwYXNz without the header"
3248
+ ]
3249
+ }
3250
+ },
3251
+ {
3252
+ "id": "url-credential",
3253
+ "regex": "(?<=\\b[A-Za-z][A-Za-z0-9+.-]{1,20}://[^\\s:/?#@'\"\\x60<>]{0,100}:)(?!\\[redacted:|\\$)[^\\s/?#@'\"\\x60<>]{1,200}(?=@[A-Za-z0-9\\[])",
3254
+ "flags": "g",
3255
+ "replacement": "[redacted:url-credential]",
3256
+ "note": "only the password of scheme://user:password@host; the scheme, user and host stay",
3257
+ "samples": {
3258
+ "positive": [
3259
+ "postgres://app:FAKEfake0000@db.internal:5432/prod",
3260
+ "DATABASE_URL=mysql://root:hunter2@localhost/db",
3261
+ "https://user:FAKEpass@github.com/org/repo.git",
3262
+ "redis://:FAKEfake0000@cache:6379"
3263
+ ],
3264
+ "negative": [
3265
+ "https://example.com:8443/path",
3266
+ "postgres://app:${DB_PASSWORD}@db",
3267
+ "ssh://git@github.com/org/repo",
3268
+ "mailto:someone@example.com",
3269
+ "http://user@host/x",
3270
+ "see https://x.io:443/@user",
3271
+ "git@github.com:org/repo.git"
3272
+ ]
3273
+ }
3274
+ },
3275
+ {
3276
+ "id": "password",
3277
+ "regex": "(?<keep>(?<![A-Za-z0-9])(?:[A-Za-z0-9]{1,40}[_-]){0,6}[A-Za-z0-9]{0,40}(?:password|passwd|pwd|passphrase)(?![A-Za-z0-9])[\"']?\\s{0,5}(?<![=!<>])(?:=>|:|=(?!=))\\s{0,5}[\"']?)(?:(?<=\")(?!(?:\\*{2,}|[xX]{3,}|•{2,}|\\.{3,}|…|<[^>\\r\\n]{0,100}>|\\$\\{[^}\\r\\n]{0,100}\\}|\\$\\([^)\\r\\n]{0,200}\\)|\\$[A-Za-z_][A-Za-z0-9_]{0,100}|%[A-Za-z_][A-Za-z0-9_]{0,100}%|\\{\\{[^}\\r\\n]{0,100}\\}\\}|\\[redacted[^\\]\\r\\n]{0,60}\\]|(?:process\\.env|os\\.environ|env)[.\\[][^\\s\"'\\r\\n]{0,100}|changeme(?:[-_][A-Za-z0-9]{1,40})?|placeholder|(?:your|enter)[-_][A-Za-z0-9_-]{1,40}|redacted|null|undefined|none)\")[^\"\\r\\n]{1,200}(?=\")|(?<=')(?!(?:\\*{2,}|[xX]{3,}|•{2,}|\\.{3,}|…|<[^>\\r\\n]{0,100}>|\\$\\{[^}\\r\\n]{0,100}\\}|\\$\\([^)\\r\\n]{0,200}\\)|\\$[A-Za-z_][A-Za-z0-9_]{0,100}|%[A-Za-z_][A-Za-z0-9_]{0,100}%|\\{\\{[^}\\r\\n]{0,100}\\}\\}|\\[redacted[^\\]\\r\\n]{0,60}\\]|(?:process\\.env|os\\.environ|env)[.\\[][^\\s\"'\\r\\n]{0,100}|changeme(?:[-_][A-Za-z0-9]{1,40})?|placeholder|(?:your|enter)[-_][A-Za-z0-9_-]{1,40}|redacted|null|undefined|none)')[^'\\r\\n]{1,200}(?=')|(?:(?<=[:=>])|(?<=\\s)(?!(?:in|is|to|the|a|an|and|or|of|for|on|with|from|via|field|flag|here|at|as|be|by|if|it|this|that|must|should|will|can|was|are|not|no|required|optional|min|max|minimum|maximum|length|policy|reset|strength|rules?|hint|prompt|input)\\s+[A-Za-z.]|(?:string|number|boolean|any|unknown|object|never|void)(?:\\[\\])?(?![^\\s;,)|])(?![^;\\r\\n]{0,300}(?<![=!<>:])=(?![=>]))))(?!(?:\\*{2,}|[xX]{3,}|•{2,}|\\.{3,}|…|<[^>\\r\\n]{0,100}>|\\$\\{[^}\\r\\n]{0,100}\\}|\\$\\([^)\\r\\n]{0,200}\\)|\\$[A-Za-z_][A-Za-z0-9_]{0,100}|%[A-Za-z_][A-Za-z0-9_]{0,100}%|\\{\\{[^}\\r\\n]{0,100}\\}\\}|\\[redacted[^\\]\\r\\n]{0,60}\\]|(?:process\\.env|os\\.environ|env)[.\\[][^\\s\"'\\r\\n]{0,100}|changeme(?:[-_][A-Za-z0-9]{1,40})?|placeholder|(?:your|enter)[-_][A-Za-z0-9_-]{1,40}|redacted|null|undefined|none)(?![^\\s,;\"'\\x60(){}<>\\[\\]$]))[^\\s,;\"'\\x60(){}<>\\[\\]]{1,200}(?![^\\s,;\"'\\x60(){}<>\\[\\]])(?!\\s{0,3}[=!<>]=))(?<tail>[\"']?)",
3278
+ "flags": "gi",
3279
+ "replacement": "[redacted:password]",
3280
+ "samples": {
3281
+ "positive": [
3282
+ "password=hunter2!",
3283
+ "PASSWORD: \"correct-horse\"",
3284
+ "{\"password\": \"hunter22\"}",
3285
+ "db?pwd=hunter22",
3286
+ "passwd='s3cr3t-pass'",
3287
+ "DB_PASSWORD=FAKEfake0000",
3288
+ "{\"DB_PASSWORD\":\"FAKEfake0000\"}",
3289
+ "MYSQL_ROOT_PASSWORD=\"FAKEfake\"",
3290
+ "password=correcthorsebattery",
3291
+ "password=hunter",
3292
+ "password=sunflowerxy",
3293
+ "password=abc12",
3294
+ "password=x",
3295
+ "password=\"abc\"",
3296
+ "PASSWORD: dragon",
3297
+ "passphrase = letmein",
3298
+ "set password=sunshine.",
3299
+ "pwd: 'ab'",
3300
+ "spring.datasource.password=hunter",
3301
+ "obj.password = \"hunter2\";",
3302
+ "this.password = hunter2!;",
3303
+ "this.password = hunter2;",
3304
+ "this.password=hunter2;",
3305
+ "obj.password = hunter2;",
3306
+ "this.password = Tr0ub4dor;",
3307
+ "this.password = s3cr3tValue;",
3308
+ "this.password = x9;",
3309
+ "this.password = hunter2; // set",
3310
+ "this.dbPassword = hunter2;",
3311
+ "dbPassword: \"x\"",
3312
+ "this.password = password;",
3313
+ "password = form.password",
3314
+ "const password = await getPassword();",
3315
+ ":password => \"hunter2\"",
3316
+ "password=pa$$word",
3317
+ "if (password === input) password = \"hunter2\";",
3318
+ "password: string; password = hunter2",
3319
+ "Password: min length 12, password=hunter2"
3320
+ ],
3321
+ "negative": [
3322
+ "password policy",
3323
+ "passwords must rotate",
3324
+ "enter your password",
3325
+ "password: changeme",
3326
+ "password: changeme-placeholder",
3327
+ "password=your_password_here",
3328
+ "password: ***",
3329
+ "password=xxxx",
3330
+ "password: \"<secret>\"",
3331
+ "password=$DB_PASSWORD",
3332
+ "password=%DB_PASSWORD%",
3333
+ "password: \"{{ db_password }}\"",
3334
+ "password: null",
3335
+ "password: undefined",
3336
+ "password=none",
3337
+ "password: [redacted:password]",
3338
+ "password: \"[redacted:password]\"",
3339
+ "password = process.env.DB_PASSWORD",
3340
+ "set password= in .env",
3341
+ "password: is required",
3342
+ "password: string;",
3343
+ "password: string | null",
3344
+ "if (password === input)",
3345
+ "if (password !== confirm)",
3346
+ "password == other",
3347
+ "const password = protocol === 'Password';",
3348
+ "Password: min length",
3349
+ "passwordMinLength: 12",
3350
+ "tokenCount: 3",
3351
+ "tokens=1234",
3352
+ "maxTokens: 8000",
3353
+ "tokensEst=52k",
3354
+ "max_tokens=4096",
3355
+ "token = req.headers.authorization",
3356
+ "const token = getToken()",
3357
+ "password=${PASSWORD}",
3358
+ "secret=process.env.X",
3359
+ "\"token\": null",
3360
+ "password: ''",
3361
+ "set password= in .env",
3362
+ "the token= flag",
3363
+ "password: <redacted>",
3364
+ "token: [redacted:token]",
3365
+ "MAX_TOKENS=4096",
3366
+ "TOKEN_LIMIT=8000",
3367
+ "PASSWORD_MIN_LENGTH=12",
3368
+ "SECRET_SANTA=true",
3369
+ "token_count: 42"
3370
+ ]
3371
+ },
3372
+ "note": "the key, separator and quotes stay; any non-empty value goes unless it is a clear placeholder"
3373
+ },
3374
+ {
3375
+ "id": "token",
3376
+ "regex": "(?<keep>(?<![A-Za-z0-9])(?:[A-Za-z0-9]{1,40}[_-]){0,6}[A-Za-z0-9]{0,40}(?:token|access[_-]?token|refresh[_-]?token|auth[_-]?token|api[_-]?key|apikey)(?![A-Za-z0-9])[\"']?\\s{0,5}(?<![=!<>])(?:=>|:|=(?!=))\\s{0,5}[\"']?)(?:(?<=\")(?!\\[redacted:)[^\"\\s$]{6,200}(?=\")|(?<=')(?!\\[redacted:)[^'\\s$]{6,200}(?=')|(?<![\"'])(?=[^\\s,;\"'\\x60(){}<>\\[\\]$]{0,199}[0-9])[^\\s,;\"'\\x60(){}<>\\[\\]$]{6,200}(?![\\w.(]))(?<tail>[\"']?)",
3377
+ "flags": "gi",
3378
+ "replacement": "[redacted:token]",
3379
+ "samples": {
3380
+ "positive": [
3381
+ "token=FAKE0123abcd",
3382
+ "see token: abc12345",
3383
+ "api_key=FAKE0000fake",
3384
+ "https://x.example/cb?access_token=FAKEfake0000",
3385
+ "\"refresh_token\":\"FAKEfake0000\"",
3386
+ "apiKey: \"FAKEfakeFAKE\"",
3387
+ "NPM_TOKEN=FAKE0000fake",
3388
+ "SLACK_BOT_TOKEN=FAKE0000fake",
3389
+ "OPENWEATHER_API_KEY=FAKE0000fake",
3390
+ "export GH_TOKEN=FAKE0000fake",
3391
+ "API-KEY: \"FAKEfakeFAKE\"",
3392
+ "apiToken: \"FAKEfake0000\"",
3393
+ "this.apiToken = FAKE0000fake;",
3394
+ "refreshToken=FAKEfake0000"
3395
+ ],
3396
+ "negative": [
3397
+ "the token budget",
3398
+ "maxTokensPerRun=5",
3399
+ "GH_TOKEN=$(gh auth token)",
3400
+ "tokens=1234",
3401
+ "maxTokens: 8000",
3402
+ "tokensEst=52k",
3403
+ "max_tokens=4096",
3404
+ "token = req.headers.authorization",
3405
+ "const token = getToken()",
3406
+ "password=${PASSWORD}",
3407
+ "secret=process.env.X",
3408
+ "\"token\": null",
3409
+ "password: ''",
3410
+ "set password= in .env",
3411
+ "the token= flag",
3412
+ "password: <redacted>",
3413
+ "token: [redacted:token]",
3414
+ "MAX_TOKENS=4096",
3415
+ "TOKEN_LIMIT=8000",
3416
+ "PASSWORD_MIN_LENGTH=12",
3417
+ "SECRET_SANTA=true",
3418
+ "token_count: 42",
3419
+ "token: \"[redacted:token]\"",
3420
+ "passwordMinLength: 12",
3421
+ "tokenCount: 3"
3422
+ ]
3423
+ },
3424
+ "note": "the key, separator and quotes stay"
3425
+ },
3426
+ {
3427
+ "id": "secret",
3428
+ "regex": "(?<keep>(?<![A-Za-z0-9])(?:[A-Za-z0-9]{1,40}[_-]){0,6}[A-Za-z0-9]{0,40}(?:secret|client[_-]?secret|secret[_-]?key|private[_-]?key|access[_-]?key)(?![A-Za-z0-9])[\"']?\\s{0,5}(?<![=!<>])(?:=>|:|=(?!=))\\s{0,5}[\"']?)(?:(?<=\")(?!\\[redacted:)[^\"\\s$]{6,200}(?=\")|(?<=')(?!\\[redacted:)[^'\\s$]{6,200}(?=')|(?<![\"'])(?=[^\\s,;\"'\\x60(){}<>\\[\\]$]{0,199}[0-9])[^\\s,;\"'\\x60(){}<>\\[\\]$]{6,200}(?![\\w.(]))(?<tail>[\"']?)",
3429
+ "flags": "gi",
3430
+ "replacement": "[redacted:secret]",
3431
+ "samples": {
3432
+ "positive": [
3433
+ "secret=FAKE0000fake",
3434
+ "client_secret: FAKEfake0000",
3435
+ "SECRET_KEY=FAKE0000fake",
3436
+ "\"secret\": \"FAKEfakeFAKE\"",
3437
+ "GITHUB_CLIENT_SECRET=FAKEfake0000",
3438
+ "JWT_SECRET=\"FAKEfakeFAKE\"",
3439
+ "private_key: \"FAKEfakeFAKE\"",
3440
+ "clientSecret: \"FAKEfake0000\"",
3441
+ "this.clientSecret = FAKE0000fake;",
3442
+ "accessKey: FAKEfake0000"
3443
+ ],
3444
+ "negative": [
3445
+ "secrets management",
3446
+ "a secret plan",
3447
+ "secret_scanning: enabled",
3448
+ "aws_access_key_id = see the vault",
3449
+ "tokens=1234",
3450
+ "maxTokens: 8000",
3451
+ "tokensEst=52k",
3452
+ "max_tokens=4096",
3453
+ "token = req.headers.authorization",
3454
+ "const token = getToken()",
3455
+ "password=${PASSWORD}",
3456
+ "secret=process.env.X",
3457
+ "\"token\": null",
3458
+ "password: ''",
3459
+ "set password= in .env",
3460
+ "the token= flag",
3461
+ "password: <redacted>",
3462
+ "token: [redacted:token]",
3463
+ "MAX_TOKENS=4096",
3464
+ "TOKEN_LIMIT=8000",
3465
+ "PASSWORD_MIN_LENGTH=12",
3466
+ "SECRET_SANTA=true",
3467
+ "token_count: 42",
3468
+ "secret: \"[redacted:secret]\"",
3469
+ "passwordMinLength: 12",
3470
+ "tokenCount: 3"
3471
+ ]
3472
+ },
3473
+ "note": "the key, separator and quotes stay"
3474
+ }
3475
+ ],
3476
+ "secretRules": [
3477
+ "every rule runs on every string value and key of item data and of job event payloads, in table order, before projection, truncation and hashing",
3478
+ "secretKeys runs in the same walk: an entry whose key names a secret loses its whole string value",
3479
+ "lineNet.block runs before the table on every string; its replacement and withheld marker are placeholders that no opener matches, so redacting twice changes nothing; a string that yields the withheld marker withholds its item",
3480
+ "lineNet runs after the table on every string, line by line; its replacement is a placeholder and its key ignores [redacted:…] markers, so redacting twice changes nothing",
3481
+ "a match is replaced by the rule replacement; a rule with the named groups keep and tail keeps them around it (the key, separator and quotes); no output matches any rule, so redacting twice changes nothing",
3482
+ "every quantifier is bounded, so one string costs time linear in its length",
3483
+ "the connector also replaces the machine credentials it holds; the cloud applies the table again on ingest"
3484
+ ],
3485
+ "secretKeys": {
3486
+ "note": "an object entry whose key names a secret and whose value is a non-empty string that is not a placeholder loses the whole value, in every walker on both sides",
3487
+ "normalize": "a key longer than 200 characters is not judged; otherwise a lower-case letter or digit followed by an upper-case letter gets a _ between them (apiKey becomes api_Key), then each family regex is tried in order; a strict family redacts any non-empty value that is not a placeholder, the others also keep nonSecretWords; under a key of a lineNet family, every string leaf of an array or object value is replaced the same way",
3488
+ "families": [
3489
+ {
3490
+ "id": "password",
3491
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:password|passwd|pwd|passphrase)$",
3492
+ "flags": "i",
3493
+ "replacement": "[redacted:password]",
3494
+ "strict": true
3495
+ },
3496
+ {
3497
+ "id": "private-key",
3498
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:private[_-]?key)$",
3499
+ "flags": "i",
3500
+ "replacement": "[redacted:private-key]"
3501
+ },
3502
+ {
3503
+ "id": "access-key",
3504
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:access[_-]?key)$",
3505
+ "flags": "i",
3506
+ "replacement": "[redacted:access-key]"
3507
+ },
3508
+ {
3509
+ "id": "secret",
3510
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:secret|client[_-]?secret|secret[_-]?key)$",
3511
+ "flags": "i",
3512
+ "replacement": "[redacted:secret]"
3513
+ },
3514
+ {
3515
+ "id": "token",
3516
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:token|api[_-]?key|apikey|access[_-]?token|refresh[_-]?token|auth[_-]?token)$",
3517
+ "flags": "i",
3518
+ "replacement": "[redacted:token]"
3519
+ },
3520
+ {
3521
+ "id": "auth",
3522
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:auth|authorization)$",
3523
+ "flags": "i",
3524
+ "replacement": "[redacted:auth]"
3525
+ },
3526
+ {
3527
+ "id": "credentials",
3528
+ "regex": "^(?:[a-z0-9]{1,40}[_-]){0,6}(?:credentials?|creds)$",
3529
+ "flags": "i",
3530
+ "replacement": "[redacted:credentials]"
3531
+ }
3532
+ ],
3533
+ "placeholder": {
3534
+ "regex": "^(?:\\*{2,}|[xX]{3,}|•{2,}|\\.{3,}|…|<[^>\\r\\n]{0,100}>|\\$\\{[^}\\r\\n]{0,100}\\}|\\$\\([^)\\r\\n]{0,200}\\)|\\$[A-Za-z_][A-Za-z0-9_]{0,100}|%[A-Za-z_][A-Za-z0-9_]{0,100}%|\\{\\{[^}\\r\\n]{0,100}\\}\\}|\\[redacted[^\\]\\r\\n]{0,60}\\]|(?:process\\.env|os\\.environ|env)[.\\[][^\\s\"'\\r\\n]{0,100}|changeme(?:[-_][A-Za-z0-9]{1,40})?|placeholder|(?:your|enter)[-_][A-Za-z0-9_-]{1,40}|redacted|null|undefined|none)$",
3535
+ "flags": "i",
3536
+ "note": "tried on the trimmed value; an empty value is never redacted"
3537
+ },
3538
+ "samples": {
3539
+ "positive": [
3540
+ {
3541
+ "input": {
3542
+ "password": "FAKEfake"
3543
+ },
3544
+ "output": {
3545
+ "password": "[redacted:password]"
3546
+ }
3547
+ },
3548
+ {
3549
+ "input": {
3550
+ "token": "FAKEfake0009"
3551
+ },
3552
+ "output": {
3553
+ "token": "[redacted:token]"
3554
+ }
3555
+ },
3556
+ {
3557
+ "input": {
3558
+ "apiKey": "FAKEfakeFAKE"
3559
+ },
3560
+ "output": {
3561
+ "apiKey": "[redacted:token]"
3562
+ }
3563
+ },
3564
+ {
3565
+ "input": {
3566
+ "client_secret": "FAKEfake0000"
3567
+ },
3568
+ "output": {
3569
+ "client_secret": "[redacted:secret]"
3570
+ }
3571
+ },
3572
+ {
3573
+ "input": {
3574
+ "env": {
3575
+ "DB_PASSWORD": "FAKEfake",
3576
+ "NPM_TOKEN": "FAKE0000fake",
3577
+ "NODE_ENV": "production"
3578
+ }
3579
+ },
3580
+ "output": {
3581
+ "env": {
3582
+ "DB_PASSWORD": "[redacted:password]",
3583
+ "NPM_TOKEN": "[redacted:token]",
3584
+ "NODE_ENV": "production"
3585
+ }
3586
+ }
3587
+ },
3588
+ {
3589
+ "input": {
3590
+ "githubToken": "FAKEfake",
3591
+ "dbPassword": "p",
3592
+ "x-api-key": "FAKE"
3593
+ },
3594
+ "output": {
3595
+ "githubToken": "[redacted:token]",
3596
+ "dbPassword": "[redacted:password]",
3597
+ "x-api-key": "[redacted:token]"
3598
+ }
3599
+ },
3600
+ {
3601
+ "input": {
3602
+ "private_key": "FAKEfakeFAKE",
3603
+ "AWS_ACCESS_KEY": "FAKEfake",
3604
+ "GITHUB_CLIENT_SECRET": "FAKEfake"
3605
+ },
3606
+ "output": {
3607
+ "private_key": "[redacted:private-key]",
3608
+ "AWS_ACCESS_KEY": "[redacted:access-key]",
3609
+ "GITHUB_CLIENT_SECRET": "[redacted:secret]"
3610
+ }
3611
+ },
3612
+ {
3613
+ "input": {
3614
+ "headers": {
3615
+ "Authorization": "Basic dXNlcjpwYXNz"
3616
+ },
3617
+ "auth": "FAKEfakeFAKE",
3618
+ "credentials": "user:FAKEpass"
3619
+ },
3620
+ "output": {
3621
+ "headers": {
3622
+ "Authorization": "[redacted:auth]"
3623
+ },
3624
+ "auth": "[redacted:auth]",
3625
+ "credentials": "[redacted:credentials]"
3626
+ }
3627
+ },
3628
+ {
3629
+ "input": [
3630
+ {
3631
+ "passwd": "FAKEfake"
3632
+ },
3633
+ {
3634
+ "list": [
3635
+ {
3636
+ "secret": "FAKEfake"
3637
+ }
3638
+ ]
3639
+ }
3640
+ ],
3641
+ "output": [
3642
+ {
3643
+ "passwd": "[redacted:password]"
3644
+ },
3645
+ {
3646
+ "list": [
3647
+ {
3648
+ "secret": "[redacted:secret]"
3649
+ }
3650
+ ]
3651
+ }
3652
+ ]
3653
+ },
3654
+ {
3655
+ "input": {
3656
+ "password": "hunter",
3657
+ "DB_PASSWORD": "abc",
3658
+ "pwd": "x",
3659
+ "passphrase": "required"
3660
+ },
3661
+ "output": {
3662
+ "password": "[redacted:password]",
3663
+ "DB_PASSWORD": "[redacted:password]",
3664
+ "pwd": "[redacted:password]",
3665
+ "passphrase": "[redacted:password]"
3666
+ }
3667
+ },
3668
+ {
3669
+ "input": {
3670
+ "credentials": {
3671
+ "user": "alice",
3672
+ "pass": "hunter2"
3673
+ },
3674
+ "apiToken": [
3675
+ "FAKEfake0000"
3676
+ ],
3677
+ "auth": {
3678
+ "mode": "oauth"
3679
+ }
3680
+ },
3681
+ "output": {
3682
+ "credentials": {
3683
+ "user": "[redacted:credentials]",
3684
+ "pass": "[redacted:credentials]"
3685
+ },
3686
+ "apiToken": [
3687
+ "[redacted:token]"
3688
+ ],
3689
+ "auth": {
3690
+ "mode": "oauth"
3691
+ }
3692
+ }
3693
+ }
3694
+ ],
3695
+ "negative": [
3696
+ {
3697
+ "tokens": 4096,
3698
+ "token_count": 3,
3699
+ "maxTokens": 8000,
3700
+ "max_tokens": 4096,
3701
+ "tokensEst": "52k"
3702
+ },
3703
+ {
3704
+ "token": null,
3705
+ "password": "",
3706
+ "secret": " ",
3707
+ "auth": {
3708
+ "type": "oauth"
3709
+ }
3710
+ },
3711
+ {
3712
+ "password": "${DB_PASSWORD}",
3713
+ "token": "<your token>",
3714
+ "secret": "process.env.SECRET",
3715
+ "apiKey": "{{api_key}}",
3716
+ "NPM_TOKEN": "$(cat ~/.npmrc)"
3717
+ },
3718
+ {
3719
+ "password": "********",
3720
+ "token": "[redacted:token]",
3721
+ "secret": "xxx",
3722
+ "auth": "required",
3723
+ "authorization": "Bearer"
3724
+ },
3725
+ {
3726
+ "passwordPolicy": "min 12 chars",
3727
+ "secretSanta": "true",
3728
+ "authMode": "oauth",
3729
+ "author": "Ashish",
3730
+ "credentialsPath": "creds.json",
3731
+ "keyId": "abc",
3732
+ "tokenizer": "cl100k",
3733
+ "PASSWORD_MIN_LENGTH": "12",
3734
+ "TOKEN_LIMIT": "8000",
3735
+ "SECRET_SANTA": "yes"
3736
+ },
3737
+ {
3738
+ "password": "${DB_PASSWORD}",
3739
+ "DB_PASSWORD": "$DB_PASSWORD",
3740
+ "pwd": "<password>",
3741
+ "passwd": "changeme-placeholder",
3742
+ "passphrase": "none",
3743
+ "PASSWORD_MIN_LENGTH": 12,
3744
+ "password_min_length": "12",
3745
+ "passwordMinLength": "12"
3746
+ }
3747
+ ]
3748
+ },
3749
+ "nonSecretWords": {
3750
+ "regex": "^(?:required|optional|enabled|disabled|true|false|oauth2?|basic|bearer)$",
3751
+ "flags": "i",
3752
+ "note": "not a secret for every family except a strict one (password), where any non-placeholder value goes"
3753
+ }
3754
+ },
3755
+ "v1Withhold": {
3756
+ "note": "compatibility check only: v1 withheld any item matching this pattern; every sample is a real secret v1 withheld, and v2 must redact each so the v1 pattern no longer matches",
3757
+ "pattern": "-----BEGIN [A-Z ]*KEY-----|\\bBearer\\s+[A-Za-z0-9._~+/=-]{16,}|\\bsk-[A-Za-z0-9_-]{16,}|\\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}|\\bgithub_pat_[A-Za-z0-9_]{20,}|\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}|(?:api[_-]?key|access[_-]?token|client[_-]?secret|password)\\s*[:=]\\s*\\S+",
3758
+ "flags": "i",
3759
+ "samples": [
3760
+ {
3761
+ "text": "-----BEGIN RSA PRIVATE KEY-----\nMIIEFAKE\n-----END RSA PRIVATE KEY-----",
3762
+ "secret": "MIIEFAKE"
3763
+ },
3764
+ {
3765
+ "text": "-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaFAKE",
3766
+ "secret": "b3BlbnNzaFAKE"
3767
+ },
3768
+ {
3769
+ "text": "Authorization: Bearer FAKEfakeFAKEfake0000",
3770
+ "secret": "FAKEfakeFAKEfake0000"
3771
+ },
3772
+ {
3773
+ "text": "sk-ant-api03-FAKEfakeFAKEfake0000",
3774
+ "secret": "FAKEfakeFAKEfake0000"
3775
+ },
3776
+ {
3777
+ "text": "sk-proj-FAKEfakeFAKEfake0000",
3778
+ "secret": "FAKEfakeFAKEfake0000"
3779
+ },
3780
+ {
3781
+ "text": "ghp_FAKEfakeFAKEfakeFAKEfake0000",
3782
+ "secret": "FAKEfakeFAKEfakeFAKEfake0000"
3783
+ },
3784
+ {
3785
+ "text": "gho_FAKEfakeFAKEfakeFAKEfake0000",
3786
+ "secret": "FAKEfakeFAKEfakeFAKEfake0000"
3787
+ },
3788
+ {
3789
+ "text": "ghu_FAKEfakeFAKEfakeFAKEfake0000",
3790
+ "secret": "FAKEfakeFAKEfakeFAKEfake0000"
3791
+ },
3792
+ {
3793
+ "text": "ghs_FAKEfakeFAKEfakeFAKEfake0000",
3794
+ "secret": "FAKEfakeFAKEfakeFAKEfake0000"
3795
+ },
3796
+ {
3797
+ "text": "ghr_FAKEfakeFAKEfakeFAKEfake0000",
3798
+ "secret": "FAKEfakeFAKEfakeFAKEfake0000"
3799
+ },
3800
+ {
3801
+ "text": "github_pat_11FAKEFAKE0_FAKEfakeFAKEfakeFAKE",
3802
+ "secret": "FAKEfakeFAKEfakeFAKE"
3803
+ },
3804
+ {
3805
+ "text": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJmYWtlIn0.FAKEfakeFAKEfake",
3806
+ "secret": "FAKEfakeFAKEfake"
3807
+ },
3808
+ {
3809
+ "text": "api_key=FAKE0000fake",
3810
+ "secret": "FAKE0000fake"
3811
+ },
3812
+ {
3813
+ "text": "API-KEY: \"FAKEfakeFAKE\"",
3814
+ "secret": "FAKEfakeFAKE"
3815
+ },
3816
+ {
3817
+ "text": "apikey=FAKE0000fake",
3818
+ "secret": "FAKE0000fake"
3819
+ },
3820
+ {
3821
+ "text": "OPENWEATHER_API_KEY=FAKE0000fake",
3822
+ "secret": "FAKE0000fake"
3823
+ },
3824
+ {
3825
+ "text": "access_token=FAKEfake0000",
3826
+ "secret": "FAKEfake0000"
3827
+ },
3828
+ {
3829
+ "text": "ACCESS-TOKEN: FAKEfake0000",
3830
+ "secret": "FAKEfake0000"
3831
+ },
3832
+ {
3833
+ "text": "access_token: \"FAKEfakeFAKE\"",
3834
+ "secret": "FAKEfakeFAKE"
3835
+ },
3836
+ {
3837
+ "text": "client_secret: FAKEfake0000",
3838
+ "secret": "FAKEfake0000"
3839
+ },
3840
+ {
3841
+ "text": "GITHUB_CLIENT_SECRET=FAKEfake0000",
3842
+ "secret": "FAKEfake0000"
3843
+ },
3844
+ {
3845
+ "text": "client-secret='FAKEfakeFAKE'",
3846
+ "secret": "FAKEfakeFAKE"
3847
+ },
3848
+ {
3849
+ "text": "password=hunter22",
3850
+ "secret": "hunter22"
3851
+ },
3852
+ {
3853
+ "text": "DB_PASSWORD=hunter22",
3854
+ "secret": "hunter22"
3855
+ },
3856
+ {
3857
+ "text": "MYSQL_ROOT_PASSWORD=\"FAKEfake\"",
3858
+ "secret": "FAKEfake"
3859
+ },
3860
+ {
3861
+ "text": "export DB_PASSWORD=FAKEfake0000",
3862
+ "secret": "FAKEfake0000"
3863
+ },
3864
+ {
3865
+ "text": "password=correcthorsebattery",
3866
+ "secret": "correcthorsebattery"
3867
+ },
3868
+ {
3869
+ "text": "password=hunter",
3870
+ "secret": "hunter"
3871
+ },
3872
+ {
3873
+ "text": "password=sunflowerxy",
3874
+ "secret": "sunflowerxy"
3875
+ },
3876
+ {
3877
+ "text": "password=abc12",
3878
+ "secret": "abc12"
3879
+ },
3880
+ {
3881
+ "text": "password=x",
3882
+ "secret": "=x"
3883
+ },
3884
+ {
3885
+ "text": "password=\"abc\"",
3886
+ "secret": "\"abc\""
3887
+ },
3888
+ {
3889
+ "text": "PASSWORD : dragon",
3890
+ "secret": "dragon"
3891
+ },
3892
+ {
3893
+ "text": "password: \"letmein\"",
3894
+ "secret": "letmein"
3895
+ },
3896
+ {
3897
+ "text": "api_key=abcdefgh",
3898
+ "secret": "abcdefgh"
3899
+ },
3900
+ {
3901
+ "text": "access_token: short",
3902
+ "secret": "short"
3903
+ },
3904
+ {
3905
+ "text": "client_secret=abc",
3906
+ "secret": "=abc"
3907
+ }
3908
+ ],
3909
+ "knownGaps": {
3910
+ "note": "not redacted by v2 (architect, backlog CONN-SEC-02). A sample v1 withheld (v1: true) is now withheld by the v1 gate (privacy.v1Gate), so it never uploads; the passes alone keep `kept`. A sample v1 did not withhold (v1: false: CLI flag forms, a markdown table cell) uploads with `kept`. The v1 ones: public keys; a password value with a comma or a semicolon, whose part after it v2 keeps (statement scoping); a continuation line after a value (a shell backslash continuation, an indented INI continuation); and the one-line block-marker forms (password: > x, password: | x, a Unicode line separator), which are not valid YAML",
3911
+ "backlog": "CONN-SEC-02",
3912
+ "samples": [
3913
+ {
3914
+ "text": "-----BEGIN PUBLIC KEY-----",
3915
+ "kept": "BEGIN PUBLIC KEY",
3916
+ "v1": true
3917
+ },
3918
+ {
3919
+ "text": "password=hun,ter2",
3920
+ "kept": "ter2",
3921
+ "v1": true
3922
+ },
3923
+ {
3924
+ "text": "password=hun;ter2",
3925
+ "kept": "ter2",
3926
+ "v1": true
3927
+ },
3928
+ {
3929
+ "text": "export DB_PASSWORD=hunter2\\\nZq9vLm",
3930
+ "kept": "Zq9vLm",
3931
+ "v1": true
3932
+ },
3933
+ {
3934
+ "text": "password = hunter2\n Zq9vLm",
3935
+ "kept": "Zq9vLm",
3936
+ "v1": true
3937
+ },
3938
+ {
3939
+ "text": "password: > hunter2",
3940
+ "kept": "hunter2",
3941
+ "v1": true
3942
+ },
3943
+ {
3944
+ "text": "password: | hunter2",
3945
+ "kept": "hunter2",
3946
+ "v1": true
3947
+ },
3948
+ {
3949
+ "text": "password: |
 hunter2",
3950
+ "kept": "hunter2",
3951
+ "v1": true
3952
+ },
3953
+ {
3954
+ "text": "| password | hunter2 |",
3955
+ "kept": "hunter2",
3956
+ "v1": false
3957
+ },
3958
+ {
3959
+ "text": "--password hunter2",
3960
+ "kept": "hunter2",
3961
+ "v1": false
3962
+ },
3963
+ {
3964
+ "text": "mysql -u root -p hunter2",
3965
+ "kept": "hunter2",
3966
+ "v1": false
3967
+ },
3968
+ {
3969
+ "text": "--token abc123xyz",
3970
+ "kept": "abc123xyz",
3971
+ "v1": false
3972
+ },
3973
+ {
3974
+ "text": "curl -u admin:hunter2 https://x",
3975
+ "kept": "hunter2",
3976
+ "v1": false
3977
+ },
3978
+ {
3979
+ "text": "IDENTIFIED BY 'hunter2'",
3980
+ "kept": "hunter2",
3981
+ "v1": false
3982
+ }
3983
+ ]
3984
+ }
3985
+ },
3986
+ "v1Gate": {
3987
+ "note": "runs last, on every string, on both sides (architect 05:52, ruled 11:23): delete every marker, then test v1Withhold.pattern unchanged on what is left. A match withholds the item as content_withheld (the string becomes the withheld marker), so v2 never uploads what v1 would have withheld. A marker is deleted with the quotes around it, if any, so a quoted value that v2 redacted (\"[redacted:password]\") leaves nothing for v1's \\S+ to match. Deleting markers lets v1's \\s*\\S+ reach what follows a redacted value, on the same line or a later one: a partial redaction is withheld, and so is any text after a redacted v1 key",
3988
+ "markers": {
3989
+ "regex": "([\"'\\x60]?)\\[redacted:[A-Za-z0-9-]{1,40}\\]\\1",
3990
+ "flags": "g"
3991
+ },
3992
+ "samples": {
3993
+ "note": "withheld: v1GateFires is true and the item is withheld; clean: the gate stays silent",
3994
+ "withheld": [
3995
+ "config password: [redacted:password]\n hunter2",
3996
+ "password: [redacted:password] hunter2",
3997
+ "password=[redacted:password],ter2",
3998
+ "password: \"[redacted:password]\" hunter2",
3999
+ "password: [redacted:password]\nuser: bob",
4000
+ "Password: min length"
4001
+ ],
4002
+ "clean": [
4003
+ "password=[redacted:password]",
4004
+ "password: [redacted:password]",
4005
+ "password: \"[redacted:password]\"",
4006
+ "DB_PASSWORD='[redacted:password]'",
4007
+ "{\"password\": \"[redacted:password]\", \"user\": \"bob\"}",
4008
+ "access_token: [redacted:token]\n",
4009
+ "the token budget is large",
4010
+ "PASSWORD_MIN_LENGTH=12"
4011
+ ]
4012
+ }
4013
+ },
4014
+ "lineNet": {
4015
+ "note": "after the table, on each line (text up to the next line end: \\r\\n, a bare \\r or \\n) that names a secret-style key: every quoted literal (\"…\", '…', `…`) that is not a placeholder, and every unquoted value after = or : in the statement of such a key (up to the next ; or ,), takes the net replacement; lines without such a key are untouched",
4016
+ "families": [
4017
+ "password",
4018
+ "token",
4019
+ "secret",
4020
+ "private-key",
4021
+ "access-key",
4022
+ "credentials"
4023
+ ],
4024
+ "replacement": "[redacted:secret-line]",
4025
+ "key": {
4026
+ "regex": "(?<!\\[redacted:[A-Za-z0-9-]{0,40})(?<![A-Za-z0-9])(?:[A-Za-z0-9]{1,40}[_-]){0,6}[A-Za-z0-9]{0,40}(?:password|passwd|pwd|passphrase|token|access[_-]?token|refresh[_-]?token|auth[_-]?token|api[_-]?key|apikey|secret|client[_-]?secret|secret[_-]?key|private[_-]?key|access[_-]?key|credentials?|creds)(?![A-Za-z0-9_-])",
4027
+ "flags": "i",
4028
+ "note": "a key name of the password, token, secret, api key or credential families with NAME_ or camelCase prefixes; a name inside a [redacted:…] marker does not count, and PASSWORD_MIN_LENGTH or tokenCount is not a key"
4029
+ },
4030
+ "scope": {
4031
+ "regex": "(?<!\\[redacted:[A-Za-z0-9-]{0,40})(?<![A-Za-z0-9])(?:[A-Za-z0-9]{1,40}[_-]){0,6}[A-Za-z0-9]{0,40}(?:password|passwd|pwd|passphrase|token|access[_-]?token|refresh[_-]?token|auth[_-]?token|api[_-]?key|apikey|secret|client[_-]?secret|secret[_-]?key|private[_-]?key|access[_-]?key|credentials?|creds)(?![A-Za-z0-9_-])[^;,\\r\\n]{0,2000}",
4032
+ "flags": "gi",
4033
+ "note": "the statement of each key, up to the next ; or ,: value runs inside it, literal runs on the whole line"
4034
+ },
4035
+ "literal": {
4036
+ "regex": "(?<skip>(?:(?<![A-Za-z0-9])|(?<=(?<![A-Za-z0-9])[fFrRbBuU]{1,2}))(?:(?<pe>\\\\)|(?<!\\\\))(?<pq>[\"'\\x60])(?:\\*{2,}|[xX]{3,}|•{2,}|\\.{3,}|…|<[^>\\r\\n]{0,100}>|\\$\\{[^}\\r\\n]{0,100}\\}|\\$\\([^)\\r\\n]{0,200}\\)|\\$[A-Za-z_][A-Za-z0-9_]{0,100}|%[A-Za-z_][A-Za-z0-9_]{0,100}%|\\{\\{[^}\\r\\n]{0,100}\\}\\}|\\[redacted[^\\]\\r\\n]{0,60}\\]|(?:process\\.env|os\\.environ|env)[.\\[][^\\s\"'\\r\\n]{0,100}|changeme(?:[-_][A-Za-z0-9]{1,40})?|placeholder|(?:your|enter)[-_][A-Za-z0-9_-]{1,40}|redacted|null|undefined|none)\\k<pe>\\k<pq>|(?<=[{,]\\s{0,5})(?:(?<![A-Za-z0-9])|(?<=(?<![A-Za-z0-9])[fFrRbBuU]{1,2}))(?:(?<ke>\\\\)|(?<!\\\\))(?<kq>[\"'\\x60])(?:(?!\\k<ke>\\k<kq>)(?:\\\\[^\\r\\n]|[^\\\\\\n\\r])){1,500}\\k<ke>\\k<kq>(?=\\s{0,5}:(?!:)))|(?<keep>(?:(?<![A-Za-z0-9])|(?<=(?<![A-Za-z0-9])[fFrRbBuU]{1,2}))(?:(?<e>\\\\)|(?<!\\\\))(?<q>[\"'\\x60]))(?:(?!\\k<e>\\k<q>)(?:\\\\[^\\r\\n]|[^\\\\\\n\\r])){1,500}(?<tail>\\k<e>\\k<q>)(?![A-Za-z0-9])",
4037
+ "flags": "gi",
4038
+ "note": "any quoted literal on the line except a placeholder and a JSON key ({\"name\": …}), which match as group skip and are kept as they are; an escaped quote opens an escaped literal (\\\"…\\\"), a quote after a backslash or inside a word (don't) opens none"
4039
+ },
4040
+ "value": {
4041
+ "regex": "(?<keep>(?<=[A-Za-z_$\\])\"'\\x60?]\\s{0,5})(?<![=!<>:]|\\[redacted)(?::=|=>|:(?![:=])|=(?![=>]))\\s{0,5})(?!=|\\\\[\"'\\x60])(?:(?<=[:=>])|(?<=\\s)(?!(?:in|is|to|the|a|an|and|or|of|for|on|with|from|via|field|flag|here|at|as|be|by|if|it|this|that|must|should|will|can|was|are|not|no|required|optional|min|max|minimum|maximum|length|policy|reset|strength|rules?|hint|prompt|input)\\s+[A-Za-z.]))(?!(?:string|number|boolean|any|unknown|object|never|void)(?:\\[\\])?(?![^\\s;,)|])(?![^;\\r\\n]{0,300}(?<![=!<>:])=(?![=>])))(?!(?:\\*{2,}|[xX]{3,}|•{2,}|\\.{3,}|…|<[^>\\r\\n]{0,100}>|\\$\\{[^}\\r\\n]{0,100}\\}|\\$\\([^)\\r\\n]{0,200}\\)|\\$[A-Za-z_][A-Za-z0-9_]{0,100}|%[A-Za-z_][A-Za-z0-9_]{0,100}%|\\{\\{[^}\\r\\n]{0,100}\\}\\}|\\[redacted[^\\]\\r\\n]{0,60}\\]|(?:process\\.env|os\\.environ|env)[.\\[][^\\s\"'\\r\\n]{0,100}|changeme(?:[-_][A-Za-z0-9]{1,40})?|placeholder|(?:your|enter)[-_][A-Za-z0-9_-]{1,40}|redacted|null|undefined|none)(?![^\\s,;\"'\\x60(){}<>\\[\\]]))[^\\s,;\"'\\x60(){}<>\\[\\]]{1,200}(?![^\\s,;\"'\\x60(){}<>\\[\\]])(?!\\s{0,3}[=!<>]=)",
4042
+ "flags": "gi",
4043
+ "note": "applied inside each scope; the guards are the ones a literal cannot satisfy: placeholders, comparisons, prose, and a type annotation with no = after it"
4044
+ },
4045
+ "samples": {
4046
+ "positive": [
4047
+ {
4048
+ "input": "password: string = \"hunter2\";",
4049
+ "output": "password: [redacted:password] = \"[redacted:secret-line]\";"
4050
+ },
4051
+ {
4052
+ "input": "const password: string = 'hunter2'",
4053
+ "output": "const password: [redacted:password] = '[redacted:secret-line]'"
4054
+ },
4055
+ {
4056
+ "input": "dbPassword: string = \"hunter2\";",
4057
+ "output": "dbPassword: [redacted:password] = \"[redacted:secret-line]\";"
4058
+ },
4059
+ {
4060
+ "input": "this.password = password + \"hunter2\";",
4061
+ "output": "this.password = [redacted:password] + \"[redacted:secret-line]\";"
4062
+ },
4063
+ {
4064
+ "input": "const apiToken = `Bearer ${token}`;",
4065
+ "output": "const apiToken = `[redacted:secret-line]`;"
4066
+ },
4067
+ {
4068
+ "input": "x = cond ? \"hunter2\" : password;",
4069
+ "output": "x = cond ? \"[redacted:secret-line]\" : password;"
4070
+ },
4071
+ {
4072
+ "input": "{\"password\": \"x\", \"user\": \"bob\"}",
4073
+ "output": "{\"password\": \"[redacted:password]\", \"user\": \"[redacted:secret-line]\"}"
4074
+ },
4075
+ {
4076
+ "input": "{\\\"password\\\":\\\"hunter2\\\",\\\"user\\\":\\\"bob\\\"}",
4077
+ "output": "{\\\"password\\\":\\\"[redacted:secret-line]\\\",\\\"user\\\":\\\"[redacted:secret-line]\\\"}"
4078
+ },
4079
+ {
4080
+ "input": "credentials = load(); user: alice",
4081
+ "output": "credentials = [redacted:secret-line](); user: alice"
4082
+ },
4083
+ {
4084
+ "input": "credentials: string = hunter2 // \"note\"",
4085
+ "output": "credentials: [redacted:secret-line] = [redacted:secret-line] // \"[redacted:secret-line]\""
4086
+ },
4087
+ {
4088
+ "input": "secret: string = s3cr3t;",
4089
+ "output": "secret: [redacted:secret-line] = [redacted:secret-line];"
4090
+ }
4091
+ ],
4092
+ "negative": [
4093
+ "the token budget",
4094
+ "Password: min length",
4095
+ "password: string;",
4096
+ "password?: string",
4097
+ "if (password === input)",
4098
+ "password: \"${PW}\"",
4099
+ "token: \"[redacted:token]\"",
4100
+ "const user = \"alice\";",
4101
+ "don't share it, it's private",
4102
+ "PASSWORD_MIN_LENGTH=12",
4103
+ "tokenCount: 3",
4104
+ "cd $PWD"
4105
+ ]
4106
+ },
4107
+ "block": {
4108
+ "note": "runs first, before the table: a secret-style key whose value opens a block is redacted to the end of the block, so no line of it reaches the table or the line net; a value whose end is not found within maxChars (or before the end of the string) withholds the whole item as content_withheld. The v1 gate (privacy.v1Gate) runs after every pass",
4109
+ "lineEnds": "\\r\\n, a bare \\r and \\n each end a line: after an opener, in the indentation and end of a YAML block, at a heredoc terminator and a continuation, and for whether a quote spans lines. A replacement that stands for whole lines ends with the line end of the line before it, so CRLF and CR text redacts exactly as its LF form",
4110
+ "open": {
4111
+ "regex": "(?<lo>(?<![*_\\x60])(?:\\*{1,3}|_{1,3}|\\x60))?(?<!\\[redacted:[A-Za-z0-9-]{0,40})(?<![A-Za-z0-9])(?:[A-Za-z0-9]{1,40}[_-]){0,6}[A-Za-z0-9]{0,40}(?:password|passwd|pwd|passphrase|token|access[_-]?token|refresh[_-]?token|auth[_-]?token|api[_-]?key|apikey|secret|client[_-]?secret|secret[_-]?key|private[_-]?key|access[_-]?key|credentials?|creds)(?![A-Za-z0-9_-])(?<lc>\\*{1,3}|_{1,3}|\\x60)?(?<kq>[\"']?)[ \\t]{0,5}(?:=>|:=|:(?![:=])|=(?![=>]))(?<le>(?:\\*{1,3}|_{1,3}|\\x60)(?=[ \\t\\r\\n]|$))?[ \\t]{0,5}(?<value>(?<yaml>[|>][1-9+-]{0,2}|)[ \\t]{0,40}(?:#[^\\r\\n]{0,200})?(?=[\\r\\n])|(?<heredoc>(?:\\$\\([ \\t]{0,5}cat[ \\t]{1,5})?<<[-~]?[ \\t]{0,5}(?<hq>['\"]?)(?<tag>[A-Za-z_][A-Za-z0-9_]{0,40})\\k<hq>)|(?<cont>\\\\)(?=[\\r\\n])|(?<close>\"\"\"|'''|[\"'\\x60])(?![\"'\\x60]{0,2}\\[redacted:)|(?<run>)(?=[^\\s,;\"'\\x60(){}<>\\[\\]]{201})|(?<inline>)(?=[^\\r\\n]))",
4112
+ "flags": "gi",
4113
+ "kinds": {
4114
+ "yaml": "a YAML block scalar (| or > with an indent or chomping indicator) or an empty value (: or = with nothing after it), wherever the key sits on its line (after indentation, a list dash, prose, markdown, a YAML parent key, code): the following lines indented deeper than the key line's own indentation, blank lines included; it ends at the first non-blank line indented no deeper. Blockquotes count: when the key line opens with > markers (up to maxQuoteDepth), a following line carrying the same markers is measured after them, and a line without them against the key line's own indentation. Replaced by one line with the first content line's lead (its indentation and quote markers). With no deeper line, a marker opens nothing; an empty value falls through to fence and label",
4115
+ "heredoc": "a shell heredoc (<<EOF, <<-EOF, <<~EOF, <<'EOF', $(cat <<EOF): the lines after the opener up to the line that, trimmed, is the tag (or the tag and a closing parenthesis); replaced by one line",
4116
+ "cont": "a trailing backslash: the next line, and the one after while each ends in a backslash",
4117
+ "close": "a quote (\"…\", '…', `…`, \"\"\"…\"\"\", '''…'''): up to the matching close (a backslash escapes the next character inside a single quote); a block when it spans lines, is longer than maxInline or is triple-quoted, otherwise left to the table and the line net. Not an opener when the key sits inside a literal of that quote opened earlier on its line (input(\"Password: \")), the key's own quotes (group kq) aside",
4118
+ "run": "an unquoted value longer than maxInline: the run of value characters",
4119
+ "fence": "after an empty value with no deeper line: when the next non-blank line (after the key line's quote markers) opens a fence (fence regex), the lines up to the closing fence (the same character, at least as many, nothing else) are replaced by one line; a fence with no close is not bounded",
4120
+ "label": "a markdown label: the key wrapped in emphasis (groups lo and lc or le: **k:**, **k**:, __k:__, *k:*, `k:`, `k`:). Its value is the rest of its line (group inline) or, for an empty value with no deeper line and no fence, the next non-blank line's text after its lead; replaced unless it is a placeholder (secretKeys.placeholder). Group inline matches only to give a label its same-line value; for any other key it opens nothing"
4121
+ }
4122
+ },
4123
+ "fence": {
4124
+ "regex": "^(`{3,}|~{3,})",
4125
+ "note": "a fence opening, matched on a line's trimmed text after its quote markers"
4126
+ },
4127
+ "maxQuoteDepth": 10,
4128
+ "run": {
4129
+ "regex": "[^\\s,;\"'\\x60(){}<>\\[\\]]{0,16001}",
4130
+ "flags": "y"
4131
+ },
4132
+ "maxChars": 16000,
4133
+ "maxInline": 200,
4134
+ "replacement": "[redacted:secret-block]",
4135
+ "withheld": "[redacted:withheld]",
4136
+ "failClosed": "a block with no end within maxChars, or one that runs to the end of the string, is not bounded: the text keeps everything before the value and ends in the withheld marker, and the item it is in is withheld as content_withheld (v1 behaviour); the connector counts it once per item in its redaction total",
4137
+ "samples": {
4138
+ "positive": [
4139
+ {
4140
+ "input": "password = \"hunter2\ncontinued\"\nnext = 1",
4141
+ "output": "password = \"[redacted:secret-block]\"\nnext = 1"
4142
+ },
4143
+ {
4144
+ "input": "password = \"\"\"\nhunter2\n\"\"\"\nnext = 1",
4145
+ "output": "password = \"\"\"[redacted:secret-block]\"\"\"\nnext = 1"
4146
+ },
4147
+ {
4148
+ "input": "password: |\n hunter2\n Zq9vLm\nuser: bob",
4149
+ "output": "password: [redacted:password]\n [redacted:secret-block]\nuser: bob"
4150
+ },
4151
+ {
4152
+ "input": "password: >-\n hunter2\nuser: bob",
4153
+ "output": "password: >-\n [redacted:secret-block]\nuser: bob"
4154
+ },
4155
+ {
4156
+ "input": "- client_secret:\n hunter2\n- next",
4157
+ "output": "- client_secret:\n [redacted:secret-block]\n- next"
4158
+ },
4159
+ {
4160
+ "input": "secret = <<~EOS\n hunter2\nEOS\nnext",
4161
+ "output": "secret = <<~EOS\n[redacted:secret-block]\nEOS\nnext"
4162
+ },
4163
+ {
4164
+ "input": "token: \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"",
4165
+ "output": "token: \"[redacted:secret-block]\""
4166
+ },
4167
+ {
4168
+ "input": "password: |\r\n hunter2\r\n Zq9vLm\r\nuser: bob",
4169
+ "output": "password: [redacted:password]\r\n [redacted:secret-block]\r\nuser: bob"
4170
+ },
4171
+ {
4172
+ "input": "db:\r\n password:\r\n hunter2\r\n host: x",
4173
+ "output": "db:\r\n password:\r\n [redacted:secret-block]\r\n host: x"
4174
+ },
4175
+ {
4176
+ "input": "secret: >-\r hunter2\rother: 1",
4177
+ "output": "secret: >-\r [redacted:secret-block]\rother: 1"
4178
+ },
4179
+ {
4180
+ "input": "secret = <<~EOS\r hunter2\rEOS\rnext",
4181
+ "output": "secret = <<~EOS\r[redacted:secret-block]\rEOS\rnext"
4182
+ },
4183
+ {
4184
+ "input": "config password: |\n XXprose\nnext: 1",
4185
+ "output": "config password: [redacted:password]\n [redacted:secret-block]\nnext: 1"
4186
+ },
4187
+ {
4188
+ "input": "> password: |\n> hunter2\n> user: bob",
4189
+ "output": "> password: [redacted:password]\n> [redacted:secret-block]\n> user: bob"
4190
+ },
4191
+ {
4192
+ "input": "yaml-crlf: password: |\r\n value\r\nuser: bob",
4193
+ "output": "yaml-crlf: password: [redacted:password]\r\n [redacted:secret-block]\r\nuser: bob"
4194
+ },
4195
+ {
4196
+ "input": "**Password:** hunter2",
4197
+ "output": "**Password:** [redacted:secret-block]"
4198
+ },
4199
+ {
4200
+ "input": "> **api_key:**\n> hunter2\n> next",
4201
+ "output": "> **api_key:**\n> [redacted:secret-block]\n> next"
4202
+ },
4203
+ {
4204
+ "input": "password:\n```\nhunter2\n```\nnext",
4205
+ "output": "password:\n```\n[redacted:secret-block]\n```\nnext"
4206
+ },
4207
+ {
4208
+ "input": "Here is the config: token: >-\n hunter2\nnext: 1",
4209
+ "output": "Here is the config: token: >-\n [redacted:secret-block]\nnext: 1"
4210
+ },
4211
+ {
4212
+ "input": "config password =\n hunter2\nnext",
4213
+ "output": "config password =\n [redacted:secret-block]\nnext"
4214
+ },
4215
+ {
4216
+ "input": "**Password**: hunter2",
4217
+ "output": "**Password**: [redacted:secret-block]"
4218
+ }
4219
+ ],
4220
+ "withheld": [
4221
+ "password = \"hunter2\ncontinued",
4222
+ "password: |\n hunter2",
4223
+ "password=<<EOF\nhunter2",
4224
+ "api_key = '''\nhunter2",
4225
+ "password: |\r\n hunter2",
4226
+ "password: |\r hunter2",
4227
+ "password=<<EOF\rhunter2",
4228
+ "config password: |\n XXprose\n",
4229
+ "password:\n```\nhunter2"
4230
+ ],
4231
+ "note": "positive outputs are the passes' result (block pass, table, line net), before the v1 gate; each withheld sample yields text ending in the withheld marker, as does any keyed value longer than maxChars; the block pass alone leaves each negative as it is; the samples with \\r\\n and \\r line ends redact as their LF forms",
4232
+ "negative": [
4233
+ "password: |\nuser: bob",
4234
+ "password = \"x\"",
4235
+ "the token:\nnext line",
4236
+ "password: [redacted:password]\n [redacted:secret-block]",
4237
+ "password = input(\"Password: \")\nprint(1)",
4238
+ "log('token: ', value)\nnext",
4239
+ "password: |\r\nuser: bob",
4240
+ "the token:\r\nnext line",
4241
+ "password = input(\"Password: \")\r\nprint(1)",
4242
+ "**Note:** the token budget\nnext",
4243
+ "**Password policy:** min 12\nnext",
4244
+ "description: >\n The password policy is strict\nnext: 1",
4245
+ "the token budget: |\n 1000\nnext"
4246
+ ]
4247
+ }
4248
+ }
4249
+ }
4250
+ },
4251
+ "response": {
4252
+ "status": 200,
4253
+ "body": {
4254
+ "accepted": "integer: items written or tombstoned",
4255
+ "unchanged": "integer: replays and stale items, not written",
4256
+ "rejected": "array of { kind, externalId, error, message } for items refused one by one",
4257
+ "cursor": "string: the change cursor after this batch",
4258
+ "ignored": "integer: data fields the contract does not know, dropped from accepted items",
4259
+ "redacted": "integer: secret-table matches replaced on ingest in the items this batch wrote; an unchanged or stale item adds nothing, so a retried batch reports 0",
4260
+ "contractAccepts": "string: the handshake range, as in the response header"
4261
+ },
4262
+ "itemErrors": [
4263
+ "invalid_item",
4264
+ "item_too_large",
4265
+ "path_not_redacted",
4266
+ "content_withheld"
4267
+ ]
4268
+ },
4269
+ "errors": {
4270
+ "400": [
4271
+ "invalid_json",
4272
+ "invalid_mirror_batch",
4273
+ "invalid_policy_version",
4274
+ "invalid_id"
4275
+ ],
4276
+ "401": [
4277
+ "bearer_required",
4278
+ "caller_unknown"
4279
+ ],
4280
+ "403": [
4281
+ "insufficient_scope",
4282
+ "machine_unknown",
4283
+ "machine_revoked",
4284
+ "machine_forbidden"
4285
+ ],
4286
+ "409": [
4287
+ "session_invalid",
4288
+ "policy_stale",
4289
+ "contract_unsupported"
4290
+ ],
4291
+ "413": [
4292
+ "payload_too_large",
4293
+ "mirror_quota"
4294
+ ],
4295
+ "429": [
4296
+ "rate_limited"
4297
+ ]
4298
+ }
4299
+ }