instar 1.3.648 → 1.3.650

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 (41) hide show
  1. package/dashboard/index.html +14 -14
  2. package/dist/commands/server.d.ts.map +1 -1
  3. package/dist/commands/server.js +3 -0
  4. package/dist/commands/server.js.map +1 -1
  5. package/dist/core/AutoUpdater.d.ts.map +1 -1
  6. package/dist/core/AutoUpdater.js +23 -3
  7. package/dist/core/AutoUpdater.js.map +1 -1
  8. package/dist/core/UpdateChecker.d.ts +12 -0
  9. package/dist/core/UpdateChecker.d.ts.map +1 -1
  10. package/dist/core/UpdateChecker.js +22 -0
  11. package/dist/core/UpdateChecker.js.map +1 -1
  12. package/dist/core/types.d.ts +10 -0
  13. package/dist/core/types.d.ts.map +1 -1
  14. package/dist/core/types.js.map +1 -1
  15. package/dist/monitoring/DegradationReporter.d.ts +18 -0
  16. package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
  17. package/dist/monitoring/DegradationReporter.js +24 -0
  18. package/dist/monitoring/DegradationReporter.js.map +1 -1
  19. package/dist/monitoring/SystemReviewer.d.ts +22 -0
  20. package/dist/monitoring/SystemReviewer.d.ts.map +1 -1
  21. package/dist/monitoring/SystemReviewer.js +37 -0
  22. package/dist/monitoring/SystemReviewer.js.map +1 -1
  23. package/dist/monitoring/WorktreeMonitor.d.ts +13 -6
  24. package/dist/monitoring/WorktreeMonitor.d.ts.map +1 -1
  25. package/dist/monitoring/WorktreeMonitor.js +50 -33
  26. package/dist/monitoring/WorktreeMonitor.js.map +1 -1
  27. package/dist/server/routes.d.ts.map +1 -1
  28. package/dist/server/routes.js +8 -3
  29. package/dist/server/routes.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/data/builtin-manifest.json +48 -48
  32. package/upgrades/1.3.649.md +30 -0
  33. package/upgrades/1.3.650.md +21 -0
  34. package/upgrades/eli16/autoupdate-strand-detector.md +22 -0
  35. package/upgrades/eli16/dashboard-health-signal-polish.md +26 -0
  36. package/upgrades/eli16/systemreview-onboot-refresh.md +24 -0
  37. package/upgrades/eli16/worktree-monitor-async-git.md +24 -0
  38. package/upgrades/side-effects/autoupdate-strand-detector.md +36 -0
  39. package/upgrades/side-effects/dashboard-health-signal-polish.md +59 -0
  40. package/upgrades/side-effects/systemreview-onboot-refresh.md +39 -0
  41. package/upgrades/side-effects/worktree-monitor-async-git.md +39 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.648",
