instar 1.3.648 → 1.3.649
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/index.html +14 -14
- package/dist/core/AutoUpdater.d.ts.map +1 -1
- package/dist/core/AutoUpdater.js +23 -3
- package/dist/core/AutoUpdater.js.map +1 -1
- package/dist/core/UpdateChecker.d.ts +12 -0
- package/dist/core/UpdateChecker.d.ts.map +1 -1
- package/dist/core/UpdateChecker.js +22 -0
- package/dist/core/UpdateChecker.js.map +1 -1
- package/dist/monitoring/DegradationReporter.d.ts +18 -0
- package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
- package/dist/monitoring/DegradationReporter.js +24 -0
- package/dist/monitoring/DegradationReporter.js.map +1 -1
- package/dist/monitoring/WorktreeMonitor.d.ts +13 -6
- package/dist/monitoring/WorktreeMonitor.d.ts.map +1 -1
- package/dist/monitoring/WorktreeMonitor.js +50 -33
- package/dist/monitoring/WorktreeMonitor.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +8 -3
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +48 -48
- package/upgrades/1.3.649.md +30 -0
- package/upgrades/eli16/autoupdate-strand-detector.md +22 -0
- package/upgrades/eli16/dashboard-health-signal-polish.md +26 -0
- package/upgrades/eli16/worktree-monitor-async-git.md +24 -0
- package/upgrades/side-effects/autoupdate-strand-detector.md +36 -0
- package/upgrades/side-effects/dashboard-health-signal-polish.md +59 -0
- package/upgrades/side-effects/worktree-monitor-async-git.md +39 -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-23T04:36:48.669Z",
|
|
5
|
+
"instarVersion": "1.3.649",
|
|
6
6
|
"entryCount": 202,
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
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": "fba7ee802dbc21caf906ea9a2d63506294ac4425fcb68749ef258fcca82cbbab",
|
|
774
774
|
"since": "2025-01-01"
|
|
775
775
|
},
|
|
776
776
|
"cli:init": {
|
|
@@ -1546,7 +1546,7 @@
|
|
|
1546
1546
|
"type": "subsystem",
|
|
1547
1547
|
"domain": "updates",
|
|
1548
1548
|
"sourcePath": "src/core/AutoUpdater.ts",
|
|
1549
|
-
"contentHash": "
|
|
1549
|
+
"contentHash": "05e6333268bc74c2acb3b8af1f95d0bd59852f2d4c683826713305922947783d",
|
|
1550
1550
|
"since": "2025-01-01"
|
|
1551
1551
|
},
|
|
1552
1552
|
"subsystem:auto-dispatcher": {
|
|
@@ -1586,7 +1586,7 @@
|
|
|
1586
1586
|
"type": "subsystem",
|
|
1587
1587
|
"domain": "monitoring",
|
|
1588
1588
|
"sourcePath": "src/monitoring/DegradationReporter.ts",
|
|
1589
|
-
"contentHash": "
|
|
1589
|
+
"contentHash": "b3707ae0af774b35ab55d97a370c5c80d5ca0ab4af245ed62bf2bc925a9a65ff",
|
|
1590
1590
|
"since": "2025-01-01"
|
|
1591
1591
|
},
|
|
1592
1592
|
"subsystem:telegram-lifeline": {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Three small, pre-existing dashboard issues, found while verifying the dashboard-freeze fix (#1253). None affect the dashboard connection.
|
|
9
|
+
|
|
10
|
+
1. The dashboard polled the WhatsApp QR endpoint every 3s and never stopped when WhatsApp wasn't configured — the route answers 503, but the poll kept firing, piling ~20 console 503 errors/min into the browser for the whole session. It now stops the poll on the first 503.
|
|
11
|
+
2. A parse-time script block attached a WebSocket "message" listener to `ws` before `connectWebSocket()` had assigned it, so `ws` was null and `ws.onmessage` threw "Cannot read properties of null (reading 'onmessage')" on every page load (and the paste-panel refresh it enabled never actually worked). Paste handling moved into the main `handleMessage` switch — no more error, and it now survives reconnects.
|
|
12
|
+
3. The `/health` "Degraded" badge turned orange whenever any degradation event had ever been recorded, and those events never self-clear — so one transient/benign fallback pinned the badge red for the whole process lifetime even after recovery. `/health` now counts only degradations from the last 30 minutes (`DegradationReporter.getRecentEvents`); a persistent problem keeps re-reporting so it stays visible, a one-off ages out. An unparseable timestamp is kept (fail-safe). The full degradation log and the mark-reported path are unchanged, and on a Telegram agent the `status` field never gated restarts.
|
|
13
|
+
|
|
14
|
+
## What to Tell Your User
|
|
15
|
+
|
|
16
|
+
If your dashboard's health badge was stuck on "Degraded" even though everything looked fine, that's fixed — it now reflects current health and clears once a transient blip has passed (a real, ongoing problem still shows). You won't notice the other two fixes directly: they quietly remove browser-console noise and an on-load error. (A separate, deeper item — a "system review" panel showing days-old data because it never re-runs — is tracked separately.)
|
|
17
|
+
|
|
18
|
+
## Summary of New Capabilities
|
|
19
|
+
|
|
20
|
+
- `DegradationReporter.getRecentEvents(windowMs = 30min, now)` — a time-windowed view of degradation events. `/health` uses it for `status` + the reported count/summary, so the dashboard "Degraded" badge reflects CURRENT health rather than any-event-ever-recorded. The full append-only log (`getEvents`) and the mark-reported path are untouched.
|
|
21
|
+
- Dashboard: the WhatsApp QR poll stops on a 503 (adapter absent) — removes ~20 console 503s/min of noise.
|
|
22
|
+
- Dashboard: paste WebSocket events (`paste_delivered` / `paste_acknowledged`) are handled in the main message router — removes the on-load null-deref TypeError and makes the paste-panel refresh survive reconnects.
|
|
23
|
+
|
|
24
|
+
## Evidence
|
|
25
|
+
|
|
26
|
+
Observed live on this agent (Echo) while verifying #1253:
|
|
27
|
+
|
|
28
|
+
1. **WhatsApp poll spam** — Before: with no WhatsApp adapter configured, the browser console accumulated repeated `GET /whatsapp/qr 503` errors at the 3s poll cadence (~20/min) for the whole session. After: the poll stops on the first 503 (`stopWaPolling()`), so the console stays clean.
|
|
29
|
+
2. **On-load null deref** — Before: `Uncaught TypeError: Cannot read properties of null (reading 'onmessage')` fired at `dashboard:~9289` on every page load (the block ran at parse time, before `connectWebSocket()` assigned `ws`), and the paste-panel refresh it was meant to wire never ran. After: paste events are handled in `handleMessage`; the parse-time block is gone, so the load-time TypeError no longer occurs.
|
|
30
|
+
3. **Stuck "Degraded" badge** — Before: `curl /health` on a healthy box returned `{"status":"degraded","degradations":2,...}` where both events were a benign `"Stop event allowed without authority ruling … fail-open"` recorded earlier in the boot — never cleared, pinning the badge red. After (unit-proven, `tests/unit/degradation-reporter.test.ts`): `getRecentEvents()` returns only events within the 30-min window, so once those benign events age out `status` returns to `ok`; a re-reported (persistent) degradation stays inside the window and keeps the badge red.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ELI16 — Notice when an update silently fell off the truck
|
|
2
|
+
|
|
3
|
+
## The problem in plain words
|
|
4
|
+
|
|
5
|
+
Instar updates itself by installing the new version into a private folder (the "shadow install") and then restarting onto it. To avoid loops, it keeps a note: "I already applied version X." On each check, if that note matches the latest version, it shrugs and says "downloaded, just waiting for a restart."
|
|
6
|
+
|
|
7
|
+
But that note is just a *memory* — it's not the same as *checking the folder*. And the version number the program reports for itself is read once when it starts up and then cached, so it never notices if the folder changes underneath it.
|
|
8
|
+
|
|
9
|
+
So here's the failure: an update installs successfully (the folder now has the new version, the note says "applied X"). Then something knocks the folder back to the OLD version — for example, a crash-loop where two copies of the program fight, or a half-finished re-install. Now the note still says "I applied X," but X isn't actually in the folder anymore. The updater believes it's up to date, refuses to re-apply, and every time it checks it cheerfully reports "downloaded, waiting for a restart" — which is a lie. The agent is quietly stuck on the old version forever, and nobody can tell from the message.
|
|
10
|
+
|
|
11
|
+
This really happened: an agent got stranded on the old version while its note insisted it had the new one. It only got unstuck when a human manually re-installed.
|
|
12
|
+
|
|
13
|
+
## The fix
|
|
14
|
+
|
|
15
|
+
Add a way to read the *live* version straight from the folder on disk (uncached), and use it. When the updater is about to print "downloaded, waiting for a restart," it now first checks the folder. If the folder doesn't actually have the version the note claims, it knows it's stranded — so instead of the misleading "waiting for a restart" it prints a loud warning and sends one honest heads-up: "an update was recorded as installed but isn't actually on disk — I'm stuck on the old version and won't auto-update until this is re-applied. Nothing's broken, but I won't pick up new versions until it's fixed."
|
|
16
|
+
|
|
17
|
+
## What it does and doesn't do
|
|
18
|
+
|
|
19
|
+
- It does: catch the stranded state immediately and tell a human (and the logs) the truth, with the exact versions involved and how to re-apply.
|
|
20
|
+
- It doesn't (yet): automatically fix the strand by re-installing. That auto-repair is a deliberate follow-up, because re-installing on the critical update path can loop if the folder keeps getting knocked back, so it needs a careful retry limit and proper review. This change is the safe, observe-only first step: stop hiding the problem.
|
|
21
|
+
|
|
22
|
+
Low risk: it's a new read plus a corrected message; it only triggers on the genuine strand (a normal "applied, waiting for restart" never reaches it), and it's covered by tests.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ELI16 — Three small dashboard annoyances, cleaned up
|
|
2
|
+
|
|
3
|
+
## The problem in plain words
|
|
4
|
+
|
|
5
|
+
While fixing the big "dashboard keeps saying Disconnected" bug, I noticed three smaller, pre-existing issues. None of them break the connection — they're noise and one misleading light — but they're the kind of papercut that makes a healthy system look unwell.
|
|
6
|
+
|
|
7
|
+
**1. A button that never stopped knocking.** The dashboard checks "is WhatsApp set up?" every 3 seconds by pinging a WhatsApp address. If WhatsApp *isn't* set up (the normal case here), that address politely answers "not available" — but the dashboard kept asking anyway, forever. The result was about twenty error lines a minute piling up in the browser's hidden console. Harmless, but messy, and it buries real errors in the noise.
|
|
8
|
+
|
|
9
|
+
**2. An error thrown on every page load.** Tucked at the very end of the dashboard's code was a line that tried to hook into the live connection to refresh a small "paste" panel. But it ran *too early* — before the connection actually existed — so it tried to use something that wasn't there yet and threw a "can't read a property of nothing" error each time the page loaded. Worse, because it ran at the wrong moment, the paste-refresh it was supposed to enable never actually worked.
|
|
10
|
+
|
|
11
|
+
**3. A warning light stuck on.** At the top of the dashboard there's a little health badge: green "Healthy" or orange "Degraded". It turns orange if *anything* ever reported a hiccup. The catch: those hiccup reports are never erased. So one tiny, long-recovered blip would keep the badge orange for the entire time the server was running — telling you something's wrong when everything is actually fine.
|
|
12
|
+
|
|
13
|
+
## The fix
|
|
14
|
+
|
|
15
|
+
**1.** When the WhatsApp check gets the "not available" answer, stop checking. (If WhatsApp gets set up later, a page refresh starts it again.) The console noise is gone.
|
|
16
|
+
|
|
17
|
+
**2.** Move the paste-refresh handling into the dashboard's normal message router — the place that's always listening once the connection is live. That removes the early-run error *and* makes the paste-refresh actually work, even after the connection drops and comes back.
|
|
18
|
+
|
|
19
|
+
**3.** Make the health badge only count hiccups from the last 30 minutes. A real, ongoing problem keeps reporting itself, so it stays visible — but a one-off blip that recovered quietly ages out, and the badge goes back to green like it should. To be safe, a hiccup with a missing or garbled timestamp is always kept (better to show a maybe-stale warning than to hide a real one).
|
|
20
|
+
|
|
21
|
+
## What it does and doesn't do
|
|
22
|
+
|
|
23
|
+
- It does: silence the console spam, remove the on-load error (and revive the paste-refresh), and make the "Degraded" badge tell the truth about *current* health.
|
|
24
|
+
- It doesn't: change anything about restarts (on this agent the badge doesn't control restarts — that's decided separately by whether the server process is actually alive), and it doesn't touch the full record of past hiccups — only the *summary badge* is time-windowed.
|
|
25
|
+
|
|
26
|
+
Low risk: two of the three are small front-end guards in the dashboard page; the third is a contained, well-tested change to which hiccups the health summary counts. A separate, deeper issue — a different "system review" panel showing data from days ago because it never re-runs — is left for a follow-up, because re-running its checks on a schedule is a bigger, cost-bearing change.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ELI16 — Make the worktree scan stop freezing the server
|
|
2
|
+
|
|
3
|
+
## The problem in plain words
|
|
4
|
+
|
|
5
|
+
Instar's server runs everything on a single thread — one line at a time, like a single cashier serving a queue. If any one task takes a long time, *everything else waits*: the dashboard's live connection, the message handlers, all of it.
|
|
6
|
+
|
|
7
|
+
One of the background helpers, the **WorktreeMonitor**, periodically looks at all the git "worktrees" (separate working copies of the code) to spot abandoned work. To do that it shells out to `git worktree list` and a few other git commands. The way it called git was **synchronous** — meaning the single thread sat there and *waited* for git to finish before doing anything else.
|
|
8
|
+
|
|
9
|
+
That's fine when there are a handful of worktrees. But on a machine where worktrees pile up (one agent had ~282 of them!), `git worktree list` takes a few *seconds*. And this scan ran on a 5-minute timer **and** every time a background job finished. So every few minutes the whole server froze for a second or two.
|
|
10
|
+
|
|
11
|
+
## Why it showed up as "dashboard disconnected"
|
|
12
|
+
|
|
13
|
+
On the local address you'd never notice — the dashboard's live connection just reconnects instantly. But when you reach the dashboard through the internet tunnel, a one- or two-second server freeze is enough to **drop the live connection and time out the data**. The result is the dashboard showing "Disconnected, 0 sessions, 0% memory" — even though the server is actually fine, it was just frozen for a moment.
|
|
14
|
+
|
|
15
|
+
## The fix
|
|
16
|
+
|
|
17
|
+
Make the git calls **asynchronous**. Instead of the single thread sitting and waiting for git, it kicks off the git command and goes back to serving everyone else; when git finishes, it picks the result back up. Same scans, same schedule, same results — but the server stays responsive the whole time, so the dashboard's live connection never drops.
|
|
18
|
+
|
|
19
|
+
## What changed and what didn't
|
|
20
|
+
|
|
21
|
+
- Changed: the worktree scan's git calls no longer block the server thread.
|
|
22
|
+
- Unchanged: it still scans on the same 5-minute timer and after each job, still reports the same things, and the `/hooks/worktrees` endpoint returns the exact same data. The git calls keep their old behavior of returning whatever output they produced even if git exits with an error.
|
|
23
|
+
|
|
24
|
+
It's a small, low-risk change covered by the existing tests (all green), and it's the permanent replacement for a quick hotpatch that had temporarily disabled the scans to stop the freezing.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Side-Effects Review — Auto-update version-strand detector
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `autoupdate-strand-detector`
|
|
4
|
+
**Date:** `2026-06-23`
|
|
5
|
+
**Author:** Echo (autonomous)
|
|
6
|
+
**Tier:** 1 (observe-only diagnostic — no change to update behavior, no new config, no decision points)
|
|
7
|
+
**Second-pass reviewer:** not-required (Tier 1; the new method + a corrected log/notify branch, covered by unit tests)
|
|
8
|
+
|
|
9
|
+
## Summary of the change
|
|
10
|
+
|
|
11
|
+
The AutoUpdater has a loop-breaker (`if lastAppliedVersion === latestVersion`) that, on every tick, assumes the recorded-applied version is genuinely installed in the shadow and prints a benign "downloaded, waiting for a restart" message. But `getInstalledVersion()` caches the version the running process booted with — it does NOT reflect the LIVE shadow on disk.
|
|
12
|
+
|
|
13
|
+
If the shadow REVERTS after a successful apply (e.g., crash-loop collateral, or a partial re-install) while `lastAppliedVersion` still records the new version, the agent is **stranded**: the updater believes it is current, the loop-breaker never re-applies, and the misleading "waiting for a restart" message hides a permanent stuck state. This actually happened (an agent stranded on the old version while `lastAppliedVersion` claimed the new one).
|
|
14
|
+
|
|
15
|
+
## The change
|
|
16
|
+
|
|
17
|
+
- `src/core/UpdateChecker.ts` — new `getShadowInstalledVersion(): string | null`, an **uncached** read of `{stateDir}/shadow-install/node_modules/instar/package.json`. Distinct from `getInstalledVersion()` (which caches the running-process version).
|
|
18
|
+
- `src/core/AutoUpdater.ts` — in the loop-breaker, read the live shadow-disk version; if it differs from `lastAppliedVersion` (the shadow doesn't actually have what the record claims), emit a distinct loud STRAND warning + a one-time honest notification ("an update was recorded as installed but isn't on disk — I'm stuck until it's re-applied") instead of the benign "awaiting restart" message.
|
|
19
|
+
- `tests/unit/UpdateChecker.test.ts` — 4 tests for `getShadowInstalledVersion` (reads the disk version, reflects a reverted version uncached, returns null when absent / version-less).
|
|
20
|
+
|
|
21
|
+
## Side effects & risk
|
|
22
|
+
|
|
23
|
+
- **Observe-only.** Update behavior is unchanged: the strand path still `return`s (no auto re-apply — a bounded auto-heal is a deliberate follow-up). The change only corrects the diagnosis and the one-time notification text.
|
|
24
|
+
- **No false positives on the benign case.** A genuine "applied, awaiting restart" has shadow-disk === lastAppliedVersion → `updateAvailable` is false → the tick returns before the loop-breaker. Reaching the loop-breaker with shadow-disk ≠ lastAppliedVersion is the strand.
|
|
25
|
+
- **Fail-safe reads.** `getShadowInstalledVersion()` returns null on any read error; a null shadow version never trips the strand branch (it falls through to the existing benign messages).
|
|
26
|
+
- **Risk:** low. New diagnostic method + a corrected branch, both covered by unit tests; AutoUpdater's existing 29 tests stay green.
|
|
27
|
+
|
|
28
|
+
## Verification
|
|
29
|
+
|
|
30
|
+
- `tsc --noEmit`: 0 errors.
|
|
31
|
+
- `tests/unit/UpdateChecker.test.ts`: 17/17 (incl. 4 new).
|
|
32
|
+
- `tests/unit/AutoUpdater.test.ts` + `tests/unit/auto-updater-failures.test.ts`: 29/29.
|
|
33
|
+
|
|
34
|
+
## Rollout
|
|
35
|
+
|
|
36
|
+
No flag, no migration. Strictly additive diagnostic — surfaces a previously-silent stuck state. The bounded auto-re-apply self-heal (which would also FIX the strand, not just surface it) is a tracked Tier-2 follow-up (it mutates the critical update path and warrants spec-converge review).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Side-Effects Review — Dashboard health-signal polish (3 pre-existing fixes)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `dashboard-health-signal-polish`
|
|
4
|
+
**Date:** `2026-06-23`
|
|
5
|
+
**Author:** Echo (autonomous)
|
|
6
|
+
**Tier:** 1 (three contained, low-risk fixes — two client-side dashboard guards + one health-status windowing on an endpoint whose `status` field does not gate restarts on this agent)
|
|
7
|
+
**Second-pass reviewer:** not-required (Tier 1; small contained fixes, the server-side change covered by new unit tests)
|
|
8
|
+
|
|
9
|
+
## Summary of the change
|
|
10
|
+
|
|
11
|
+
Three minor, pre-existing dashboard issues found while verifying the dashboard-freeze fix (#1253). None affect the dashboard connection; all are noise/cosmetic.
|
|
12
|
+
|
|
13
|
+
1. **WhatsApp QR poll spam.** `pollWaQr()` polls `/whatsapp/qr` every 3s. When WhatsApp isn't configured the route returns 503, but the poll loop was never stopped — so the browser console accumulated ~20 503s/min for the whole session. Fix: call `stopWaPolling()` on the 503 (adapter absent).
|
|
14
|
+
2. **Null-deref TypeError on load.** A parse-time block attached a `'message'` listener to `ws`, guarded by `if (typeof ws !== 'undefined')`. `ws` is a declared `let` that is **null** at parse time (`connectWebSocket()` runs later in a `.then()`), and `typeof null === 'object' !== 'undefined'`, so the guard passed and `ws.onmessage` threw `Cannot read properties of null (reading 'onmessage')` on every load. The block was the only place paste WebSocket events refreshed the drop-zone — so the feature was also effectively dead. Fix: fold `paste_delivered` / `paste_acknowledged` into the main `handleMessage` switch (where it survives reconnects) and remove the broken parse-time block.
|
|
15
|
+
3. **Stale "Degraded" badge.** The vital-signs badge renders `/health`'s `status`, which is `degraded` whenever `DegradationReporter.getEvents().length > 0`. Degradation events are append-only and never self-clear, so a single transient/benign fallback pins the badge red for the entire process lifetime even after recovery. Fix: `/health` now uses a new `DegradationReporter.getRecentEvents()` (30-min window) for status + the reported count/summary — a persistent problem keeps re-reporting so it stays visible; a one-off ages out.
|
|
16
|
+
|
|
17
|
+
## The change
|
|
18
|
+
|
|
19
|
+
- `dashboard/index.html` — (1) `stopWaPolling()` on 503; (2) paste cases added to `handleMessage`, broken parse-time block removed.
|
|
20
|
+
- `src/monitoring/DegradationReporter.ts` — new `getRecentEvents(windowMs = HEALTH_WINDOW_MS, now = Date.now())` + `static HEALTH_WINDOW_MS = 30min`. Filters by event `timestamp`; an unparseable timestamp is KEPT (fail-safe: surface, never hide). `getEvents()` (full log) is unchanged.
|
|
21
|
+
- `src/server/routes.ts` — `/health` calls `getRecentEvents()` instead of `getEvents()` for the `degradations` list that feeds `status` + `degradations` count + `degradationSummary`.
|
|
22
|
+
- `tests/unit/degradation-reporter.test.ts` — 3 new tests (recent kept / old aged out / unparseable kept).
|
|
23
|
+
|
|
24
|
+
## Side effects & risk
|
|
25
|
+
|
|
26
|
+
- **`/health` status semantics.** `status` flips back to `ok` once degradations age past 30 min without recurring. Reviewed consumers: the **Telegram lifeline** derives `serverHealthy` from the supervisor's process status, NOT from `/health.status`, so this never affects restart behavior on a Telegram agent (Echo). `SlackLifeline` keys on `status === 'ok'` only to detect the unhealthy→healthy *recovery* transition (a log/notify), not to trigger restarts. The change makes status MORE truthful (reflects current health), and is the safe direction (a real, recurring problem keeps re-reporting and stays visible).
|
|
27
|
+
- **The full degradation log is untouched.** `getEvents()`, `getUnreportedEvents()`, mark-reported, and persistence all still see every event — only the /health *status view* is windowed.
|
|
28
|
+
- **Client-side fixes are isolated** to the dashboard static asset; no server behavior changes; the dashboard isn't in the typecheck/test suite, so both were syntax-checked with `node --check`.
|
|
29
|
+
- **Risk:** low. No new config, no new route, no migration (the dashboard asset + core source ship with the package on update). Reversible (revert the three edits).
|
|
30
|
+
|
|
31
|
+
## 6b. Operator-surface quality (Operator-Surface Quality standard)
|
|
32
|
+
|
|
33
|
+
This change touches `dashboard/index.html`. It alters **background behavior**, not layout or primary actions — so it adds no new operator-facing controls or content. Against the four criteria:
|
|
34
|
+
|
|
35
|
+
1. **Leads with the primary action?** Unchanged — the dashboard still leads with the session list + vital-signs strip. No new primary action is introduced; nothing is moved, collapsed, or pushed below the fold.
|
|
36
|
+
2. **Zero raw internals as primary content?** Yes — the change adds NO displayed content. It REMOVES noise (the WhatsApp console 503 spam) and an on-load TypeError, and makes the existing plain-language health badge ("Healthy" / uptime vs "Degraded") accurate. No JSON/UUID/fingerprint/hash is shown.
|
|
37
|
+
3. **Destructive actions de-emphasized?** N/A — no destructive control is added or touched.
|
|
38
|
+
4. **Plain language + phone width?** Yes — the only user-visible behavioral change is the top-of-dashboard badge now correctly reads "Healthy" when the box is healthy (it was stuck on "Degraded"). Plain wording, same layout, same width — no new elements, so no phone-width regression.
|
|
39
|
+
|
|
40
|
+
(The dashboard's pre-existing raw-input field — the PIN/token unlock — already carries the co-located `operator-surface-power-user` marker and is untouched here.)
|
|
41
|
+
|
|
42
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
43
|
+
|
|
44
|
+
**machine-local BY DESIGN.** The vital-signs badge reads THIS machine's `/health`; each machine's `DegradationReporter` and health state are local, per-machine observability (a degradation on machine A is machine A's concern). The dashboard already exposes pool-wide state through separate `?scope=pool` surfaces (sessions, guards, attention, …), which this change does not touch. The WhatsApp poll and the paste WS handler are pure client-side, per-browser-tab.
|
|
45
|
+
|
|
46
|
+
- **User-facing notices?** None emitted — no one-voice gating concern.
|
|
47
|
+
- **Durable state strand on topic transfer?** No durable state added; nothing strands.
|
|
48
|
+
- **Generated URLs?** None.
|
|
49
|
+
|
|
50
|
+
## Verification
|
|
51
|
+
|
|
52
|
+
- `tsc --noEmit`: 0 errors.
|
|
53
|
+
- `tests/unit/degradation-reporter.test.ts`: 20/20 (incl. 3 new windowing tests).
|
|
54
|
+
- `tests/unit/{routes-degradations-mark-reported,degradation-never-silent,degradation-reporter-reentrancy-wedge}.test.ts`: 14/14 (no regression on the mark-reported / never-silent paths).
|
|
55
|
+
- `dashboard/index.html` embedded script: `node --check` passes.
|
|
56
|
+
|
|
57
|
+
## Rollout
|
|
58
|
+
|
|
59
|
+
No flag, no migration. Three additive fixes that surface previously-hidden console errors and make the health badge truthful. The genuinely-stale `systemReview` *panel* (last ran 2026-06-20, never re-runs) is a SEPARATE, more-involved concern (re-running 16 probes on a cadence is cost-bearing) — explicitly NOT bundled here; tracked for follow-up.
|