instar 1.1.4 → 1.2.2

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-21T04:11:40.504Z",
5
- "instarVersion": "1.1.4",
4
+ "generatedAt": "2026-05-21T04:38:07.750Z",
5
+ "instarVersion": "1.2.2",
6
6
  "entryCount": 190,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -392,7 +392,7 @@
392
392
  "type": "route-group",
393
393
  "domain": "monitoring",
394
394
  "sourcePath": "src/server/routes.ts",
395
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
395
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
396
396
  "since": "2025-01-01"
397
397
  },
398
398
  "route-group:agents": {
@@ -400,7 +400,7 @@
400
400
  "type": "route-group",
401
401
  "domain": "sessions",
402
402
  "sourcePath": "src/server/routes.ts",
403
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
403
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
404
404
  "since": "2025-01-01"
405
405
  },
406
406
  "route-group:backups": {
@@ -408,7 +408,7 @@
408
408
  "type": "route-group",
409
409
  "domain": "operations",
410
410
  "sourcePath": "src/server/routes.ts",
411
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
411
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
412
412
  "since": "2025-01-01"
413
413
  },
414
414
  "route-group:git": {
@@ -416,7 +416,7 @@
416
416
  "type": "route-group",
417
417
  "domain": "coordination",
418
418
  "sourcePath": "src/server/routes.ts",
419
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
419
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
420
420
  "since": "2025-01-01"
421
421
  },
422
422
  "route-group:memory": {
@@ -424,7 +424,7 @@
424
424
  "type": "route-group",
425
425
  "domain": "memory",
426
426
  "sourcePath": "src/server/routes.ts",
427
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
427
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
428
428
  "since": "2025-01-01"
429
429
  },
430
430
  "route-group:semantic": {
@@ -432,7 +432,7 @@
432
432
  "type": "route-group",
433
433
  "domain": "memory",
434
434
  "sourcePath": "src/server/routes.ts",
435
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
435
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
436
436
  "since": "2025-01-01"
437
437
  },
438
438
  "route-group:status": {
@@ -440,7 +440,7 @@
440
440
  "type": "route-group",
441
441
  "domain": "monitoring",
442
442
  "sourcePath": "src/server/routes.ts",
443
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
443
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
444
444
  "since": "2025-01-01"
445
445
  },
446
446
  "route-group:capabilities": {
@@ -448,7 +448,7 @@
448
448
  "type": "route-group",
449
449
  "domain": "mapping",
450
450
  "sourcePath": "src/server/routes.ts",
451
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
451
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
452
452
  "since": "2025-01-01"
453
453
  },
454
454
  "route-group:project-map": {
@@ -456,7 +456,7 @@
456
456
  "type": "route-group",
457
457
  "domain": "mapping",
458
458
  "sourcePath": "src/server/routes.ts",
459
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
459
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
460
460
  "since": "2025-01-01"
461
461
  },
462
462
  "route-group:coherence": {
@@ -464,7 +464,7 @@
464
464
  "type": "route-group",
465
465
  "domain": "coherence",
466
466
  "sourcePath": "src/server/routes.ts",
467
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
467
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
468
468
  "since": "2025-01-01"
469
469
  },
470
470
  "route-group:topic-bindings": {
@@ -472,7 +472,7 @@
472
472
  "type": "route-group",
473
473
  "domain": "sessions",
474
474
  "sourcePath": "src/server/routes.ts",
475
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
475
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
476
476
  "since": "2025-01-01"
477
477
  },
478
478
  "route-group:context": {
@@ -480,7 +480,7 @@
480
480
  "type": "route-group",
481
481
  "domain": "context",
482
482
  "sourcePath": "src/server/routes.ts",
483
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
483
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
484
484
  "since": "2025-01-01"
485
485
  },
486
486
  "route-group:scope-coherence": {
@@ -488,7 +488,7 @@
488
488
  "type": "route-group",
489
489
  "domain": "coherence",
490
490
  "sourcePath": "src/server/routes.ts",
491
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
491
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
492
492
  "since": "2025-01-01"
493
493
  },