3
+ "version": "1.3.650",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-06-22T22:56:43.249Z",
5
- "instarVersion": "1.3.648",
4
+ "generatedAt": "2026-06-23T05:05:15.576Z",
5
+ "instarVersion": "1.3.650",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "cb2f112cb6404ad51d59f815dbf5500ffcf7d4e262ce66f97679047829645d17",
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": "60802cc5aad744cad139c5f5c0b1e4b27468c0a27b38384804ed09a6aa4e081c",
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": "3895b7eb8c6d3caf4337014ad6aeda537ae5f2507fa22a2357609be319811326",
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,21 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The built-in "system review" (a batch of ~16 local self-checks surfaced in `/health` and rendered as the dashboard health panel) runs on a 6-hour timer — but it only ever ran when that timer fired, never on boot. Each restart resets the 6-hour timer, so on an agent that restarts more often than every 6 hours (updates, recovery bounces), the review never runs again after the first time, and the health panel freezes on a days-old snapshot. `SystemReviewer.start()` now also runs one review shortly after boot (default 30s delay, in the background, behind a default-on `reviewOnStart` flag), gated by a freshness guard so a restart loop doesn't pile up reviews (skipped if a review ran in the last hour; an unparseable timestamp errs toward running it).
9
+
10
+ ## What to Tell Your User
11
+
12
+ If your dashboard's health panel showed a scary days-old "critical" status even though everything was fine, that's fixed — the panel now refreshes within about 30 seconds of every startup, so it reflects current health instead of an old snapshot. There's nothing to do; it's on by default. If you'd ever prefer it only refresh on its slower six-hour cycle, just ask me and I'll switch it.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - `SystemReviewer` runs one review shortly after `start()` (in addition to the `scheduleMs` interval), so the health panel stays current on agents that restart more often than the interval.
17
+ - New `monitoring.systemReview` config: `reviewOnStart` (default true), `initialReviewDelayMs` (default 30s), `initialReviewStaleAfterMs` (default 1h — skip the on-boot review if the last one is younger than this).
18
+
19
+ ## Evidence
20
+
21
+ Observed live on Echo: `curl /health` returned `systemReview` with `lastReview.timestamp = "2026-06-20T11:51:54.985Z"` and `status: "critical", passed: 11, failed: 5` — days stale, from a past incident, while the box was healthy (uptime ~1–2h, no current failures). Root cause confirmed by reading `start()`: it set the `scheduleMs` (6h) interval but ran no review on boot, and the probe sources contain no LLM/network calls (so an on-boot review is cheap). After: 4 new unit tests prove `start()` runs a review after the delay when the last review is absent or >1h old, and skips it when the last review is <1h old.
@@ -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 — The health panel that was stuck showing days-old news
2
+
3
+ ## The problem in plain words
4
+
5
+ Instar runs a built-in "system review" — a batch of ~16 quick self-checks (is the scheduler alive, is messaging working, etc.) — and shows the result as a health summary. It's meant to run on a repeating timer so the summary stays current.
6
+
7
+ The timer is set to every 6 hours. But here's the bug: the review only ever ran *when the 6-hour timer went off* — it never ran *when the agent started up*. And this agent restarts pretty often (every update, every recovery bounce, restarts a few hours apart). Each restart resets the 6-hour timer back to zero. So if the agent restarts more often than every 6 hours, the timer never actually reaches 6 hours — and the review never runs again after the very first time.
8
+
9
+ The result: the health panel got frozen on whatever it last said. On this agent it was stuck showing a scary "critical — only 11 of 16 checks passing" from days ago (during a past incident), long after everything had recovered. Anyone looking at the dashboard would think the agent was on fire when it was perfectly healthy.
10
+
11
+ ## The fix
12
+
13
+ Run one review shortly after the agent boots, in addition to the 6-hour timer. Now every startup refreshes the panel within about 30 seconds, so it always reflects the *current* state regardless of how often the agent restarts.
14
+
15
+ Two safeguards keep it sensible:
16
+ - **It waits ~30 seconds and runs in the background**, so it never slows down startup.
17
+ - **It skips if the panel is already fresh** (a review ran in the last hour). That way, if the agent is in a rapid restart loop, it won't pile up a review on every single boot — just one per hour at most. (If the timestamp is somehow unreadable, it errs on the side of running the review — better a fresh check than a stale one.)
18
+
19
+ ## What it does and doesn't do
20
+
21
+ - It does: keep the health panel honest by refreshing it on every boot, so it shows current health instead of a days-old snapshot.
22
+ - It doesn't: change what the checks are or how the 6-hour cadence works, and it doesn't add any cost worth worrying about — the checks are all local (no AI calls, no network), so running one extra on boot is cheap.
23
+
24
+ There's an off-switch (`reviewOnStart: false`) for anyone who wants only the 6-hour cadence, and it's on by default because a health panel showing days-old "critical" status is a real, misleading bug. Low risk: it's an additive background timer with a freshness guard, covered by tests.
@@ -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).