instar 1.3.521 → 1.3.523
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +100 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +16 -1
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/MeshRpc.d.ts +5 -0
- package/dist/core/MeshRpc.d.ts.map +1 -1
- package/dist/core/MeshRpc.js +8 -0
- package/dist/core/MeshRpc.js.map +1 -1
- package/dist/core/StoreSnapshot.d.ts +455 -0
- package/dist/core/StoreSnapshot.d.ts.map +1 -0
- package/dist/core/StoreSnapshot.js +786 -0
- package/dist/core/StoreSnapshot.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/stateSyncConfig.js +1 -1
- package/dist/core/stateSyncConfig.js.map +1 -1
- package/dist/core/storeSnapshotBuild.worker.d.ts +2 -0
- package/dist/core/storeSnapshotBuild.worker.d.ts.map +1 -0
- package/dist/core/storeSnapshotBuild.worker.js +32 -0
- package/dist/core/storeSnapshotBuild.worker.js.map +1 -0
- package/dist/core/types.d.ts +17 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/OrphanedWorkSentinel.d.ts +148 -0
- package/dist/monitoring/OrphanedWorkSentinel.d.ts.map +1 -0
- package/dist/monitoring/OrphanedWorkSentinel.js +177 -0
- package/dist/monitoring/OrphanedWorkSentinel.js.map +1 -0
- package/dist/monitoring/guardManifest.d.ts.map +1 -1
- package/dist/monitoring/guardManifest.js +14 -0
- package/dist/monitoring/guardManifest.js.map +1 -1
- package/dist/monitoring/orphanedWorkGit.d.ts +30 -0
- package/dist/monitoring/orphanedWorkGit.d.ts.map +1 -0
- package/dist/monitoring/orphanedWorkGit.js +124 -0
- package/dist/monitoring/orphanedWorkGit.js.map +1 -0
- package/dist/server/AgentServer.d.ts +3 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +1 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +11 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.522.md +25 -0
- package/upgrades/1.3.523.md +31 -0
- package/upgrades/side-effects/hlc-step3-snapshot-tail.md +133 -0
- package/upgrades/side-effects/orphaned-work-sentinel.md +40 -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-13T11:15:43.520Z",
|
|
5
|
+
"instarVersion": "1.3.523",
|
|
6
6
|
"entryCount": 201,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -418,7 +418,7 @@
|
|
|
418
418
|
"type": "route-group",
|
|
419
419
|
"domain": "monitoring",
|
|
420
420
|
"sourcePath": "src/server/routes.ts",
|
|
421
|
-
"contentHash": "
|
|
421
|
+
"contentHash": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
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": "0f8ee3aeadbc20cceb8d717583d9a195174679a1a181f87fc1ef04b6a4263d58",
|
|
774
774
|
"since": "2025-01-01"
|
|
775
775
|
},
|
|
776
776
|
"cli:init": {
|
|
@@ -1522,7 +1522,7 @@
|
|
|
1522
1522
|
"type": "subsystem",
|
|
1523
1523
|
"domain": "server",
|
|
1524
1524
|
"sourcePath": "src/server/AgentServer.ts",
|
|
1525
|
-
"contentHash": "
|
|
1525
|
+
"contentHash": "db7ec67cd606ba59dba8acb7f821204a795b7425acb404482a9b5f416f94a1f6",
|
|
1526
1526
|
"since": "2025-01-01"
|
|
1527
1527
|
},
|
|
1528
1528
|
"subsystem:session-manager": {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: minor -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
A new dark, dev-gated, signal-only monitoring component — **OrphanedWorkSentinel** — detects agent worktrees that hold uncommitted work whose owning session has died and settled, records each durably, and raises ONE deduped agent-health attention item. It needs nothing registered: it reads the stranded work straight off disk (worktree dirty + no live process/lock + quiet for a settle window), closing the gap the PromiseBeacon escalation ladder (#1093/#1097) cannot see — that ladder acts only on REGISTERED commitments, while this catches code stranded by a dead build/autonomous session with no obligation representing it.
|
|
9
|
+
|
|
10
|
+
It is the inverse of `AgentWorktreeReaper` (which reclaims clean+merged+idle worktrees and leaves anything dirty alone) and shares the same git signal sources so worktree discovery + process-cwd liveness have ONE implementation. An optional, off-by-default `preserveWork` writes a NON-destructive preservation patch (read-only `git diff` to a state-dir file; never mutates the worktree, index, or ref). Read surface: `GET /orphaned-work` (503 when dark, 200 when live). Ships dark on the fleet, live on the development agent via the `developmentAgent` dark-feature gate.
|
|
11
|
+
|
|
12
|
+
audience: agent-only
|
|
13
|
+
maturity: experimental
|
|
14
|
+
|
|
15
|
+
## What to Tell Your User
|
|
16
|
+
|
|
17
|
+
Nothing to announce — this is an experimental, agent-only safety net that runs quietly in the background. If anyone asks: I now notice when a background work session dies before saving its changes, so that work gets surfaced instead of vanishing silently.
|
|
18
|
+
|
|
19
|
+
## Summary of New Capabilities
|
|
20
|
+
|
|
21
|
+
| Capability | How to Use |
|
|
22
|
+
|-----------|-----------|
|
|
23
|
+
| Detect work stranded by a dead session | Automatic (dark on fleet, live on dev agent) |
|
|
24
|
+
| Inspect orphaned-work findings | `GET /orphaned-work` |
|
|
25
|
+
| Non-destructive preservation patch | Off by default; opt-in config |
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The **snapshot-then-tail** join/recover path for cross-machine memory stores — so a returning / compacted / long-dark machine never replays a peer's journal from genesis. This step builds the GENERIC substrate ONLY; it adds no concrete store kind (that lands with the first store, WS2.1). Per `docs/specs/multi-machine-replicated-store-foundation.md` §6 / §8.2.
|
|
9
|
+
|
|
10
|
+
- **Single-origin snapshots** (`src/core/StoreSnapshot.ts`) — a peer materializes the current state of the records **it itself authored** (`origin === serving machine`, the first-hop anti-forgery invariant enforced at build AND at the receive door, so a compromised peer can never smuggle a record under another machine's name). A multi-origin store is recovered by snapshot-then-tailing each origin separately.
|
|
11
|
+
- **Seq-watermark VECTOR + the cutover** — the snapshot carries a per-`(origin, kind)` sequence watermark (not a scalar — a scalar would silently lose a lagging stream's record). `applySnapshotCutover()` seeds the applier's cursor to that watermark, then tails the UNCHANGED `buildServeBatch` seq transport, so the no-gap / no-double-apply guarantee is inherited from the existing seq-contiguity. The hybrid logical clock is demoted to a belt-and-suspenders duplicate filter. Re-running the whole snapshot-then-tail is idempotent.
|
|
12
|
+
- **Tombstone safety** — a per-key deleted-keys high-water seed blocks a stale pre-delete edit from resurrecting a key after the tombstone record itself rotates out.
|
|
13
|
+
- **Off-event-loop build + bounded cache** — `StoreSnapshotEngine` runs the whole-store materialization in a worker thread (the instar#1069 discipline, mirroring `CartographerSweepEngine`); `SnapshotCache` is a fixed-ceiling LRU ring (count AND bytes, NOT pool-scaled) with a `cacheLossCounter`, and `SnapshotRebuildBreaker` bounds rebuild storms from a flapping peer. An over-cap (truncated) build is a HARD REFUSAL — never a silent partial — so a consumer can never seed the cursor past dropped records.
|
|
14
|
+
- **Mesh verb + config** — a new `state-snapshot` read/observe verb (`src/core/MeshRpc.ts`) pulls the snapshot over the existing authenticated mesh RPC (no LAN/broadcast — scales to N cloud machines). `DEFAULT_MAX_CACHE_BYTES` reconciled 32 MiB → 64 MiB to match spec §8.2.
|
|
15
|
+
|
|
16
|
+
Pure MECHANISM, dark by default (`multiMachine.stateSync.*`, default false). The only refusal surfaces are at the receive door (anti-forgery) and the build door (rebuild breaker / truncation refusal); neither blocks a user-initiated action. A single-machine install is a strict no-op (no peer to pull from, nothing to materialize).
|
|
17
|
+
|
|
18
|
+
## What to Tell Your User
|
|
19
|
+
|
|
20
|
+
None — internal substrate (no user-facing surface). The cross-machine memory features that USERS will notice (preferences/relationships following them across machines) land in later WS2.x steps that consume this foundation.
|
|
21
|
+
|
|
22
|
+
## Summary of New Capabilities
|
|
23
|
+
|
|
24
|
+
None — internal substrate. New internal modules: `StoreSnapshot.ts` (single-origin snapshot + cutover + cache + rebuild breaker), `storeSnapshotBuild.worker.ts` (off-loop build worker), the `state-snapshot` mesh verb. All dark by default; no new user-facing API surface.
|
|
25
|
+
|
|
26
|
+
## Evidence
|
|
27
|
+
|
|
28
|
+
- `tests/unit/StoreSnapshot.test.ts` — single-origin anti-forgery (cross-origin entries dropped at build; wire snapshot with any foreign-origin record rejected wholesale), per-`(origin,kind)` watermark-vector correctness, seq-driven cutover completeness across a simulated multi-origin pool + idempotent re-apply, tombstone-resurrection drop, cache LRU eviction + `cacheLossCounter` (count + byte ceilings), rebuild breaker bounded across windows (reset + cooldown), and truncation-refusal (cutover throws, serve returns `build-truncated` + does not cache). Green.
|
|
29
|
+
- `tests/integration/store-snapshot-mesh.test.ts` — the REAL compiled off-event-loop worker (dist) builds a bounded snapshot and a 60k-record build keeps main-loop lag < 250 ms (the instar#1069 proof); the `state-snapshot` verb flows through the full mesh dispatcher (verify → RBAC → handler) and serves a single-origin snapshot; the Step-3 substrate (empty registry) answers `no-entries` (strict no-op). Green.
|
|
30
|
+
- `tests/unit/MeshRpc.test.ts` — `state-snapshot` is read/observe RBAC class (any registered peer; self-binding, no router/owner role). Green.
|
|
31
|
+
- Gates: `tsc --noEmit` clean; `no-silent-fallbacks` green (untrusted-wire-reject catches tagged); `lint-dev-agent-dark-gate` green; `docs-coverage --check` exit 0 (StoreSnapshot sections added to `multi-machine.md` + `under-the-hood.md`).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Side-Effects Review — HLC Foundation Step 3 (snapshot-then-tail)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `hlc-step3-snapshot-tail`
|
|
4
|
+
**Date:** `2026-06-13`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `echo (Phase-5 reviewer subagent)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Implements Component 4 (snapshot-then-tail) of the multi-machine replicated-store foundation (`docs/specs/multi-machine-replicated-store-foundation.md` §6). GENERIC substrate only — there is NO concrete store kind (preferences/relationships are later consumers). New `src/core/StoreSnapshot.ts` exports: `materializeSnapshot()` (single-origin materialization, §6.1/§6.2), the per-`(origin,kind)` seq-watermark VECTOR (§6.6), `applySnapshotCutover()` (seeds `lastHeldSeq = snapshotSeq` then rides the UNCHANGED `buildServeBatch` seq transport — §6.3, HLC demoted to secondary dedup §6.4), the deleted-keys high-water seed (§6.5 tombstone safety), `SnapshotCache` (fixed-ceiling LRU ring + `cacheLossCounter`, §8.2), `SnapshotRebuildBreaker` (§6.3 rebuild-storm bound), `StoreSnapshotEngine` (orchestrates an OFF-event-loop worker build mirroring `CartographerSweepEngine`, instar#1069), and `validateWireSnapshot()` (the receiver anti-forgery gate). New `src/core/storeSnapshotBuild.worker.ts` is the trivial worker entrypoint. `src/core/MeshRpc.ts` gains a `state-snapshot` read/observe verb. `src/commands/server.ts` constructs the engine + registers the dark-gated mesh handler. `src/core/stateSyncConfig.ts` + `src/config/ConfigDefaults.ts` reconcile `DEFAULT_MAX_CACHE_BYTES` 32 MiB → 64 MiB to match spec §8.2. Ships dark/additive behind `multiMachine.stateSync.*` (default false); a single-machine agent is a strict no-op.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- `validateWireSnapshot()` (receive-door anti-forgery) — **add** — rejects (returns null) any wire snapshot whose top-level/record/watermark `origin !== authenticated sender` (single-origin §6.1); the caller quarantines as untrusted-origin. Protects data, never blocks a user.
|
|
15
|
+
- `materializeSnapshot()` cross-origin drop — **add** — drops (counts) any own-stream entry whose `machine !== origin` at build time. Defense-in-depth, not a user gate.
|
|
16
|
+
- `applySnapshotCutover()` HLC-max merge + resurrection guard — **add** — a snapshot record is the winner only if HLC-greater than the present record AND not below the deleted-keys high-water. Mechanism, no user surface.
|
|
17
|
+
- `SnapshotRebuildBreaker.shouldRebuild()` — **add** — a build-side rate decision (serve cache / refuse) that bounds rebuild storms. Protects the holder's CPU; never touches user data.
|
|
18
|
+
- `MeshRpc` `state-snapshot` RBAC — **add (pass-through)** — read/observe class: any registered peer may issue it (same as journal-sync/preferences-sync). The single-origin invariant is the authority, not a role.
|
|
19
|
+
- `buildServeBatch` seq-contiguity — **pass-through** — the no-gap/no-double-apply guarantee is BORROWED unchanged from the existing applier; this change adds NO new gap-detection.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Over-block
|
|
24
|
+
|
|
25
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
26
|
+
|
|
27
|
+
The only block surface is `validateWireSnapshot()` at the receive door. It rejects a whole snapshot if any record's `origin` disagrees with the authenticated sender. A legitimate snapshot is ALWAYS single-origin by construction (the holder serves only its own authored records — the engine passes its own machine id as origin, never a peer field), so a well-formed snapshot from an honest peer is never rejected. A malformed/forged snapshot SHOULD be rejected — that is the §6.1 anti-forgery purpose. No legitimate input is over-blocked: a multi-origin store is recovered by snapshot-then-tailing EACH origin separately, each pull single-origin (§6.1), so the rejection of a cross-origin snapshot never blocks a real recovery.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 2. Under-block
|
|
32
|
+
|
|
33
|
+
**What failure modes does this still miss?**
|
|
34
|
+
|
|
35
|
+
**[RESOLVED by the Phase-5 second-pass review — truncation-under-seed gap trap.]** The reviewer found a real correctness trap that the first-pass review missed: `materializeSnapshot()` truncates the records set when over `maxSnapshotBytes` but keeps the FULL `snapshotSeq` watermark. If a truncated snapshot were applied, the cutover would seed `lastHeldSeq = snapshotSeq` while the snapshot is MISSING records at-or-below that seq — and the subsequent tail (`seq > snapshotSeq`) would never replay them, a SILENT GAP the seq-contiguity cannot catch (it starts above them). Originally the code only FLAGGED `truncated` and no caller refused it, while `server.ts` armed `maxSnapshotBytes = maxCacheBytes` (64 MiB) — so a future WS2.1 consumer would have inherited an armed under-seed. **Folded fix (in THIS PR, where the trap is introduced):** the `truncated` flag now travels ON the `StoreSnapshot` itself (not just the serve-result envelope); `StoreSnapshotEngine.serveSnapshot` REFUSES a truncated build with `build-truncated` (never caches/serves it — the caller falls back to a from-genesis tail, the complete path), and `applySnapshotCutover` THROWS on a truncated snapshot (a structural backstop even against a buggy/old holder that serves one anyway). `validateWireSnapshot` carries the flag off the wire so the backstop holds end-to-end. Three new tests assert it (`tests/unit/StoreSnapshot.test.ts`: cutover throws on truncated, serve returns `build-truncated` + does not cache, wire carries the flag). The real fix for an over-cap store is its per-kind retention bound (§8), not a silent partial.
|
|
36
|
+
|
|
37
|
+
Beyond that: `validateWireSnapshot()` enforces origin === sender but does NOT cryptographically per-record-sign (the spec §6.1/§11.1 names per-record signing as the heavier "alternative B," explicitly NOT chosen). So a COMPROMISED peer M can still forge arbitrary records under `origin = M` (its OWN namespace) — bounded exactly as the steady-state tail's first-hop binding already allows, and the operator's recourse is rollback-unmerge (§7.4, a later step). This is the documented threat-model boundary (§11.1: "a compromised peer is bounded to corrupting records under ITS OWN origin"), not a gap this step introduces. The §6.4 secondary HLC-identity dedup is belt-and-suspenders only — it does not catch a record with a NEW (recordKey, origin, hlc) identity that is semantically a duplicate; that is correct, because the seq-contiguity (the primary mechanism) already handles it. No remaining under-block beyond the spec-acknowledged boundary.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 3. Level-of-abstraction fit
|
|
42
|
+
|
|
43
|
+
**Is this at the right layer?**
|
|
44
|
+
|
|
45
|
+
Correct layer. The cutover deliberately RIDES the existing `JournalSyncApplier` seq-contiguity (lastHeldSeq+1) and `buildServeBatch` serve path rather than re-implementing gap detection — `applySnapshotCutover()` is injected with `CutoverApplierSeams` so it never duplicates the applier's logic; the real wiring binds those seams to the applier's PeerMeta. The off-event-loop build mirrors the established `CartographerSweepEngine`/`cartographerDetect.worker.ts` pattern (instar#1069) rather than inventing a new threading model. The cache + breaker are bounded primitives mirroring the quarantine ring's `lossCounter`. Nothing here re-implements a primitive that exists; it composes the existing transport.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 4. Signal vs authority compliance
|
|
50
|
+
|
|
51
|
+
**Required reference:** `docs/signal-vs-authority.md`
|
|
52
|
+
|
|
53
|
+
**Does this change hold blocking authority with brittle logic?**
|
|
54
|
+
|
|
55
|
+
- [x] No — this change has no block/allow surface over USER actions (it is pure mechanism: it orders, validates, caches, materializes, and un-merges; it never actuates and never decides a conflict winner).
|
|
56
|
+
|
|
57
|
+
The two refusals it does have — the receive-door anti-forgery rejection (`validateWireSnapshot`) and the build-side rebuild breaker — are both deterministic structural checks that protect the user's data / the holder's CPU, neither blocks a user-initiated action (spec §14: "No gate in this foundation blocks a user-initiated action"). The single-origin invariant is a STRUCTURAL property (origin === authenticated sender), not brittle content-pattern logic. The conflict-winner decision (the one judgment call) is explicitly deferred UP to the operator in a later step (`POST /state/resolve-conflict`, §7.3), not decided here.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 5. Interactions
|
|
62
|
+
|
|
63
|
+
**Does this interact with existing checks, recovery paths, or infrastructure?**
|
|
64
|
+
|
|
65
|
+
- **Shadowing:** The cutover seeds `PeerMeta.lastHeldSeq` then defers to the UNCHANGED applier serve/apply path — it does not shadow the existing seq-contiguity; it places the cursor and lets the existing rule run. The `seedLastHeldSeq` seam never LOWERS an already-advanced cursor (idempotent re-cutover does not rewind), so it cannot shadow steady-state replication progress.
|
|
66
|
+
- **Double-fire:** Re-running the whole snapshot-then-tail is safe (§6.3 step 5): the §6.4 HLC-identity dedup + the existing seq `duplicate` drop (seq ≤ lastHeldSeq) prevent double-apply. The unit test asserts a re-applied snapshot yields `applied: 0, dedupSkipped: N`.
|
|
67
|
+
- **Races:** The build runs on a worker thread and posts a single bounded result; the engine settles once (mirrors the cartographer worker's settle-once guard). The cache + breaker are main-thread, single-writer. No shared mutable state crosses the thread boundary (the worker receives a plain-object copy of `entriesByKind`).
|
|
68
|
+
- **Feedback loops:** A flapping peer that keeps requesting a rebuild is served the cache (within the min-interval) and rate-limited by the breaker (frequency cap → cooldown), so the request→rebuild loop is bounded across windows (the §12 #14 sustained-flapping invariant, covered by the breaker unit test).
|
|
69
|
+
|
|
70
|
+
In the Step-3 substrate the registry is EMPTY → the engine's `loadOwnEntries` returns no contributing kinds → the handler answers `no-entries` and the caller falls back to a from-genesis tail (the legacy behavior). So this change interacts with NOTHING at runtime until a concrete store (WS2.1) registers a kind.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 6. External surfaces
|
|
75
|
+
|
|
76
|
+
**Does this change anything visible outside the immediate code path?**
|
|
77
|
+
|
|
78
|
+
- **Other agents on the same machine:** none.
|
|
79
|
+
- **Other users of the install base:** none — dark by default; with no `stateSync.<store>.enabled` flag set the engine has nothing to materialize and the mesh handler answers `no-entries`. Default config preserves today's behavior exactly.
|
|
80
|
+
- **External systems:** the `state-snapshot` pull rides the EXISTING authenticated mesh RPC (Cloudflare tunnel, no LAN/broadcast); no new external endpoint, no new network posture.
|
|
81
|
+
- **Persistent state:** none added by this step (the deleted-keys high-water + namespaced storage are consumed via injected seams; the real persistence lands with the consumer PR). The config reconcile (`maxCacheBytes` 32→64 MiB) backfills via `applyDefaults`/`migrateConfig` add-missing semantics (Migration Parity) — an operator's explicit value is never overwritten.
|
|
82
|
+
- **Timing/runtime conditions:** the build timeout (120 s default) + worker heap ceiling (1536 MB) bound the build; a timeout returns `build-timeout` (the caller falls back), never a hang.
|
|
83
|
+
- **Operator surface (Mobile-Complete Operator Actions):** no operator-facing actions added in this step. The future operator surfaces (conflict resolution, rollback-unmerge) land with later steps and will carry their own phone-completable surfaces. "No operator-facing actions" — valid here.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
88
|
+
|
|
89
|
+
**When this agent runs on MORE THAN ONE machine, what is this feature's posture?**
|
|
90
|
+
|
|
91
|
+
**proxied-on-read** — this IS a cross-machine feature by design. A recovering machine PULLS a single-origin snapshot from a live holder of each origin's stream (the `state-snapshot` mesh verb), the holder builds it off-loop and may serve a cached copy. The merged read is the §7 union across per-origin namespaces (a later step); this step provides the snapshot PULL + cutover that populates one origin's namespace. Single-origin (§6.1) is the multi-machine security boundary: `origin === authenticated sender` holds end-to-end so a compromised peer cannot smuggle a foreign-origin record across the machine boundary.
|
|
92
|
+
|
|
93
|
+
- **User-facing notices:** none in this step (no one-voice gating needed).
|
|
94
|
+
- **Durable state on topic transfer:** the snapshot cache is machine-local + rebuildable (an eviction is a recompute, never a correctness loss), so it does not strand on transfer; the rollback-unmerge `dropOrigin` hook is provided for the later un-merge step.
|
|
95
|
+
- **URLs surviving machine boundaries:** none generated.
|
|
96
|
+
|
|
97
|
+
Phase-C (N machines, not 2): the snapshot is single-origin and the union is across N origins; the cache ceiling is a FIXED constant (NOT pool-scaled, §8.2) so a large pool rebuilds more often rather than growing the cache unboundedly; the rebuild breaker is per-(peer, origin, store) so N peers requesting the same snapshot are independent. The transport is mesh RPC (no LAN/broadcast). Scales to N cloud machines by construction.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 8. Rollback cost
|
|
102
|
+
|
|
103
|
+
**If this turns out wrong in production, what's the back-out?**
|
|
104
|
+
|
|
105
|
+
Pure code change, dark by default — revert and ship a patch. No persistent state is written by this step (the seams are injected; the real persistence lands with the consumer). The config reconcile (`maxCacheBytes` 32→64 MiB) is a default bump; reverting it is another default change (no migration needed — `applyDefaults` add-missing leaves an operator's explicit value untouched either way). No user-visible regression during the rollback window because nothing user-facing is enabled. The `multiMachine.stateSync.<store>.enabled` per-store flags (all default false) are the kill switch — turning every store off returns to byte-for-byte today's behavior.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Conclusion
|
|
110
|
+
|
|
111
|
+
This review confirms the change is pure, dark-by-default foundation mechanism with a single structural anti-forgery gate (`validateWireSnapshot`) that protects data and never blocks a user. The three requested adversarial lenses were applied: (1) **distributed-correctness / snapshot-cutover** — the no-gap/no-double-apply guarantee is borrowed unchanged from the existing seq-contiguity, HLC is correctly demoted to secondary dedup, and the watermark is a VECTOR (not a scalar) so a lagging stream is never silently excluded; idempotent re-cutover is asserted. (2) **cache-bounds / DoS** — the cache is a FIXED-ceiling LRU ring (count AND bytes, not pool-scaled) with a visible loss counter, and the per-peer rebuild breaker bounds rebuild storms across windows. (3) **integration-purity / Phase-C** — the build runs off the event loop in a worker (instar#1069), the transport is authenticated mesh RPC (no LAN), and every primitive is N-machine-correct. No design changes were required by the review. Clear to ship as dark/additive foundation.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Second-pass review (if required)
|
|
116
|
+
|
|
117
|
+
**Reviewer:** echo (Phase-5 reviewer subagent)
|
|
118
|
+
**Independent read of the artifact: concern raised → resolved in this PR.**
|
|
119
|
+
|
|
120
|
+
The reviewer independently confirmed the artifact's core conclusions against the code: the watermark IS a genuine per-`(origin,kind)` vector (not a scalar — BLOCKER-1 honored); HLC IS demoted to secondary dedup (`tailCursorAfterCutover` returns `snapshotSeq`, never HLC); re-cutover is idempotent; the tombstone high-water is seeded before puts apply (correct ordering, blocks resurrection); the cache is fixed-ceiling (count AND bytes, not pool-scaled) with `cacheLossCounter` bumping only on real LRU eviction (not on supersede); the breaker resets+cooldowns across windows; the build runs off the event loop in a real worker with a minimal secret-free env; single-origin is enforced end-to-end (materialize drops cross-origin AND `validateWireSnapshot` rejects it); the server handler passes the holder's OWN machine id as origin; the transport is authenticated mesh RPC; and there is no signal-vs-authority violation (no user-action gate).
|
|
121
|
+
|
|
122
|
+
**Concern raised:** the truncation-under-seed gap trap (detailed in §2 above) — a truncated snapshot kept the full `snapshotSeq` but no caller refused it, and `server.ts` armed `maxSnapshotBytes` to 64 MiB, so a future WS2.1 consumer would have seeded `lastHeldSeq` past dropped records, creating a silent sub-watermark gap that contradicts the "no-gap guarantee borrowed from seq-contiguity." The reviewer recommended closing the contract structurally in this PR (where the trap is introduced).
|
|
123
|
+
|
|
124
|
+
**Resolution (folded in this PR):** `truncated` now travels on the `StoreSnapshot`; `serveSnapshot` refuses with `build-truncated` (never caches/serves); `applySnapshotCutover` throws on a truncated snapshot; `validateWireSnapshot` carries the flag — a structural, end-to-end refusal so a consumer cannot under-seed by construction. Three new tests lock it. Concern resolved.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Evidence pointers
|
|
129
|
+
|
|
130
|
+
- Unit: `tests/unit/StoreSnapshot.test.ts` (26 tests — materialization/anti-forgery, cutover/idempotency, tombstone-resurrection drop, wire-validation forgery rejection, cache LRU + lossCounter, breaker across windows, engine orchestration). Green.
|
|
131
|
+
- Integration: `tests/integration/store-snapshot-mesh.test.ts` (5 tests — REAL dist off-loop worker build + event-loop-lag<250ms proof; full mesh dispatcher verify→rbac→handler round-trip; substrate no-entries no-op). Green.
|
|
132
|
+
- RBAC ratchet: `tests/unit/MeshRpc.test.ts` (state-snapshot read/observe RBAC). Green.
|
|
133
|
+
- Gates: `tsc --noEmit` clean; `no-silent-fallbacks` green (3 untrusted-wire-reject catches tagged `@silent-fallback-ok`); `lint-dev-agent-dark-gate` green (16); `feature-delivery-completeness` green (95); `docs-coverage --check` exit 0 (StoreSnapshot sections added to multi-machine.md + under-the-hood.md).
|