494
494
  "route-group:canonical-state": {
@@ -496,7 +496,7 @@
496
496
  "type": "route-group",
497
497
  "domain": "state",
498
498
  "sourcePath": "src/server/routes.ts",
499
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
499
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
500
500
  "since": "2025-01-01"
501
501
  },
502
502
  "route-group:ci": {
@@ -504,7 +504,7 @@
504
504
  "type": "route-group",
505
505
  "domain": "monitoring",
506
506
  "sourcePath": "src/server/routes.ts",
507
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
507
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
508
508
  "since": "2025-01-01"
509
509
  },
510
510
  "route-group:sessions": {
@@ -512,7 +512,7 @@
512
512
  "type": "route-group",
513
513
  "domain": "sessions",
514
514
  "sourcePath": "src/server/routes.ts",
515
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
515
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
516
516
  "since": "2025-01-01"
517
517
  },
518
518
  "route-group:jobs": {
@@ -520,7 +520,7 @@
520
520
  "type": "route-group",
521
521
  "domain": "scheduling",
522
522
  "sourcePath": "src/server/routes.ts",
523
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
523
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
524
524
  "since": "2025-01-01"
525
525
  },
526
526
  "route-group:skip-ledger": {
@@ -528,7 +528,7 @@
528
528
  "type": "route-group",
529
529
  "domain": "scheduling",
530
530
  "sourcePath": "src/server/routes.ts",
531
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
531
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
532
532
  "since": "2025-01-01"
533
533
  },
534
534
  "route-group:telegram": {
@@ -536,7 +536,7 @@
536
536
  "type": "route-group",
537
537
  "domain": "communication",
538
538
  "sourcePath": "src/server/routes.ts",
539
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
539
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
540
540
  "since": "2025-01-01"
541
541
  },
542
542
  "route-group:attention": {
@@ -544,7 +544,7 @@
544
544
  "type": "route-group",
545
545
  "domain": "communication",
546
546
  "sourcePath": "src/server/routes.ts",
547
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
547
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
548
548
  "since": "2025-01-01"
549
549
  },
550
550
  "route-group:relationships": {
@@ -552,7 +552,7 @@
552
552
  "type": "route-group",
553
553
  "domain": "relationships",
554
554
  "sourcePath": "src/server/routes.ts",
555
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
555
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
556
556
  "since": "2025-01-01"
557
557
  },
558
558
  "route-group:feedback": {
@@ -560,7 +560,7 @@
560
560
  "type": "route-group",
561
561
  "domain": "feedback",
562
562
  "sourcePath": "src/server/routes.ts",
563
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
563
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
564
564
  "since": "2025-01-01"
565
565
  },
566
566
  "route-group:updates": {
@@ -568,7 +568,7 @@
568
568
  "type": "route-group",
569
569
  "domain": "updates",
570
570
  "sourcePath": "src/server/routes.ts",
571
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
571
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
572
572
  "since": "2025-01-01"
573
573
  },
574
574
  "route-group:dispatches": {
@@ -576,7 +576,7 @@
576
576
  "type": "route-group",
577
577
  "domain": "dispatches",
578
578
  "sourcePath": "src/server/routes.ts",
579
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
579
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
580
580
  "since": "2025-01-01"
581
581
  },
582
582
  "route-group:quota": {
@@ -584,7 +584,7 @@
584
584
  "type": "route-group",
585
585
  "domain": "monitoring",
586
586
  "sourcePath": "src/server/routes.ts",
587
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
587
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
588
588
  "since": "2025-01-01"
589
589
  },
590
590
  "route-group:publishing": {
@@ -592,7 +592,7 @@
592
592
  "type": "route-group",
593
593
  "domain": "publishing",
594
594
  "sourcePath": "src/server/routes.ts",
595
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
595
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
596
596
  "since": "2025-01-01"
597
597
  },
