instar 1.3.620 → 1.3.622
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard/subscriptions.js +3 -1
- package/dist/commands/server.js +4 -2
- package/dist/commands/server.js.map +1 -1
- package/dist/monitoring/CompactionSentinel.d.ts +11 -6
- package/dist/monitoring/CompactionSentinel.d.ts.map +1 -1
- package/dist/monitoring/CompactionSentinel.js +32 -7
- package/dist/monitoring/CompactionSentinel.js.map +1 -1
- package/dist/server/AgentServer.d.ts +20 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +116 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +41 -2
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.621.md +22 -0
- package/upgrades/1.3.622.md +26 -0
- package/upgrades/side-effects/compaction-sentinel-no-trample.md +52 -0
- package/upgrades/side-effects/ws52-enroll-seams.md +71 -0
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-18T23:22:31.986Z",
|
|
5
|
+
"instarVersion": "1.3.622",
|
|
6
6
|
"entryCount": 201,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -418,7 +418,7 @@
|
|
|
418
418
|
"type": "route-group",
|
|
419
419
|
"domain": "monitoring",
|
|
420
420
|
"sourcePath": "src/server/routes.ts",
|
|
421
|
-
"contentHash": "
|
|
421
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
422
422
|
"since": "2025-01-01"
|
|
423
423
|
},
|
|
424
424
|
"route-group:agents": {
|
|
@@ -426,7 +426,7 @@
|
|
|
426
426
|
"type": "route-group",
|
|
427
427
|
"domain": "sessions",
|
|
428
428
|
"sourcePath": "src/server/routes.ts",
|
|
429
|
-
"contentHash": "
|
|
429
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
430
430
|
"since": "2025-01-01"
|
|
431
431
|
},
|
|
432
432
|
"route-group:backups": {
|
|
@@ -434,7 +434,7 @@
|
|
|
434
434
|
"type": "route-group",
|
|
435
435
|
"domain": "operations",
|
|
436
436
|
"sourcePath": "src/server/routes.ts",
|
|
437
|
-
"contentHash": "
|
|
437
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
438
438
|
"since": "2025-01-01"
|
|
439
439
|
},
|
|
440
440
|
"route-group:git": {
|
|
@@ -442,7 +442,7 @@
|
|
|
442
442
|
"type": "route-group",
|
|
443
443
|
"domain": "coordination",
|
|
444
444
|
"sourcePath": "src/server/routes.ts",
|
|
445
|
-
"contentHash": "
|
|
445
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
446
446
|
"since": "2025-01-01"
|
|
447
447
|
},
|
|
448
448
|
"route-group:memory": {
|
|
@@ -450,7 +450,7 @@
|
|
|
450
450
|
"type": "route-group",
|
|
451
451
|
"domain": "memory",
|
|
452
452
|
"sourcePath": "src/server/routes.ts",
|
|
453
|
-
"contentHash": "
|
|
453
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
454
454
|
"since": "2025-01-01"
|
|
455
455
|
},
|
|
456
456
|
"route-group:semantic": {
|
|
@@ -458,7 +458,7 @@
|
|
|
458
458
|
"type": "route-group",
|
|
459
459
|
"domain": "memory",
|
|
460
460
|
"sourcePath": "src/server/routes.ts",
|
|
461
|
-
"contentHash": "
|
|
461
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
462
462
|
"since": "2025-01-01"
|
|
463
463
|
},
|
|
464
464
|
"route-group:status": {
|
|
@@ -466,7 +466,7 @@
|
|
|
466
466
|
"type": "route-group",
|
|
467
467
|
"domain": "monitoring",
|
|
468
468
|
"sourcePath": "src/server/routes.ts",
|
|
469
|
-
"contentHash": "
|
|
469
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
470
470
|
"since": "2025-01-01"
|
|
471
471
|
},
|
|
472
472
|
"route-group:capabilities": {
|
|
@@ -474,7 +474,7 @@
|
|
|
474
474
|
"type": "route-group",
|
|
475
475
|
"domain": "mapping",
|
|
476
476
|
"sourcePath": "src/server/routes.ts",
|
|
477
|
-
"contentHash": "
|
|
477
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
478
478
|
"since": "2025-01-01"
|
|
479
479
|
},
|
|
480
480
|
"route-group:project-map": {
|
|
@@ -482,7 +482,7 @@
|
|
|
482
482
|
"type": "route-group",
|
|
483
483
|
"domain": "mapping",
|
|
484
484
|
"sourcePath": "src/server/routes.ts",
|
|
485
|
-
"contentHash": "
|
|
485
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
486
486
|
"since": "2025-01-01"
|
|
487
487
|
},
|
|
488
488
|
"route-group:coherence": {
|
|
@@ -490,7 +490,7 @@
|
|
|
490
490
|
"type": "route-group",
|
|
491
491
|
"domain": "coherence",
|
|
492
492
|
"sourcePath": "src/server/routes.ts",
|
|
493
|
-
"contentHash": "
|
|
493
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
494
494
|
"since": "2025-01-01"
|
|
495
495
|
},
|
|
496
496
|
"route-group:topic-bindings": {
|
|
@@ -498,7 +498,7 @@
|
|
|
498
498
|
"type": "route-group",
|
|
499
499
|
"domain": "sessions",
|
|
500
500
|
"sourcePath": "src/server/routes.ts",
|
|
501
|
-
"contentHash": "
|
|
501
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
502
502
|
"since": "2025-01-01"
|
|
503
503
|
},
|
|
504
504
|
"route-group:context": {
|
|
@@ -506,7 +506,7 @@
|
|
|
506
506
|
"type": "route-group",
|
|
507
507
|
"domain": "context",
|
|
508
508
|
"sourcePath": "src/server/routes.ts",
|
|
509
|
-
"contentHash": "
|
|
509
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
510
510
|
"since": "2025-01-01"
|
|
511
511
|
},
|
|
512
512
|
"route-group:scope-coherence": {
|
|
@@ -514,7 +514,7 @@
|
|
|
514
514
|
"type": "route-group",
|
|
515
515
|
"domain": "coherence",
|
|
516
516
|
"sourcePath": "src/server/routes.ts",
|
|
517
|
-
"contentHash": "
|
|
517
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
518
518
|
"since": "2025-01-01"
|
|
519
519
|
},
|
|
520
520
|
"route-group:canonical-state": {
|
|
@@ -522,7 +522,7 @@
|
|
|
522
522
|
"type": "route-group",
|
|
523
523
|
"domain": "state",
|
|
524
524
|
"sourcePath": "src/server/routes.ts",
|
|
525
|
-
"contentHash": "
|
|
525
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
526
526
|
"since": "2025-01-01"
|
|
527
527
|
},
|
|
528
528
|
"route-group:ci": {
|
|
@@ -530,7 +530,7 @@
|
|
|
530
530
|
"type": "route-group",
|
|
531
531
|
"domain": "monitoring",
|
|
532
532
|
"sourcePath": "src/server/routes.ts",
|
|
533
|
-
"contentHash": "
|
|
533
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
534
534
|
"since": "2025-01-01"
|
|
535
535
|
},
|
|
536
536
|
"route-group:sessions": {
|
|
@@ -538,7 +538,7 @@
|
|
|
538
538
|
"type": "route-group",
|
|
539
539
|
"domain": "sessions",
|
|
540
540
|
"sourcePath": "src/server/routes.ts",
|
|
541
|
-
"contentHash": "
|
|
541
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
542
542
|
"since": "2025-01-01"
|
|
543
543
|
},
|
|
544
544
|
"route-group:jobs": {
|
|
@@ -546,7 +546,7 @@
|
|
|
546
546
|
"type": "route-group",
|
|
547
547
|
"domain": "scheduling",
|
|
548
548
|
"sourcePath": "src/server/routes.ts",
|
|
549
|
-
"contentHash": "
|
|
549
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
550
550
|
"since": "2025-01-01"
|
|
551
551
|
},
|
|
552
552
|
"route-group:skip-ledger": {
|
|
@@ -554,7 +554,7 @@
|
|
|
554
554
|
"type": "route-group",
|
|
555
555
|
"domain": "scheduling",
|
|
556
556
|
"sourcePath": "src/server/routes.ts",
|
|
557
|
-
"contentHash": "
|
|
557
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
558
558
|
"since": "2025-01-01"
|
|
559
559
|
},
|
|
560
560
|
"route-group:telegram": {
|
|
@@ -562,7 +562,7 @@
|
|
|
562
562
|
"type": "route-group",
|
|
563
563
|
"domain": "communication",
|
|
564
564
|
"sourcePath": "src/server/routes.ts",
|
|
565
|
-
"contentHash": "
|
|
565
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
566
566
|
"since": "2025-01-01"
|
|
567
567
|
},
|
|
568
568
|
"route-group:attention": {
|
|
@@ -570,7 +570,7 @@
|
|
|
570
570
|
"type": "route-group",
|
|
571
571
|
"domain": "communication",
|
|
572
572
|
"sourcePath": "src/server/routes.ts",
|
|
573
|
-
"contentHash": "
|
|
573
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
574
574
|
"since": "2025-01-01"
|
|
575
575
|
},
|
|
576
576
|
"route-group:relationships": {
|
|
@@ -578,7 +578,7 @@
|
|
|
578
578
|
"type": "route-group",
|
|
579
579
|
"domain": "relationships",
|
|
580
580
|
"sourcePath": "src/server/routes.ts",
|
|
581
|
-
"contentHash": "
|
|
581
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
582
582
|
"since": "2025-01-01"
|
|
583
583
|
},
|
|
584
584
|
"route-group:feedback": {
|
|
@@ -586,7 +586,7 @@
|
|
|
586
586
|
"type": "route-group",
|
|
587
587
|
"domain": "feedback",
|
|
588
588
|
"sourcePath": "src/server/routes.ts",
|
|
589
|
-
"contentHash": "
|
|
589
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
590
590
|
"since": "2025-01-01"
|
|
591
591
|
},
|
|
592
592
|
"route-group:updates": {
|
|
@@ -594,7 +594,7 @@
|
|
|
594
594
|
"type": "route-group",
|
|
595
595
|
"domain": "updates",
|
|
596
596
|
"sourcePath": "src/server/routes.ts",
|
|
597
|
-
"contentHash": "
|
|
597
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
598
598
|
"since": "2025-01-01"
|
|
599
599
|
},
|
|
600
600
|
"route-group:dispatches": {
|
|
@@ -602,7 +602,7 @@
|
|
|
602
602
|
"type": "route-group",
|
|
603
603
|
"domain": "dispatches",
|
|
604
604
|
"sourcePath": "src/server/routes.ts",
|
|
605
|
-
"contentHash": "
|
|
605
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
606
606
|
"since": "2025-01-01"
|
|
607
607
|
},
|
|
608
608
|
"route-group:quota": {
|
|
@@ -610,7 +610,7 @@
|
|
|
610
610
|
"type": "route-group",
|
|
611
611
|
"domain": "monitoring",
|
|
612
612
|
"sourcePath": "src/server/routes.ts",
|
|
613
|
-
"contentHash": "
|
|
613
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
614
614
|
"since": "2025-01-01"
|
|
615
615
|
},
|
|
616
616
|
"route-group:publishing": {
|
|
@@ -618,7 +618,7 @@
|
|
|
618
618
|
"type": "route-group",
|
|
619
619
|
"domain": "publishing",
|
|
620
620
|
"sourcePath": "src/server/routes.ts",
|
|
621
|
-
"contentHash": "
|
|
621
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
622
622
|
"since": "2025-01-01"
|
|
623
623
|
},
|
|
624
624
|
"route-group:private-views": {
|
|
@@ -626,7 +626,7 @@
|
|
|
626
626
|
"type": "route-group",
|
|
627
627
|
"domain": "publishing",
|
|
628
628
|
"sourcePath": "src/server/routes.ts",
|
|
629
|
-
"contentHash": "
|
|
629
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
630
630
|
"since": "2025-01-01"
|
|
631
631
|
},
|
|
632
632
|
"route-group:tunnel": {
|
|
@@ -634,7 +634,7 @@
|
|
|
634
634
|
"type": "route-group",
|
|
635
635
|
"domain": "networking",
|
|
636
636
|
"sourcePath": "src/server/routes.ts",
|
|
637
|
-
"contentHash": "
|
|
637
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
638
638
|
"since": "2025-01-01"
|
|
639
639
|
},
|
|
640
640
|
"route-group:events": {
|
|
@@ -642,7 +642,7 @@
|
|
|
642
642
|
"type": "route-group",
|
|
643
643
|
"domain": "networking",
|
|
644
644
|
"sourcePath": "src/server/routes.ts",
|
|
645
|
-
"contentHash": "
|
|
645
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
646
646
|
"since": "2025-01-01"
|
|
647
647
|
},
|
|
648
648
|
"route-group:evolution": {
|
|
@@ -650,7 +650,7 @@
|
|
|
650
650
|
"type": "route-group",
|
|
651
651
|
"domain": "evolution",
|
|
652
652
|
"sourcePath": "src/server/routes.ts",
|
|
653
|
-
"contentHash": "
|
|
653
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
654
654
|
"since": "2025-01-01"
|
|
655
655
|
},
|
|
656
656
|
"route-group:watchdog": {
|
|
@@ -658,7 +658,7 @@
|
|
|
658
658
|
"type": "route-group",
|
|
659
659
|
"domain": "monitoring",
|
|
660
660
|
"sourcePath": "src/server/routes.ts",
|
|
661
|
-
"contentHash": "
|
|
661
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
662
662
|
"since": "2025-01-01"
|
|
663
663
|
},
|
|
664
664
|
"route-group:topic-memory": {
|
|
@@ -666,7 +666,7 @@
|
|
|
666
666
|
"type": "route-group",
|
|
667
667
|
"domain": "memory",
|
|
668
668
|
"sourcePath": "src/server/routes.ts",
|
|
669
|
-
"contentHash": "
|
|
669
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
670
670
|
"since": "2025-01-01"
|
|
671
671
|
},
|
|
672
672
|
"route-group:state-sync": {
|
|
@@ -674,7 +674,7 @@
|
|
|
674
674
|
"type": "route-group",
|
|
675
675
|
"domain": "coordination",
|
|
676
676
|
"sourcePath": "src/server/routes.ts",
|
|
677
|
-
"contentHash": "
|
|
677
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
678
678
|
"since": "2025-01-01"
|
|
679
679
|
},
|
|
680
680
|
"route-group:intent": {
|
|
@@ -682,7 +682,7 @@
|
|
|
682
682
|
"type": "route-group",
|
|
683
683
|
"domain": "intent",
|
|
684
684
|
"sourcePath": "src/server/routes.ts",
|
|
685
|
-
"contentHash": "
|
|
685
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
686
686
|
"since": "2025-01-01"
|
|
687
687
|
},
|
|
688
688
|
"route-group:triage": {
|
|
@@ -690,7 +690,7 @@
|
|
|
690
690
|
"type": "route-group",
|
|
691
691
|
"domain": "safety",
|
|
692
692
|
"sourcePath": "src/server/routes.ts",
|
|
693
|
-
"contentHash": "
|
|
693
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
694
694
|
"since": "2025-01-01"
|
|
695
695
|
},
|
|
696
696
|
"route-group:operations": {
|
|
@@ -698,7 +698,7 @@
|
|
|
698
698
|
"type": "route-group",
|
|
699
699
|
"domain": "safety",
|
|
700
700
|
"sourcePath": "src/server/routes.ts",
|
|
701
|
-
"contentHash": "
|
|
701
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
702
702
|
"since": "2025-01-01"
|
|
703
703
|
},
|
|
704
704
|
"route-group:sentinel": {
|
|
@@ -706,7 +706,7 @@
|
|
|
706
706
|
"type": "route-group",
|
|
707
707
|
"domain": "safety",
|
|
708
708
|
"sourcePath": "src/server/routes.ts",
|
|
709
|
-
"contentHash": "
|
|
709
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
710
710
|
"since": "2025-01-01"
|
|
711
711
|
},
|
|
712
712
|
"route-group:trust": {
|
|
@@ -714,7 +714,7 @@
|
|
|
714
714
|
"type": "route-group",
|
|
715
715
|
"domain": "safety",
|
|
716
716
|
"sourcePath": "src/server/routes.ts",
|
|
717
|
-
"contentHash": "
|
|
717
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
718
718
|
"since": "2025-01-01"
|
|
719
719
|
},
|
|
720
720
|
"route-group:monitoring": {
|
|
@@ -722,7 +722,7 @@
|
|
|
722
722
|
"type": "route-group",
|
|
723
723
|
"domain": "monitoring",
|
|
724
724
|
"sourcePath": "src/server/routes.ts",
|
|
725
|
-
"contentHash": "
|
|
725
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
726
726
|
"since": "2025-01-01"
|
|
727
727
|
},
|
|
728
728
|
"route-group:commitments": {
|
|
@@ -730,7 +730,7 @@
|
|
|
730
730
|
"type": "route-group",
|
|
731
731
|
"domain": "commitments",
|
|
732
732
|
"sourcePath": "src/server/routes.ts",
|
|
733
|
-
"contentHash": "
|
|
733
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
734
734
|
"since": "2025-01-01"
|
|
735
735
|
},
|
|
736
736
|
"route-group:episodes": {
|
|
@@ -738,7 +738,7 @@
|
|
|
738
738
|
"type": "route-group",
|
|
739
739
|
"domain": "memory",
|
|
740
740
|
"sourcePath": "src/server/routes.ts",
|
|
741
|
-
"contentHash": "
|
|
741
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
742
742
|
"since": "2025-01-01"
|
|
743
743
|
},
|
|
744
744
|
"route-group:messages": {
|
|
@@ -746,7 +746,7 @@
|
|
|
746
746
|
"type": "route-group",
|
|
747
747
|
"domain": "coordination",
|
|
748
748
|
"sourcePath": "src/server/routes.ts",
|
|
749
|
-
"contentHash": "
|
|
749
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
750
750
|
"since": "2025-01-01"
|
|
751
751
|
},
|
|
752
752
|
"route-group:system-reviews": {
|
|
@@ -754,7 +754,7 @@
|
|
|
754
754
|
"type": "route-group",
|
|
755
755
|
"domain": "monitoring",
|
|
756
756
|
"sourcePath": "src/server/routes.ts",
|
|
757
|
-
"contentHash": "
|
|
757
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
758
758
|
"since": "2025-01-01"
|
|
759
759
|
},
|
|
760
760
|
"route-group:machine-mesh": {
|
|
@@ -770,7 +770,7 @@
|
|
|
770
770
|
"type": "route-group",
|
|
771
771
|
"domain": "security",
|
|
772
772
|
"sourcePath": "src/server/routes.ts",
|
|
773
|
-
"contentHash": "
|
|
773
|
+
"contentHash": "a68a3c72eac278d5e5a7d0264e60a7a925e9e5df4ac0c428456525b64535e746",
|
|
774
774
|
"since": "2025-01-01"
|
|
775
775
|
},
|
|
776
776
|
"cli:init": {
|
|
@@ -1522,7 +1522,7 @@
|
|
|
1522
1522
|
"type": "subsystem",
|
|
1523
1523
|
"domain": "server",
|
|
1524
1524
|
"sourcePath": "src/server/AgentServer.ts",
|
|
1525
|
-
"contentHash": "
|
|
1525
|
+
"contentHash": "805647440853ee9d8d4a2472a51bc883ef4524a1dcf2dec5c29e0438a8b9e71a",
|
|
1526
1526
|
"since": "2025-01-01"
|
|
1527
1527
|
},
|
|
1528
1528
|
"subsystem:session-manager": {
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Fixes the recurring mid-turn interrupt of long sessions (the "Claude was interrupted" / "[Request interrupted by user]" you'd see on a long autonomous run). Root cause: the CompactionSentinel's recovery guard deferred a resume-nudge while a session was actively working, but only for ~4 minutes (`maxWorkingDefers`); after that it force-injected the nudge **even if the session was still actively working**, interrupting the live turn. On a long session that compacts periodically, it fired repeatedly. Now, when the defer budget is exhausted but the session is still actively working, the sentinel **stands down** (the session is alive and self-recovered — no nudge needed) instead of force-injecting. The genuinely-frozen-footer case is already owned by the silence/context-wedge sentinels. The `maxWorkingDefers: 0` opt-out (inject-immediately) is preserved.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
If you ever saw your long-running session get "interrupted" out of nowhere, that's fixed. An internal recovery watchdog was occasionally nudging sessions that were actually still working, which interrupted them. It now leaves a working session alone.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
- No new capability — a reliability fix. The compaction-recovery watchdog no longer interrupts a session that is still actively working; it stands down instead of forcing a resume nudge.
|
|
17
|
+
|
|
18
|
+
## Evidence
|
|
19
|
+
|
|
20
|
+
- `tests/unit/CompactionSentinel.test.ts` — 24/24 pass. Updated the old "caps defers then forces an inject" test to assert STAND-DOWN, and added a dedicated regression test that fails if a still-working session is ever force-injected again.
|
|
21
|
+
- `npx tsc --noEmit` clean.
|
|
22
|
+
- Root cause evidenced in `logs/sentinel-events.jsonl`: `"resume nudge injected via internal recovery channel"` + `"no jsonl growth after 6 attempts"`.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Makes the account-follow-me proof work end-to-end. Driving it as the operator exposed that tapping Approve issued + delivered the mandate to the target machine, but three seams were unwired so nothing happened after ("machine logging in now" then silence). Wired all three:
|
|
9
|
+
|
|
10
|
+
1. **Delivered-mandate consumer** — a boot-sweep + 60s tick on the target machine walks the delivered-mandate store and drives the real enroll-start route for each approved mandate not already pending/enrolled. Idempotent (survives restart), authority-free (the route still enforces every gate).
|
|
11
|
+
2. **Peer-view email resolution** — `accountFollowMePeerViews` now uses the working peer-resolution path (`resolvePeerUrls`) instead of an empty field, so the target can resolve the approved account's email (fixes the `409 "cannot resolve approved account email"`).
|
|
12
|
+
3. **Pending-login surfacing** — `GET /subscription-pool/pending-logins?scope=pool` merges peers' pending logins (dark-peer-tolerant), and the dashboard polls it pool-scope, so a login created on another machine surfaces on the operator's single dashboard.
|
|
13
|
+
|
|
14
|
+
## What to Tell Your User
|
|
15
|
+
|
|
16
|
+
The "let another machine use this subscription" flow now actually completes: tap Approve, and the other machine starts its login and the link shows up on your dashboard for you to tap. Before this, Approve issued the approval but nothing carried it through.
|
|
17
|
+
|
|
18
|
+
## Summary of New Capabilities
|
|
19
|
+
|
|
20
|
+
- Account-follow-me works end-to-end: Approve → the target machine enrolls itself → its login link surfaces on your single dashboard. Dark on fleet / live on the dev agent (unchanged gate).
|
|
21
|
+
|
|
22
|
+
## Evidence
|
|
23
|
+
|
|
24
|
+
- `tests/integration/pending-logins-pool-merge.test.ts` (NEW, 3 tests) — verifies the `?scope=pool` merge tags logins by machine, tolerates a dark peer (no 500), and leaves the default local-only path unchanged.
|
|
25
|
+
- All existing follow-me / enroll-start / scan / delivered-mandate / resolve / peer-view tests green (no regressions); `tsc --noEmit` clean.
|
|
26
|
+
- The full Approve→enroll→login-link flow driven on the real two-machine setup before release (Live-User-Channel-Proof).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Side-Effects Review — CompactionSentinel: stand down instead of trampling a working session
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `compaction-sentinel-no-trample`
|
|
4
|
+
**Date:** `2026-06-18`
|
|
5
|
+
**Author:** `Echo (instar-dev agent)`
|
|
6
|
+
**Second-pass reviewer:** `required (sentinel/recovery change) — appended below`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Fixes the recurring mid-turn interrupt of long autonomous sessions ("[Request interrupted by user]"). Root cause: `CompactionSentinel.deferForActiveWork` deferred a recovery resume-nudge while the session was actively working, but only up to `maxWorkingDefers` (~4min); once exhausted it returned `false`, and the caller **force-injected the resume nudge even though the session was still actively working** — interrupting the live turn. On a 23h session that compacts periodically, this fired repeatedly. The fix: when the defer budget is exhausted but `isActivelyWorking` is STILL true, the sentinel **stands down** (emits `compaction:recovered`, finalizes — a session demonstrably alive + working has already self-recovered and needs no nudge) instead of force-injecting. The explicit `maxWorkingDefers === 0` opt-out (inject-immediately-even-while-working) is preserved. File: `src/monitoring/CompactionSentinel.ts` (one guard method). Test: `tests/unit/CompactionSentinel.test.ts` (updated the old "force inject after cap" test to assert stand-down; added a dedicated stand-down regression test; 24 tests pass).
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
- `CompactionSentinel.deferForActiveWork` — **modify** — when budget exhausted AND still actively working: stand down (no inject) instead of returning false (which force-injected). The `not actively working` path and the `maxWorkingDefers === 0` opt-out are unchanged.
|
|
14
|
+
|
|
15
|
+
## 1. Over-block
|
|
16
|
+
Not a block/allow surface. The change makes the sentinel inject LESS (a de-escalation). The only "rejection" added: it now declines to inject a recovery nudge into a still-working session — which is the entire point (that inject was the defect).
|
|
17
|
+
|
|
18
|
+
## 2. Under-block
|
|
19
|
+
The one scenario the old force-inject targeted — a session whose tmux footer FALSELY shows "working" while truly hung — is no longer force-recovered by THIS sentinel. That case is covered by the frozen-frame detectors (ActiveWorkSilenceSentinel, ContextWedgeSentinel, SessionWatchdog), which use frame-change/socket signals rather than the footer boolean. So the genuinely-hung case still has recovery owners; this sentinel simply stops trampling genuinely-working sessions.
|
|
20
|
+
|
|
21
|
+
## 3. Level-of-abstraction fit
|
|
22
|
+
Correct layer — the fix is in the guard that already exists for exactly this purpose (`deferForActiveWork`). It uses the same `isActivelyWorking` (live-tmux-frame) signal already wired; no new detection added.
|
|
23
|
+
|
|
24
|
+
## 4. Signal vs authority compliance
|
|
25
|
+
**Required reference:** docs/signal-vs-authority.md
|
|
26
|
+
- [x] Yes, with appropriate de-escalation: the sentinel holds runtime authority (it injects into sessions). This change REDUCES that authority (it stops acting on working sessions). Strictly safer direction — never adds a brittle block; it removes a brittle action.
|
|
27
|
+
|
|
28
|
+
## 5. Interactions
|
|
29
|
+
- **Shadowing:** none changed. The other recovery sentinels are unaffected and now solely own the falsely-working-footer case (no double-recovery with this one).
|
|
30
|
+
- **Double-fire:** reduced (this sentinel no longer fires into working sessions that the autonomous stop-hook is already re-driving).
|
|
31
|
+
- **Races:** the stand-down calls `finalize(state,'recovered')` which keeps state briefly for the recovery-guard window (existing behavior), so the zombie-killer veto timing is unchanged.
|
|
32
|
+
|
|
33
|
+
## 6. External surfaces
|
|
34
|
+
No operator surface, no API, no message shape change. The only external-visible effect: long sessions stop being interrupted mid-turn. A `compaction:recovered` event now fires for the stand-down case (audited in `sentinel-events.jsonl`) — additive, no consumer breaks.
|
|
35
|
+
|
|
36
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
37
|
+
Machine-local BY DESIGN — the CompactionSentinel runs per-machine over that machine's own sessions (recovery is a local-process concern). No cross-machine state; the fix changes only local decision logic. Both machines get the fix via the normal deploy/update path.
|
|
38
|
+
|
|
39
|
+
## 8. Rollback cost
|
|
40
|
+
One-method revert, ship a patch. No persistent state, no migration, no operator action. Because the change is a pure de-escalation, even an un-noticed regression fails safe (worst case: a falsely-working-footer hung session waits for the other sentinels instead of this one).
|
|
41
|
+
|
|
42
|
+
## Conclusion
|
|
43
|
+
Small, well-scoped fix to the exact guard responsible for the recurring interrupt. De-escalation only; 24 unit tests pass incl. a new regression test that fails if a still-working session is ever force-injected again. Clear to ship pending the appended second-pass.
|
|
44
|
+
|
|
45
|
+
## Second-pass review (if required)
|
|
46
|
+
**Reviewer:** independent general-purpose reviewer subagent (read-only), 2026-06-18 — **CONCUR**
|
|
47
|
+
|
|
48
|
+
Verified against the actual code (cited file:line): (1) stand-down replaces force-inject — when `isActivelyWorking` && `workingDefers >= maxWorkingDefers`, emits `compaction:recovered` + `finalize('recovered')` + returns true; both callers (`attemptInjection:297`, `verifyRecovery:420`) bail before `recoverFn` — no inject. (2) `maxWorkingDefers === 0` opt-out preserved (early `return false` at :348 → inject). (3) not-working path unchanged (:345 → normal inject/retry/fail; genuinely-stuck still recovered). (4) no timer/state leak — stand-down routes through the same `finalize` terminal path; at every call site the per-session timer was already deleted; `isRecoveryActive` returns false in `recovered` so the zombie-veto releases. (5) strict de-escalation — `recoverFn` called strictly less; no new block/interrupt path. (6) coverage gap closed — the falsely-working-footer hung case is owned by ActiveWorkSilenceSentinel (frame-HASH change + frozen-indicator backstop) and ContextWedgeSentinel (transcript fast-fail signatures), which use orthogonal signals, so standing down here strands nothing. **No concerns.**
|
|
49
|
+
|
|
50
|
+
## Evidence pointers
|
|
51
|
+
- `tests/unit/CompactionSentinel.test.ts` — 24/24 pass; new "STANDS DOWN" test + updated cap test.
|
|
52
|
+
- `npx tsc --noEmit` clean.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Side-Effects Review — WS5.2: wire the 3 enroll seams (make the follow-me proof work end-to-end)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `ws52-enroll-seams`
|
|
4
|
+
**Date:** `2026-06-18`
|
|
5
|
+
**Author:** `Echo (instar-dev agent)`
|
|
6
|
+
**Second-pass reviewer:** `required (cross-machine + credential enrollment) — appended below`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Completes Part B of the approved `ws52-operator-tap-not-text` spec — the connector that turns an operator's Approve into an actual login on the target machine. Driving the proof as the operator (2026-06-18, topic 13481) exposed that Approve issued + delivered the mandate to the Mini fine, but THREE seams were unwired so nothing happened after ("machine logging in now" then silence). This wires all three:
|
|
11
|
+
|
|
12
|
+
- **Seam #1 — delivered-mandate consumer** (`src/server/AgentServer.ts`): a boot-sweep + 60s tick (`driveDeliveredFollowMeEnrollments`) walks the `DeliveredMandateStore` and, for each account-follow-me mandate not already pending/enrolled, self-POSTs the REAL `/subscription-pool/follow-me/enroll/start` route. Idempotent (skips accounts already in `pending-logins` or the pool — durable, survives restart) and authority-free (the route enforces the dev-gate + deny-by-default + point-of-use mandate re-verify). Re-entrancy-guarded; timer cleared on stop.
|
|
13
|
+
- **Seam #2 — peer-view email resolution** (`src/commands/server.ts`): `accountFollowMePeerViews` now sources peers from `_resolvePeerUrls()` (the working pool-scope path) instead of the empty `lastKnownUrl` — falling back to `lastKnownUrl`. This is what the `fetchPeerSubscriptionViews` doc comment always intended. Fixes the `409 "cannot resolve approved account email"` I hit driving enroll-start by hand.
|
|
14
|
+
- **Seam #3 — pending-login pool surfacing** (`src/server/routes.ts` + `dashboard/subscriptions.js`): `GET /subscription-pool/pending-logins?scope=pool` fans out to peers' local pending-logins and merges (tagged by machine, dark-peer-tolerant); the dashboard subscriptions controller now polls with `?scope=pool` so a login created on the Mini surfaces on the operator's single dashboard.
|
|
15
|
+
|
|
16
|
+
## Decision-point inventory
|
|
17
|
+
- `driveDeliveredFollowMeEnrollments` (AgentServer) — **add** — nudges the enroll-start route for delivered mandates; carries NO authority itself (route gates).
|
|
18
|
+
- `accountFollowMePeerViews` peer source (server.ts) — **modify** — resolvePeerUrls (working) vs lastKnownUrl (empty); fallback preserved.
|
|
19
|
+
- `GET /subscription-pool/pending-logins` — **modify** — adds an optional `?scope=pool` merged read; default (no scope) is byte-for-byte unchanged.
|
|
20
|
+
|
|
21
|
+
## 1. Over-block
|
|
22
|
+
No block/allow surface. The consumer only ADDS enroll attempts for mandates the operator already approved+delivered; it never blocks anything. It SKIPS already-pending/enrolled accounts (correct — prevents re-mint), which is the only "rejection" and is the desired idempotency.
|
|
23
|
+
|
|
24
|
+
## 2. Under-block
|
|
25
|
+
The consumer relies on the enroll-start route for all gating (dev-gate, deny-by-default, point-of-use mandate re-verify incl. revocation/expiry). It adds no new trust path — a delivered mandate that fails the route's re-verify still gets 403/409 and no login. The idempotency read (pending-logins + pool) is best-effort; a read failure could cause a redundant enroll-start attempt, but the route itself is the backstop (it re-verifies and the wizard's own pending-login dedup applies), so worst case is a logged retry, never a double-mint of a completed account.
|
|
26
|
+
|
|
27
|
+
## 3. Level-of-abstraction fit
|
|
28
|
+
Correct. Seam #1 is glue at the server layer (where the delivered store lives) that reuses the existing route rather than duplicating credential logic — the lowest-risk placement. Seam #2 swaps a data source to the one the rest of the pool-scope reads already use. Seam #3 mirrors the established `?scope=pool` fan-out pattern (`/sessions?scope=pool`).
|
|
29
|
+
|
|
30
|
+
## 4. Signal vs authority compliance
|
|
31
|
+
**Required reference:** docs/signal-vs-authority.md
|
|
32
|
+
- [x] No new brittle authority. The consumer is authority-free (it nudges a route that holds the real authority, deterministically gated). The route's authority is unchanged. Seam #3 is a read-merge. Strictly additive wiring; the failure direction is "no login produced" (safe), never "wrong login" — the email gate (S7) + point-of-use re-verify still hold.
|
|
33
|
+
|
|
34
|
+
## 5. Interactions
|
|
35
|
+
- **Shadowing:** the `?scope=pool` branch is gated on the query param; the default path is unchanged, so existing callers are unaffected.
|
|
36
|
+
- **Double-fire:** the consumer's pending/enrolled skip-set + the wizard's own pending dedup prevent re-driving; the re-entrancy guard prevents overlapping ticks.
|
|
37
|
+
- **Races:** the consumer reads the delivered store + self-GETs state each tick; a mandate mid-enroll shows a pending login → skipped next tick.
|
|
38
|
+
- **Self-call:** the consumer self-POSTs localhost with the agent's own authToken — same-process HTTP, no external surface.
|
|
39
|
+
|
|
40
|
+
## 6. External surfaces
|
|
41
|
+
- Operator dashboard now shows follow-me logins created on OTHER machines (the whole point). No secrets exposed — pending-logins carry only the device-code + verification URL (already the case; the merge just forwards them, machine-tagged).
|
|
42
|
+
- Peers are queried at their existing `/subscription-pool/pending-logins` with the agent's authToken (5s timeout, dark-peer-tolerant). No new endpoint exposed to the outside.
|
|
43
|
+
|
|
44
|
+
## 6b. Operator-surface quality
|
|
45
|
+
Touches `dashboard/subscriptions.js` (a one-line URL change to add `?scope=pool`). The rendered surface (the Pending Logins panel) is unchanged in shape — it now simply includes cross-machine logins. Leads with plain language, no raw internals, phone-width (unchanged). N/a for destructive actions.
|
|
46
|
+
|
|
47
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
48
|
+
This change EXISTS for multi-machine. Seam #1 is machine-local (each target drives its own delivered mandates). Seam #2 is proxied-on-read (resolvePeerUrls fan-out). Seam #3 is proxied-on-read (the `?scope=pool` merge), dark-peer-tolerant (classified failed entry, never a 500). The login link is the provider's own URL (machine-independent); it surfaces on the operator's single fronting dashboard. Single-machine install: consumer still runs (drives any local delivered mandate); `?scope=pool` returns just local (no peers) — no-op.
|
|
49
|
+
|
|
50
|
+
## 8. Rollback cost
|
|
51
|
+
Revert the commit; ship a patch. No persistent state shape change (uses existing DeliveredMandateStore + PendingLoginStore). The consumer is additive (stops nudging on revert); the `?scope=pool` branch is additive (default unchanged). Behind the existing dev-gate (dark on fleet) — blast radius is dev agents only.
|
|
52
|
+
|
|
53
|
+
## Conclusion
|
|
54
|
+
Wires the three seams that made the proof stall, reusing existing route authority (no new brittle gate), with idempotency that survives restart. tsc clean; new pool-merge integration test (3) + all existing follow-me/enroll route + resolve + peer-view tests green (no regressions). Clear to ship pending the appended second-pass. The TRUE verification — me driving Approve→consumer→enroll→login-link-surfaced on the real machines — is done before this reaches the operator (per the Live-User-Channel-Proof standard I violated last time).
|
|
55
|
+
|
|
56
|
+
## Second-pass review (if required)
|
|
57
|
+
**Reviewer:** independent general-purpose reviewer subagent (read-only), 2026-06-18 — **CONCUR**
|
|
58
|
+
|
|
59
|
+
Verified all 5 review points against real code (cited file:line): (1) consumer is authority-free (only self-POSTs the real enroll-start route which holds the dev-gate + deny-by-default mandate gate + R4a point-of-use re-verify + S7 email gate), idempotent (handled-set from local pending-logins+pool; PendingLogin.id keyed to accountId so the skip is sound; intra-tick handled.add), re-entrancy-guarded (followMeConsumerRunning, released in finally; serial awaited fetch makes a slow drive skip the next tick not overlap), inert without the store, no secret in logs. (2) seam #2 is a pure data-source swap to resolvePeerUrls (lastKnownUrl fallback, nickname mapped, [] when no peers, authToken unchanged). (3) seam #3 default no-scope path byte-identical; dark peers → classified failed entry never a 500 (AbortSignal.timeout 5s); only non-secret fields (device-code/verificationUrl/machine tags) cross; remote tagged. (4) strictly additive, fails toward "no login produced" — the consumer can't produce a wrong-account login because it passes only mandateId+accountId and the route independently re-derives the email + re-checks exact bounds. (5) no re-mint loop / double-enroll / route hang / auth / missing-await bug. One non-blocking note: the enroll-start self-call has no client-side timeout, which is intentional+safe (start() legitimately runs up to ~180s; the re-entrancy guard, not a timeout, correctly prevents pile-up; the route's EnrollmentDriveError returns a retryable 502 leaving no stuck pending-login). **No concerns.**
|
|
60
|
+
|
|
61
|
+
## Evidence pointers
|
|
62
|
+
- `npx tsc --noEmit` clean (full worktree).
|
|
63
|
+
- `tests/integration/pending-logins-pool-merge.test.ts` (NEW, 3) + subscription-enrollment-routes (5) + follow-me-controller-wiring (4) + scan/enroll-start/delivered-mandate route tests (14) + resolve-follow-me-enroll-target (6) + fetch-peer-subscription-views (5) — all green.
|
|
64
|
+
|
|
65
|
+
## Follow-up (CI fix, 2026-06-18)
|
|
66
|
+
|
|
67
|
+
CI surfaced two real issues from seam #3, both fixed: (1) the `?scope=pool` branch hardcoded `enabled:true`, which broke the dashboard's feature-dark detection (it needs `pending.enabled===false` alongside accounts) — now it mirrors local pool presence (`enabled: !!ctx.enrollmentWizard`), so a dark machine still reads disabled even while forwarding peers' logins; (2) the `subscriptions-tab` integration-test fetch mocks keyed the old `/subscription-pool/pending-logins` URL, but the controller now fetches `?scope=pool` — updated the mock keys. Verified: subscriptions-tab (5) + subscriptions-tab-lifecycle e2e (2) + pending-logins-pool-merge (3) + follow-me-controller-wiring (4) green; tsc clean.
|
|
68
|
+
|
|
69
|
+
## Follow-up (CI hang fix, 2026-06-18)
|
|
70
|
+
|
|
71
|
+
CI shard 4/4 hung ~1h46m — root cause in this change: the seam #1 consumer's `setTimeout` (boot-sweep) + `setInterval` (60s tick) in AgentServer were NOT `.unref()`'d, so a test that boots AgentServer kept the event loop alive (vitest hangs on the open handle). Fixed: `.unref()` both timers (matches the sibling pollers), and added `AbortSignal.timeout` to the consumer's self-fetches (5s on the idempotency reads, 200s on the enroll-start drive) so a wedged fetch can't hold the loop either. tsc clean.
|