598
598
  "route-group:private-views": {
@@ -600,7 +600,7 @@
600
600
  "type": "route-group",
601
601
  "domain": "publishing",
602
602
  "sourcePath": "src/server/routes.ts",
603
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
603
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
604
604
  "since": "2025-01-01"
605
605
  },
606
606
  "route-group:tunnel": {
@@ -608,7 +608,7 @@
608
608
  "type": "route-group",
609
609
  "domain": "networking",
610
610
  "sourcePath": "src/server/routes.ts",
611
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
611
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
612
612
  "since": "2025-01-01"
613
613
  },
614
614
  "route-group:events": {
@@ -616,7 +616,7 @@
616
616
  "type": "route-group",
617
617
  "domain": "networking",
618
618
  "sourcePath": "src/server/routes.ts",
619
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
619
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
620
620
  "since": "2025-01-01"
621
621
  },
622
622
  "route-group:evolution": {
@@ -624,7 +624,7 @@
624
624
  "type": "route-group",
625
625
  "domain": "evolution",
626
626
  "sourcePath": "src/server/routes.ts",
627
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
627
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
628
628
  "since": "2025-01-01"
629
629
  },
630
630
  "route-group:watchdog": {
@@ -632,7 +632,7 @@
632
632
  "type": "route-group",
633
633
  "domain": "monitoring",
634
634
  "sourcePath": "src/server/routes.ts",
635
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
635
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
636
636
  "since": "2025-01-01"
637
637
  },
638
638
  "route-group:topic-memory": {
@@ -640,7 +640,7 @@
640
640
  "type": "route-group",
641
641
  "domain": "memory",
642
642
  "sourcePath": "src/server/routes.ts",
643
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
643
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
644
644
  "since": "2025-01-01"
645
645
  },
646
646
  "route-group:state-sync": {
@@ -648,7 +648,7 @@
648
648
  "type": "route-group",
649
649
  "domain": "coordination",
650
650
  "sourcePath": "src/server/routes.ts",
651
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
651
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
652
652
  "since": "2025-01-01"
653
653
  },
654
654
  "route-group:intent": {
@@ -656,7 +656,7 @@
656
656
  "type": "route-group",
657
657
  "domain": "intent",
658
658
  "sourcePath": "src/server/routes.ts",
659
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
659
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
660
660
  "since": "2025-01-01"
661
661
  },
662
662
  "route-group:triage": {
@@ -664,7 +664,7 @@
664
664
  "type": "route-group",
665
665
  "domain": "safety",
666
666
  "sourcePath": "src/server/routes.ts",
667
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
667
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
668
668
  "since": "2025-01-01"
669
669
  },
670
670
  "route-group:operations": {
@@ -672,7 +672,7 @@
672
672
  "type": "route-group",
673
673
  "domain": "safety",
674
674
  "sourcePath": "src/server/routes.ts",
675
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
675
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
676
676
  "since": "2025-01-01"
677
677
  },
678
678
  "route-group:sentinel": {
@@ -680,7 +680,7 @@
680
680
  "type": "route-group",
681
681
  "domain": "safety",
682
682
  "sourcePath": "src/server/routes.ts",
683
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
683
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
684
684
  "since": "2025-01-01"
685
685
  },
686
686
  "route-group:trust": {
@@ -688,7 +688,7 @@
688
688
  "type": "route-group",
689
689
  "domain": "safety",
690
690
  "sourcePath": "src/server/routes.ts",
691
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
691
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
692
692
  "since": "2025-01-01"
693
693
  },
694
694
  "route-group:monitoring": {
@@ -696,7 +696,7 @@
696
696
  "type": "route-group",
697
697
  "domain": "monitoring",
698
698
  "sourcePath": "src/server/routes.ts",
699
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
699
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
700
700
  "since": "2025-01-01"
701
701
  },
702
702
  "route-group:commitments": {
@@ -704,7 +704,7 @@
704
704
  "type": "route-group",
705
705
  "domain": "commitments",
706
706
  "sourcePath": "src/server/routes.ts",
707
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
707
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
708
708
  "since": "2025-01-01"
709
709
  },
710
710
  "route-group:episodes": {
@@ -712,7 +712,7 @@
712
712
  "type": "route-group",
713
713
  "domain": "memory",
714
714
  "sourcePath": "src/server/routes.ts",
715
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
715
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
716
716
  "since": "2025-01-01"
717
717
  },
718
718
  "route-group:messages": {
@@ -720,7 +720,7 @@
720
720
  "type": "route-group",
721
721
  "domain": "coordination",
722
722
  "sourcePath": "src/server/routes.ts",
723
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
723
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
724
724
  "since": "2025-01-01"
725
725
  },
726
726
  "route-group:system-reviews": {
@@ -728,7 +728,7 @@
728
728
  "type": "route-group",
729
729
  "domain": "monitoring",
730
730
  "sourcePath": "src/server/routes.ts",
731
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
731
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
732
732
  "since": "2025-01-01"
733
733
  },
734
734
  "route-group:machine-mesh": {
@@ -744,7 +744,7 @@
744
744
  "type": "route-group",
745
745
  "domain": "security",
746
746
  "sourcePath": "src/server/routes.ts",
747
- "contentHash": "2eccf8b9643cd244125cd69b2453db09ae642a2514e1237541e24086a17347bc",
747
+ "contentHash": "e0abd503b434c2df51917a9a68f8a9a2d514c61faf43012712878282eb9ccf8d",
748
748
  "since": "2025-01-01"
749
749
  },
750
750
  "cli:init": {
package/upgrades/1.1.4.md CHANGED
@@ -1,42 +1,143 @@
1
- # Upgrade Guide — vNEXT
1
+ # Upgrade Guide — v1.2.0 (telegram-history-backfill + test-env GIT_DIR hardening)
2
2
 
3
- <!-- bump: patch -->
4
- <!-- patch = bug fixes, refactors, test additions, doc updates -->
3
+ <!-- bump: minor -->
5
4
 
6
5
  ## What Changed
7
6
 
8
- **fix(test-env): close the inherited-GIT_DIR failure class.**
7
+ Two changes ship together. The headline is the new operator-driven
8
+ recovery primitive; the test-env hardening from PR #286 rides along in
9
+ the same release.
10
+
11
+ **1. New: telegram-history-backfill (MTProto recovery primitive).** A
12
+ script-tier path to restore `topic-memory.db` after a local-store loss
13
+ event. The 2026-05-20 cascade (a Node 22→25 host swap broke
14
+ `better-sqlite3`; the recovery procedure restored the module but left
15
+ topic-memory's local mirror near-empty) exposed a durable gap: the
16
+ Telegram Bot API cannot fetch chat history, so any local mirror loss
17
+ was previously permanent. Authenticates as the operator's account via
18
+ gramjs (MTProto), iterates forum topics, writes idempotently via the
19
+ existing `UNIQUE(message_id, topic_id)` constraint + `INSERT OR IGNORE`.
20
+ Three new files under `scripts/`:
21
+
22
+ - `scripts/lib/topic-memory-importer.mjs` — pure-DB importer with batch
23
+ transactions and INSERT OR IGNORE idempotency.
24
+ - `scripts/lib/telegram-historian.mjs` — gramjs wrapper. Auth, topic
25
+ listing, per-topic iteration. **Read-only Telegram posture** — no
26
+ send/edit/delete method is exposed.
27
+ - `scripts/telegram-history-backfill.mjs` — CLI entry. Three driving
28
+ modes for auth (interactive stdin, `--phone` + `--code-file` polling
29
+ for SMS, `--password-file` for 2FA). The file-poll mode supports
30
+ autonomous operation paired with instar's Secret Drop web form
31
+ (avoids Telegram's anti-phishing "code was shared in a chat" block).
32
+
33
+ Session string stored at `~/.local/share/instar-echo-secrets/` mode
34
+ 0600, outside any git tree.
35
+
36
+ **2. fix(test-env): close the inherited-GIT_DIR failure class.** Carried
37
+ forward from PR #286. When git invokes a hook (`.husky/pre-push` runs
38
+ `npm run test:smoke`), it sets `GIT_DIR` / `GIT_WORK_TREE` /
39
+ `GIT_INDEX_FILE` / `GIT_OBJECT_DIRECTORY` / `GIT_COMMON_DIR` on the
40
+ child env. Those variables override cwd-based repo resolution for
41
+ every descendant git process, so test fixtures that did
42
+ `git init && git commit` in a tmpdir actually committed into the
43
+ parent repo on whichever branch was checked out. That's what landed
44
+ `# Test Project` over the project's `README.md` on `main` via PRs #130
45
+ and #277 — the README clobber shipped to npm in the v1.1.x series
46
+ before PR #285 restored it.
47
+
48
+ The fix closes the failure class in five interlocking layers:
49
+
50
+ 1. **`tests/vitest-setup.ts` strips the GIT_DIR family** from
51
+ `process.env` before any test file loads. Single-line root-cause fix.
52
+ 2. **`tests/helpers/git-test-env.ts` exports `sanitizedGitEnv()`** for
53
+ fixtures that pass their own `env` object to `spawnSync` /
54
+ `execFileSync`. Defense-in-depth on top of Layer 1.
55
+ 3. **`scripts/pre-push-fixture-guard.mjs`** runs in `.husky/pre-push`
56
+ before the smoke tests and refuses pushes whose ahead-of-upstream
57
+ commits carry the historical fixture signature (author email in
58
+ `{test@instar.local, t@t.com, t@e.com, test@test.com}` or subject
59
+ matching `Initial commit` / `seed` / `init` / `Worktree commit N`).
60
+ 4. **`scripts/check-repo-invariants.mjs`** runs as a dedicated
61
+ `Repo Invariants` CI job and fails the build if `README.md` drops
62
+ below 100 lines or if `file-0.txt` / `seed` appear at repo root.
63
+ 5. **Removed `file-0.txt` and `seed`** stowaway files from repo root —
64
+ fixture droppings that would have falsely passed Layer 4 on the
65
+ PR adding it.
9
66
 
10
- When git invokes a hook (`.husky/pre-push` runs `npm run test:smoke`), it sets `GIT_DIR` / `GIT_WORK_TREE` / `GIT_INDEX_FILE` / `GIT_OBJECT_DIRECTORY` / `GIT_COMMON_DIR` on the child env. Those variables override cwd-based repo resolution for every descendant git process, so test fixtures that did `git init && git commit` in a tmpdir actually committed into the parent repo on whichever branch was checked out. That's what landed `# Test Project` over the project's `README.md` on `main` via PRs #130 and #277 — the README clobber shipped to npm in the v1.1.x series before PR #285 restored it.
11
-
12
- This release closes the failure class in five interlocking layers:
13
-
14
- 1. **`tests/vitest-setup.ts` strips the GIT_DIR family** from `process.env` before any test file loads. Single-line root-cause fix — no test in the suite can inherit the dangerous overrides from the parent pre-push environment.
15
-
16
- 2. **`tests/helpers/git-test-env.ts` exports `sanitizedGitEnv()`** for fixtures that pass their own `env` object to `spawnSync` / `execFileSync`. Applied to the three fixtures whose write patterns are visible in PR #130's diff (`worktree-monitor.test.ts`, `SafeGitExecutor.test.ts`, `rich-profile-integration.test.ts`). Defense-in-depth on top of Layer 1.
17
-
18
- 3. **`scripts/pre-push-fixture-guard.mjs`** runs in `.husky/pre-push` before the smoke tests and refuses pushes whose ahead-of-upstream commits carry the historical fixture signature — author email in `{test@instar.local, t@t.com, t@e.com, test@test.com}` or subject matching `Initial commit` / `seed` / `init` / `Worktree commit N`. Bypass for legitimate test-only branches: `INSTAR_PRE_PUSH_FIXTURE_GUARD_SKIP=1`.
19
-
20
- 4. **`scripts/check-repo-invariants.mjs`** runs as a dedicated `Repo Invariants` CI job and fails the build if `README.md` drops below 100 lines or if `file-0.txt` / `seed` appear at repo root. Final structural safety net; threshold overridable via `INSTAR_README_MIN_LINES`.
21
-
22
- 5. **Removed `file-0.txt` and `seed`** stowaway files from repo root — fixture droppings from prior incidents that would have falsely passed Layer 4 on the PR adding it.
67
+ ## Evidence
23
68
 
24
- Spec: `docs/specs/test-env-isolation.md`. ELI16: `docs/specs/test-env-isolation.eli16.md`. Side-effects review: `upgrades/side-effects/test-env-isolation.md`.
69
+ **Backfill — reproduction prior:** in topic 10873 on 2026-05-20, after
70
+ Echo's better-sqlite3 native-module cascade recovery, the agent's local
71
+ `topic-memory.db` showed 98 messages across 7 topics where the
72
+ operator's Telegram client showed thousands across 100+ topics. The
73
+ agent had no path to fetch the missing rows — Bot API has no
74
+ history-fetch primitive.
75
+
76
+ **Backfill — reproduction after:** ran against the lifeline supergroup
77
+ (`-1003742343280`) on 2026-05-20T21:00:27Z. Result:
78
+ `topics=101 fetched=10308 inserted=10207 skipped=101`. The 101
79
+ skipped rows match the pre-existing on-disk count exactly — the
80
+ UNIQUE constraint + `INSERT OR IGNORE` correctly de-duplicated the
81
+ overlap, no doubles introduced. Topic 10873 went from 43 to 93
82
+ messages, restoring the full deployment-lockdown arc.
83
+
84
+ **Backfill — idempotency:** verified by
85
+ `tests/unit/topic-memory-importer.test.ts` (12 cases). Re-running the
86
+ same batch produces zero new inserts; partial-overlap re-run inserts
87
+ only the new messages; same message_id across different topics is not
88
+ a duplicate; FTS index stays clean across re-runs; a regression case
89
+ reproduces the exact "post-truncation overlap" shape from the
90
+ 2026-05-20 incident.
91
+
92
+ **Test-env GIT_DIR — reproduction prior:** the README clobber on
93
+ `main` was reproduced before the fix landed: `gh api
94
+ repos/JKHeadley/instar/contents/README.md --jq .size` returned `7`
95
+ (the literal text `# Test\n`) prior to PR #285. PR #285 restored the
96
+ README; PR #286 closed the underlying class so the same regression
97
+ cannot recur. Test-fixture pollution detection was verified end-to-end:
98
+ against a tmpdir repo with a commit subject `Initial commit`,
99
+ `node scripts/pre-push-fixture-guard.mjs` exits 1 and names the
100
+ offending commit. Repo-invariant detection was verified end-to-end:
101
+ against a repo where `README.md` has been trimmed to a single line,
102
+ `node scripts/check-repo-invariants.mjs` exits 1 and reports the line
103
+ count.
25
104
 
26
105
  ## What to Tell Your User
27
106
 
28
- Nothing user-visible. This release hardens instar's own development pipeline against a class of bug that, while invisible to running agents, had been quietly corrupting our published README. Agents continue to behave identically.
29
-
30
- If a contributor asks why their push is suddenly refused with a fixture-pollution guard error, the script's own output includes recovery instructions — usually resetting past a stray commit and pushing again.
107
+ - "I can now restore Telegram message history into my local store if it ever gets wiped again. Tell me 'back up our Telegram history' and I run a one-time auth flow with you (phone number, then a one-time code through a secure form, not through this chat) and walk the supergroup top to bottom. The whole thing is read-only on the Telegram side and the code never passes through our chat, so Telegram does not flag the login."
108
+ - "The recovery itself is safe to re-run. If I get interrupted partway through, I just run it again — there is built-in deduplication that means existing messages are skipped, not duplicated."
109
+ - "Nothing user-visible from the test-env GIT_DIR fix carried in from PR 286. This release hardens instar's own development pipeline against a class of bug that, while invisible to running agents, had been quietly corrupting our published README. Agents continue to behave identically."
31
110
 
32
111
  ## Summary of New Capabilities
33
112
 
34
- This release is a pure hardening fix. No new runtime capabilities for agents. The new pre-push and CI guards are infrastructure for the instar-developing agent and direct contributors only.
35
-
36
- ## Evidence
37
-
38
- The README clobber on `main` was reproduced before the fix landed: `gh api repos/JKHeadley/instar/contents/README.md --jq .size` returned `7` (the literal text `# Test\n`) prior to PR #285. PR #285 restored the README; this PR closes the underlying class so the same regression cannot recur.
39
-
40
- Test-fixture pollution detection was verified end-to-end: against a tmpdir repo with a commit subject `Initial commit`, `node scripts/pre-push-fixture-guard.mjs` exits 1 and names the offending commit. Against the same repo with the env bypass set, the script exits 0. Repo-invariant detection was verified end-to-end: against a repo where `README.md` has been trimmed to a single line, `node scripts/check-repo-invariants.mjs` exits 1 and reports the line count; against a healthy repo, it exits 0.
41
-
42
- 14 new tests across the env-strip regression, the fixture-guard, and the invariants script. The three refactored fixtures (`worktree-monitor.test.ts`, `SafeGitExecutor.test.ts`, `rich-profile-integration.test.ts`) retain their pre-existing 45+ test assertions.
113
+ | Capability | How to Use |
114
+ |-----------|-----------|
115
+ | Telegram history backfill (script tier) | Operator-triggered. One-time auth via `node scripts/telegram-history-backfill.mjs --auth --phone +X...` plus a Secret Drop form for the SMS code, then `--chat <supergroup-id>` to walk every topic. |
116
+ | Idempotent topic-memory imports | Built on the existing `UNIQUE(message_id, topic_id)` constraint plus `INSERT OR IGNORE`. Re-running the backfill is a no-op for already-imported rows. |
117
+ | Session-string persistence | Stored at `~/.local/share/instar-echo-secrets/telegram-mtproto.session` (mode 0600, outside any git tree). Re-runs after the first auth are non-interactive. |
118
+ | GIT_DIR-leak hardening (carried from #286) | Automatic. Test runner strips the GIT_DIR env family before any test loads; pre-push fixture guard refuses pushes carrying fixture-style commits; CI repo-invariants job catches README clobbers and stowaway files. |
119
+
120
+ ## Deferred (Tracked Follow-ups)
121
+
122
+ - Promotion of the backfill to a full `src/messaging/TelegramHistorian.ts`
123
+ feature with three-tier tests (integration + e2e), an HTTP route on
124
+ the agent server, a CLI subcommand on the `instar` binary, an
125
+ agent-template update so every agent surfaces it, and a migration
126
+ parity entry for existing agents. The script-tier primitive shipping
127
+ now is the proof of concept and the recovery delivery; the durable
128
+ feature is the next PR.
129
+ - Bitwarden as the canonical credential source. The credentials live
130
+ in BW already (secure-note item created during the auth handshake),
131
+ but the script reads from the sealed local file at
132
+ `~/.local/share/instar-echo-secrets/telegram-mtproto.json`. A small
133
+ follow-up wires the script to pull from `bw get` when BW is
134
+ unlocked, falling back to the sealed file when not.
135
+ - Secret Drop hardening — the bridge that pulls a submitted code out
136
+ of the in-memory store and writes it to the auth script's poll file
137
+ had a parsing bug on first ship that consumed the code without
138
+ extracting it, losing the value. Server-side fix planned: stop
139
+ auto-deleting submissions on first retrieve; rely on the existing
140
+ 5-minute timeout for cleanup; add an explicit `?consume=true`
141
+ parameter for callers that want one-shot semantics. Design approved
142
+ by operator 2026-05-20; implementation is the next PR after this
143
+ one lands.
@@ -0,0 +1,71 @@
1
+ # Upgrade Guide — v1.2.1 (Secret Drop hardening — non-destructive retrieve + stuck-consumer event)
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ The `/secrets/retrieve/<token>` endpoint is now **non-destructive by
8
+ default**. Repeated calls return the same value until the in-memory
9
+ 5-minute cleanup timer fires. Callers that need one-shot semantics opt
10
+ in by appending `?consume=true` to the URL.
11
+
12
+ Three concrete surface changes in `src/server/SecretDrop.ts` and
13
+ `src/server/routes.ts`:
14
+
15
+ 1. **Two new methods on `SecretDrop`.** `peekReceived(token)` returns
16
+ the submission without removing it; `consumeReceived(token)` returns
17
+ AND removes it. The existing `getReceived(token)` is preserved as a
18
+ back-compat alias for `consumeReceived(token)` so no caller breaks.
19
+
20
+ 2. **The retrieve route honors `?consume=true`.** Default behavior is
21
+ `peek`. The response includes a `consumed: boolean` field so callers
22
+ can self-check which path ran.
23
+
24
+ 3. **Stuck-consumer event.** If a submission lingers in the in-memory
25
+ store for >60 seconds without being explicitly consumed, every
26
+ registered listener is invoked with a `StuckConsumerEvent`. The
27
+ default route-layer listener routes a `[secret-drop-stuck]` system
28
+ message to the bound topic's agent session, giving the operator a
29
+ visible cue that the consumer chain broke.
30
+
31
+ ## Evidence
32
+
33
+ Reproduction prior: on 2026-05-20 in topic 10873, a bridge script
34
+ called `/secrets/retrieve/<token>`, the server returned the submitted
35
+ SMS code AND deleted it atomically, and the bridge's parser dropped
36
+ the value on the way to disk. The code was lost; Telegram had to send
37
+ a fresh one. Pattern verified end-to-end in
38
+ `tests/unit/secret-drop-hardening.test.ts` ("regression: 2026-05-20
39
+ lost-SMS-code scenario"): the test reproduces the buggy-consumer drop
40
+ and asserts that under the hardening a retry succeeds because the
41
+ submission is still in the store.
42
+
43
+ Reproduction after: same buggy-consumer flow. First call returns the
44
+ value AND it stays in the store. The buggy parser fails. Second call
45
+ returns the value again. Caller fixes the parse and explicitly
46
+ consumes. No code is lost.
47
+
48
+ Idempotency, grace-period, and listener-isolation contracts verified
49
+ by 13 unit cases. The pre-existing `tests/unit/SecretDrop.test.ts`
50
+ suite (25 cases) continues to pass — no back-compat regressions.
51
+
52
+ ## What to Tell Your User
53
+
54
+ - "I made my own secret-handling more forgiving. The bug that lost your one-time code earlier today can't repeat without a deliberate opt-in — my pickup process can now retry a failed handoff inside the 5-minute window instead of losing the value on the first attempt. And if something does sit unread for more than a minute, I now get a visible alert telling me to look at it, rather than silently waiting on a value that's already gone."
55
+
56
+ ## Summary of New Capabilities
57
+
58
+ | Capability | How to Use |
59
+ |-----------|-----------|
60
+ | Non-destructive retrieve (default) | Agent calls `POST /secrets/retrieve/<token>`. Same call repeated within ~5 min returns the same value. |
61
+ | Explicit consume path | Agent appends `?consume=true` to commit a one-shot read. Response includes `consumed: true`. |
62
+ | Stuck-consumer event | Automatic. If a submission isn't consumed within 60s, a `[secret-drop-stuck]` system message routes to the bound topic's agent session. |
63
+
64
+ ## Deferred (Tracked Follow-ups)
65
+
66
+ - Configurable grace period per-request (currently a hard-coded 60s
67
+ constant). Will be added when a real need surfaces.
68
+ - Updating the bridge script in the parallel
69
+ `scripts/telegram-history-backfill.mjs` PR to read non-destructively
70
+ by default, parse first, and only consume after a successful parse.
71
+ That refactor lives in a separate commit after this PR lands.