instar 1.3.319 → 1.3.321

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-06-05T20:42:29.342Z",
5
- "instarVersion": "1.3.319",
4
+ "generatedAt": "2026-06-05T22:14:45.187Z",
5
+ "instarVersion": "1.3.321",
6
6
  "entryCount": 199,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -778,7 +778,7 @@
778
778
  "type": "cli-command",
779
779
  "domain": "setup",
780
780
  "sourcePath": "src/cli.ts",
781
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
781
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
782
782
  "since": "2025-01-01"
783
783
  },
784
784
  "cli:setup": {
@@ -786,7 +786,7 @@
786
786
  "type": "cli-command",
787
787
  "domain": "setup",
788
788
  "sourcePath": "src/cli.ts",
789
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
789
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
790
790
  "since": "2025-01-01"
791
791
  },
792
792
  "cli:add": {
@@ -794,7 +794,7 @@
794
794
  "type": "cli-command",
795
795
  "domain": "setup",
796
796
  "sourcePath": "src/cli.ts",
797
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
797
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
798
798
  "since": "2025-01-01"
799
799
  },
800
800
  "cli:backup": {
@@ -802,7 +802,7 @@
802
802
  "type": "cli-command",
803
803
  "domain": "operations",
804
804
  "sourcePath": "src/cli.ts",
805
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
805
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
806
806
  "since": "2025-01-01"
807
807
  },
808
808
  "cli:git": {
@@ -810,7 +810,7 @@
810
810
  "type": "cli-command",
811
811
  "domain": "coordination",
812
812
  "sourcePath": "src/cli.ts",
813
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
813
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
814
814
  "since": "2025-01-01"
815
815
  },
816
816
  "cli:memory": {
@@ -818,7 +818,7 @@
818
818
  "type": "cli-command",
819
819
  "domain": "memory",
820
820
  "sourcePath": "src/cli.ts",
821
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
821
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
822
822
  "since": "2025-01-01"
823
823
  },
824
824
  "cli:knowledge": {
@@ -826,7 +826,7 @@
826
826
  "type": "cli-command",
827
827
  "domain": "memory",
828
828
  "sourcePath": "src/cli.ts",
829
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
829
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
830
830
  "since": "2025-01-01"
831
831
  },
832
832
  "cli:semantic": {
@@ -834,7 +834,7 @@
834
834
  "type": "cli-command",
835
835
  "domain": "memory",
836
836
  "sourcePath": "src/cli.ts",
837
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
837
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
838
838
  "since": "2025-01-01"
839
839
  },
840
840
  "cli:intent": {
@@ -842,7 +842,7 @@
842
842
  "type": "cli-command",
843
843
  "domain": "intent",
844
844
  "sourcePath": "src/cli.ts",
845
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
845
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
846
846
  "since": "2025-01-01"
847
847
  },
848
848
  "cli:feedback": {
@@ -850,7 +850,7 @@
850
850
  "type": "cli-command",
851
851
  "domain": "feedback",
852
852
  "sourcePath": "src/cli.ts",
853
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
853
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
854
854
  "since": "2025-01-01"
855
855
  },
856
856
  "cli:server": {
@@ -858,7 +858,7 @@
858
858
  "type": "cli-command",
859
859
  "domain": "server",
860
860
  "sourcePath": "src/cli.ts",
861
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
861
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
862
862
  "since": "2025-01-01"
863
863
  },
864
864
  "cli:status": {
@@ -866,7 +866,7 @@
866
866
  "type": "cli-command",
867
867
  "domain": "monitoring",
868
868
  "sourcePath": "src/cli.ts",
869
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
869
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
870
870
  "since": "2025-01-01"
871
871
  },
872
872
  "cli:user": {
@@ -874,7 +874,7 @@
874
874
  "type": "cli-command",
875
875
  "domain": "users",
876
876
  "sourcePath": "src/cli.ts",
877
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
877
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
878
878
  "since": "2025-01-01"
879
879
  },
880
880
  "cli:relationship": {
@@ -882,7 +882,7 @@
882
882
  "type": "cli-command",
883
883
  "domain": "relationships",
884
884
  "sourcePath": "src/cli.ts",
885
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
885
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
886
886
  "since": "2025-01-01"
887
887
  },
888
888
  "cli:job": {
@@ -890,7 +890,7 @@
890
890
  "type": "cli-command",
891
891
  "domain": "scheduling",
892
892
  "sourcePath": "src/cli.ts",
893
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
893
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
894
894
  "since": "2025-01-01"
895
895
  },
896
896
  "cli:lifeline": {
@@ -898,7 +898,7 @@
898
898
  "type": "cli-command",
899
899
  "domain": "communication",
900
900
  "sourcePath": "src/cli.ts",
901
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
901
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
902
902
  "since": "2025-01-01"
903
903
  },
904
904
  "cli:list": {
@@ -906,7 +906,7 @@
906
906
  "type": "cli-command",
907
907
  "domain": "monitoring",
908
908
  "sourcePath": "src/cli.ts",
909
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
909
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
910
910
  "since": "2025-01-01"
911
911
  },
912
912
  "cli:autostart": {
@@ -914,7 +914,7 @@
914
914
  "type": "cli-command",
915
915
  "domain": "operations",
916
916
  "sourcePath": "src/cli.ts",
917
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
917
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
918
918
  "since": "2025-01-01"
919
919
  },
920
920
  "cli:migrate": {
@@ -922,7 +922,7 @@
922
922
  "type": "cli-command",
923
923
  "domain": "updates",
924
924
  "sourcePath": "src/cli.ts",
925
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
925
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
926
926
  "since": "2025-01-01"
927
927
  },
928
928
  "cli:machines": {
@@ -930,7 +930,7 @@
930
930
  "type": "cli-command",
931
931
  "domain": "coordination",
932
932
  "sourcePath": "src/cli.ts",
933
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
933
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
934
934
  "since": "2025-01-01"
935
935
  },
936
936
  "cli:whoami": {
@@ -938,7 +938,7 @@
938
938
  "type": "cli-command",
939
939
  "domain": "identity",
940
940
  "sourcePath": "src/cli.ts",
941
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
941
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
942
942
  "since": "2025-01-01"
943
943
  },
944
944
  "cli:pair": {
@@ -946,7 +946,7 @@
946
946
  "type": "cli-command",
947
947
  "domain": "coordination",
948
948
  "sourcePath": "src/cli.ts",
949
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
949
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
950
950
  "since": "2025-01-01"
951
951
  },
952
952
  "cli:join": {
@@ -954,7 +954,7 @@
954
954
  "type": "cli-command",
955
955
  "domain": "coordination",
956
956
  "sourcePath": "src/cli.ts",
957
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
957
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
958
958
  "since": "2025-01-01"
959
959
  },
960
960
  "cli:wakeup": {
@@ -962,7 +962,7 @@
962
962
  "type": "cli-command",
963
963
  "domain": "coordination",
964
964
  "sourcePath": "src/cli.ts",
965
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
965
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
966
966
  "since": "2025-01-01"
967
967
  },
968
968
  "cli:leave": {
@@ -970,7 +970,7 @@
970
970
  "type": "cli-command",
971
971
  "domain": "coordination",
972
972
  "sourcePath": "src/cli.ts",
973
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
973
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
974
974
  "since": "2025-01-01"
975
975
  },
976
976
  "cli:doctor": {
@@ -978,7 +978,7 @@
978
978
  "type": "cli-command",
979
979
  "domain": "monitoring",
980
980
  "sourcePath": "src/cli.ts",
981
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
981
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
982
982
  "since": "2025-01-01"
983
983
  },
984
984
  "cli:review": {
@@ -986,7 +986,7 @@
986
986
  "type": "cli-command",
987
987
  "domain": "monitoring",
988
988
  "sourcePath": "src/cli.ts",
989
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
989
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
990
990
  "since": "2025-01-01"
991
991
  },
992
992
  "cli:nuke": {
@@ -994,7 +994,7 @@
994
994
  "type": "cli-command",
995
995
  "domain": "operations",
996
996
  "sourcePath": "src/cli.ts",
997
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
997
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
998
998
  "since": "2025-01-01"
999
999
  },
1000
1000
  "cli:playbook": {
@@ -1002,7 +1002,7 @@
1002
1002
  "type": "cli-command",
1003
1003
  "domain": "context",
1004
1004
  "sourcePath": "src/cli.ts",
1005
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
1005
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
1006
1006
  "since": "2025-01-01"
1007
1007
  },
1008
1008
  "cli:dev-preflight": {
@@ -1010,7 +1010,7 @@
1010
1010
  "type": "cli-command",
1011
1011
  "domain": "development",
1012
1012
  "sourcePath": "src/cli.ts",
1013
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
1013
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
1014
1014
  "since": "2025-01-01"
1015
1015
  },
1016
1016
  "cli:dev-ci-failures": {
@@ -1018,7 +1018,7 @@
1018
1018
  "type": "cli-command",
1019
1019
  "domain": "development",
1020
1020
  "sourcePath": "src/cli.ts",
1021
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
1021
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
1022
1022
  "since": "2025-01-01"
1023
1023
  },
1024
1024
  "cli:dev-profile-node": {
@@ -1026,7 +1026,7 @@
1026
1026
  "type": "cli-command",
1027
1027
  "domain": "development",
1028
1028
  "sourcePath": "src/cli.ts",
1029
- "contentHash": "e4f500dbdb5e986b90f211b0890134effbc477a7d123a2f9282c6082fa87ae66",
1029
+ "contentHash": "189bf25909698ef7aeeaa7b59dc8b737096bcaa64ff32e693f63c4654c311032",
1030
1030
  "since": "2025-01-01"
1031
1031
  },
1032
1032
  "template:build-stop-hook.sh": {
@@ -1162,7 +1162,7 @@
1162
1162
  "type": "template",
1163
1163
  "domain": "operations",
1164
1164
  "sourcePath": "src/templates/scripts/instar-watchdog.sh",
1165
- "contentHash": "5bd48e727691adcb9e1aaee2d61af192f54ed6d1244ca1931422a5926c7d9d10",
1165
+ "contentHash": "207d3cf08ac5bd1030dd35f6d30f472aef9c087e5635e23d92bd574d6291af6b",
1166
1166
  "since": "2025-01-01"
1167
1167
  },
1168
1168
  "template:instar-worktree-create.sh": {
@@ -1514,7 +1514,7 @@
1514
1514
  "type": "subsystem",
1515
1515
  "domain": "sessions",
1516
1516
  "sourcePath": "src/core/SessionManager.ts",
1517
- "contentHash": "a6cf21efd904fb1c7d274d03c92ef7c368f14de8471242905f9a78ad43da47d5",
1517
+ "contentHash": "90f71f02aaeac3edcf5cd62d854b74e35ed77fd257e351d55f4391f9bb9cfa8b",
1518
1518
  "since": "2025-01-01"
1519
1519
  },
1520
1520
  "subsystem:auto-updater": {
@@ -468,7 +468,11 @@ probe_server_identity() {
468
468
  if [ -n "$auth_token" ]; then
469
469
  auth_args=(-H "Authorization: Bearer $auth_token" -H "X-Instar-AgentId: $agent_id")
470
470
  fi
471
- resp=$(curl -sS --max-time 5 -w '\n%{http_code}' "${auth_args[@]}" "http://localhost:${port}/health" 2>/dev/null || echo $'\n000')
471
+ if [ -n "$auth_token" ]; then
472
+ resp=$(curl -sS --max-time 5 -w '\n%{http_code}' "${auth_args[@]}" "http://localhost:${port}/health" 2>/dev/null || echo $'\n000')
473
+ else
474
+ resp=$(curl -sS --max-time 5 -w '\n%{http_code}' "http://localhost:${port}/health" 2>/dev/null || echo $'\n000')
475
+ fi
472
476
  http_code=$(echo "$resp" | tail -n1)
473
477
  body=$(echo "$resp" | sed '$d')
474
478
 
@@ -0,0 +1,20 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The SessionManager age-gate (the 5-second monitor tick) used to re-request a kill for an over-age, idle-at-prompt session on EVERY tick. When the §P2 KEEP-guard correctly vetoed that kill (the session had a recent user message, was topic-bound, or held an open commitment), the session survived — but the gate re-asked 5 seconds later, forever. On 2026-06-05 this produced 17,503 identical kill-request log lines for kept sessions plus the wasted CPU that read as "heavy load." A new pure, bounded `AgeKillBackoff` ledger makes the age-gate RESPECT the guard's verdict: after a veto it suppresses re-requests for `ageKillBackoffMinutes` (default 10) — ~6 asks/hour instead of 720 — collapsing to ONE informative log line. It changes only how OFTEN the age-gate asks, never WHICH sessions die: the KEEP-guard remains the sole authority, and a genuinely-abandoned session (no keep-reason) still dies on the first ask exactly as before.
9
+
10
+ ## What to Tell Your User
11
+
12
+ Your long-lived working sessions no longer get hammered by a kill-request loop they always survive — the churn (and the log/CPU noise it caused) is gone, while nothing about which sessions actually get cleaned up has changed.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - Age-gate kill back-off: a vetoed kill is honored for a back-off window instead of being re-asked every tick. Tunable via `ageKillBackoffMinutes` in config (default 10; `0` restores the legacy every-tick behavior). Existing agents get the fix automatically on update — the default lives in code, no config migration required.
17
+
18
+ ## Evidence
19
+
20
+ Live incident 2026-06-05: 17,503 identical "Requesting kill"/deferral lines for over-age sessions (this conversation's topic plus three other long-lived sessions), every one correctly vetoed by the KEEP-guard — wasted CPU that surfaced to the operator as "resource issues." Root cause: the age-gate at `SessionManager.monitorTick` re-requested a kill every 5s with no memory of the prior veto. Fix: `src/core/AgeKillBackoff.ts` (pure, injectable clock, bounded `maxTracked` memory, mirrors `AttentionTopicGuard`), wired into the age-gate to `recordVeto`/`recordKilled` and gate re-asks via `shouldRequest`. Spec `docs/specs/age-kill-backoff.md` (converged + approved). Tests: 11 green — 7 unit (incl. a 720→6 asks/hour regression pin) + 4 integration against the real SessionManager ledger; tsc clean.
@@ -0,0 +1,25 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Instar now has a post-drive transcript auditor for operator-seat UX review. Given topic ids and a drive window, it reads the existing topic message history, classifies duplicate notices or deliveries, resend or retry asks, internal infrastructure noise, and content-free status updates, then files each finding into the framework issue ledger with a stable dedupe key.
9
+
10
+ The framework issue ledger also now preserves related-spec citations when observations are recorded, so findings can keep their link to Observation Needs Structure and the UX-blindspot work instead of losing that context after the write.
11
+
12
+ ## What to Tell Your User
13
+
14
+ I can now audit a supervised Telegram drive after it happens and turn visible friction into durable findings instead of leaving it buried in chat.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ | Capability | How to Use |
19
+ |-----------|-----------|
20
+ | Post-drive transcript UX audit | Run the new developer audit command with topic ids and a time window. |
21
+ | Framework issue citations | Automatic when an observation includes a parent-principle or related-spec citation. |
22
+
23
+ ## Evidence
24
+
25
+ Live fixture verification used topics 2278 and 2271 for the 11:15-11:21 PDT window on 2026-06-05. Dry-run first reported one duplicate-delivery group and two content-free status-notice groups after the ACK false positive was removed. Filing mode then wrote three framework issue observations with stable dedupe keys; rerunning the command deduped them instead of creating duplicates. Targeted tests passed for 50 cases across the auditor and framework issue ledger suites, build passed, lint passed, and the Tier-1 dev gate accepted the ELI16 plus side-effects artifacts.
@@ -0,0 +1,75 @@
1
+ # Side-Effects Review — Age-Timeout Kill Back-off
2
+
3
+ **Version / slug:** `age-kill-backoff`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `Echo (instar-dev agent)`
6
+ **Second-pass reviewer:** `independent reviewer subagent — CONCUR (with one non-blocking accuracy fix, since applied)`
7
+
8
+ ## Summary of the change
9
+
10
+ The `SessionManager` age-gate (`monitorTick`, runs every 5s) used to re-request a kill for an over-age, idle-at-prompt session on every tick. When the §P2 KEEP-guard inside `terminateSession` vetoed the kill (returning `{ terminated:false, skipped:<reason> }` for a session with a recent user message / topic binding / open commitment), the session survived but the gate threw away that verdict and re-asked 5s later — forever (the 2026-06-05 17,503-line flood + wasted CPU read as "heavy load"). This change adds a pure, bounded back-off ledger (`src/core/AgeKillBackoff.ts`) and wires it into the age-gate (`src/core/SessionManager.ts`): after a veto, `recordVeto` suppresses re-requests for `ageKillBackoffMinutes` (default 10, new optional field on `SessionManagerConfig` in `src/core/types.ts`); `shouldRequest` gates the re-ask; `recordKilled` cleans up on an actual kill. Files touched: `AgeKillBackoff.ts` (new), `SessionManager.ts` (import + construct + gate the age-kill branch), `types.ts` (one optional config field). Decision point: the age-gate's kill-request *frequency* only — never the kill *decision* itself.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `SessionManager.monitorTick age-gate` — **modify** — gates how OFTEN it re-requests a kill for a kept over-age session; does not change the kill predicate.
15
+ - `§P2 KEEP-guard inside terminateSession` — **pass-through** — unchanged; remains the sole authority over WHICH sessions die. The back-off only consumes its verdict.
16
+ - `AgeKillBackoff ledger` — **add** — a pure signal-suppressor (no kill authority of its own).
17
+
18
+ ## 1. Over-block
19
+
20
+ **What legitimate inputs does this change reject that it shouldn't?**
21
+
22
+ The only thing "suppressed" is a redundant *kill request* for a session the guard ALREADY decided to keep within the last `backoffMs`. It never suppresses a kill of a genuinely-reapable session: a session is only in back-off because its most recent kill request was vetoed (kept). The one edge worth naming: a session kept at T0 whose keep-reason lapses at T0+1min is not re-evaluated until the back-off window expires (≤10min) — so a now-abandoned session lingers at most ~10 extra minutes before its first re-ask. That is a delay in *cleanup of an idle session*, not an over-block of any live work, and it is bounded and reversible (`ageKillBackoffMinutes: 0` restores instant re-checks). Note a re-engaged session needs no special handling: its new injection makes it non-idle, so the age-gate takes its active-work branch (never the kill branch) — it is never age-killed while active regardless of the back-off window. (`reset()`/`clear()` exist as ledger-maintenance API exercised by the unit suite but are intentionally NOT wired into the injection/removal paths in this PR — they would be redundant given the active-work branch, and memory is already bounded by `maxTracked` eviction.)
23
+
24
+ ## 2. Under-block
25
+
26
+ **What failure modes does this still miss?**
27
+
28
+ It does not unify the two redundant mechanisms (the crude age-gate and the sophisticated `SessionReaper`) — that larger refactor is tracked separately (spec §Follow-up, topic-18423). It also does not change the age THRESHOLD (still `maxDurationMinutes + 20%`); a mis-tuned threshold would still mis-classify, just without the flood. Neither is a regression — both are pre-existing and out of this fix's stated scope. A `backoffMs` set absurdly high by an operator would delay legitimate cleanup of abandoned sessions, but the KEEP-guard still gates the eventual kill, so nothing dies wrongly.
29
+
30
+ ## 3. Level-of-abstraction fit
31
+
32
+ **Is this at the right layer?**
33
+
34
+ Yes. It is a low-level, deterministic suppressor sitting at the exact layer that was generating the redundant requests (the age-gate inside `monitorTick`). It deliberately does NOT re-implement the reap decision — it consumes the existing authority's verdict. It mirrors the established `AttentionTopicGuard` pattern (pure logic, injectable clock, bounded memory) rather than inventing a new shape. The smarter authority (`terminateSession`/KEEP-guard) already exists and is FED by this, not duplicated.
35
+
36
+ ## 4. Signal vs authority compliance
37
+
38
+ **Required reference:** `docs/signal-vs-authority.md`
39
+
40
+ - [x] No — this change produces a signal (a "stop asking for now" suppressor) consumed by / feeding the existing smart authority; it holds NO kill authority.
41
+
42
+ The back-off ledger cannot kill anything. It can only make the age-gate *skip a redundant request*. The kill decision remains 100% with `terminateSession`'s KEEP-guard, which has the full multi-signal context. Brittle-detector-with-block-authority is explicitly avoided: the brittle part (an age timer) was ALREADY there; this change strictly *reduces* how often that brittle part speaks, and routes nothing past the smart authority.
43
+
44
+ ## 5. Interactions
45
+
46
+ - **Shadowing:** The `!shouldRequest` branch falls through to the existing idle-detection block exactly as the prior code path did on a kept session — it does not shadow idle detection or any other monitor check. Verified in the diff: the new `else if` sits between the active-work branch and the kill branch and `continue`s to the same place.
47
+ - **Double-fire:** No. Two paths exist (`terminated` → `recordKilled`; `!terminated` → `recordVeto`) and they are mutually exclusive on a single `terminateSession` result. No other component writes the ledger.
48
+ - **Races:** The ledger is a plain in-process `Map` touched only from the single-threaded `monitorTick` loop (`shouldRequest`/`recordVeto`/`recordKilled`) — no cross-thread/async sharing, and no write from the injection path. Bounded by `maxTracked` (1024) with oldest-eviction, so it cannot grow unbounded even across thousands of session ids; a stale entry for a removed session id self-evicts and is harmless (that id never returns).
49
+ - **Feedback loops:** None. Suppressing a request cannot change whether the guard would keep the session; it only changes cadence.
50
+
51
+ ## 6. External surfaces
52
+
53
+ - **Other agents / users:** None directly. The behavior ships to every agent on update, but the only observable change is *fewer* log lines and *less* wasted CPU — strictly a reduction in noise. No API, message, or schema surface changes.
54
+ - **External systems:** None (no Telegram/Slack/GitHub/Cloudflare interaction).
55
+ - **Persistent state:** None. The ledger is in-memory only; nothing is written to disk, no migration, no new column.
56
+ - **Logs (the intended visible change):** the per-tick "Requesting kill" flood for kept sessions collapses to ONE "over age but KEPT (reason); backing off re-checks" line per back-off window. Operators / log scrapers keying on the old high-volume line will see far fewer of them — a benign reduction.
57
+ - **Timing:** Introduces a bounded ≤`backoffMs` delay before re-checking a kept-then-lapsed session (analyzed in §1).
58
+
59
+ ## 7. Rollback cost
60
+
61
+ Pure in-process code change. Back-out = revert the commit and ship a patch, OR set `ageKillBackoffMinutes: 0` in config (instant per-agent disable, restoring exact legacy every-tick behavior with no restart-coupled migration). No persistent state to clean up, no agent-state repair, no user-visible regression during the rollback window (the only difference users could notice is the log flood returning).
62
+
63
+ ## Conclusion
64
+
65
+ This review produced no design changes — the implementation already matched the converged spec's signal-not-authority shape. The review confirmed: (a) the KEEP-guard remains the sole kill authority (no over-block of live work; at most a bounded ≤10min delay in cleaning up a session whose keep-reason just lapsed), (b) no persistent state / external surface / race, and (c) a trivial dual rollback (revert or `ageKillBackoffMinutes:0`). Migration parity is met by the in-code default, consistent with the sibling `defaultMaxDurationMinutes` dial (neither is in `migrateConfig`). Because this touches session lifecycle (kill path), a Phase-5 second-pass reviewer audit is required before commit; this artifact awaits that concurrence.
66
+
67
+ ---
68
+
69
+ ## Phase 5 — Second-pass review (session-lifecycle change → required)
70
+
71
+ An independent reviewer subagent audited the diff, spec, artifact, and both test files at line level, specifically probing whether the back-off could ever prevent a genuinely-abandoned session from being killed, ledger memory safety, veto/kill mutual-exclusion, the `!shouldRequest` fall-through, and migration safety.
72
+
73
+ **Verdict: Concur with the review.** The core safety invariants hold under line-level inspection: `recordVeto` is only reachable when `terminateSession` returns `terminated:false`, so a no-keep-reason session is never backed off and dies on its first ask; the `!shouldRequest` branch falls through to the fully independent idle-detection / idle-zombie kill path, so a genuinely-abandoned backed-off session is still reaped; `recordVeto`/`recordKilled` are mutually exclusive on one result (no ledger corruption); the `Map` is bounded by `maxTracked` oldest-eviction; and the in-code default safely mirrors the sibling `defaultMaxDurationMinutes` with no migration needed. The change alters only the FREQUENCY of asking, never WHICH sessions die.
74
+
75
+ **One non-blocking accuracy defect raised — and fixed:** the reviewer noted that the spec (Design step 3) and this artifact (§1/§5) originally claimed `reset()` was wired into the injection path and `clear()` on session removal, but neither is actually called in production (they are API exercised only by the unit suite). Practical impact was nil (a re-engaged session is already protected by the age-gate's active-work branch; memory is bounded by eviction), but the docs were inaccurate. Resolution: the spec and this artifact were corrected to state accurately that `reset()`/`clear()` are unwired maintenance API and that a re-engaged session is protected by the active-work branch — the implementation was left as-is (wiring `reset()` across the tmux→session.id key boundary would add risk for zero behavioral benefit, per the reviewer's own analysis). Spec and code now agree.
@@ -0,0 +1,69 @@
1
+ # Side-Effects Review — Hermetic local unit suite
2
+
3
+ **Version / slug:** `hermetic-unit-suite`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `instar-codey`
6
+ **Second-pass reviewer:** `not required — Tier-1 patch; watchdog template path reviewed here`
7
+
8
+ ## Summary of the change
9
+
10
+ This change makes local unit-suite evidence hermetic on a live-agent Node 25 developer box. It touches `src/templates/scripts/instar-watchdog.sh`, `tests/unit/Config.test.ts`, and `tests/unit/coherence-gate-escalation.test.ts`. The source change fixes the existing watchdog no-auth health probe so it calls curl without auth arguments when no auth token exists. The test changes pin framework-specific config fixtures and make package export checks static so full-suite load does not turn a valid export check into a timeout.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `probe_server_identity` in `src/templates/scripts/instar-watchdog.sh` — modify — preserves the existing server identity decision, but corrects the no-auth request path so auth headers are only supplied when an auth token exists.
15
+ - `Config.test.ts` fixture framework selection — modify — test-only fixture isolation; no production decision point.
16
+ - `coherence-gate-escalation.test.ts` export verification — modify — test-only import strategy; no production decision point.
17
+
18
+ ## 1. Over-block
19
+
20
+ No new block/allow surface is added. The watchdog already decided whether server identity was same-project, wrong-project, unreachable, or indeterminate; this patch only makes the unauthenticated curl invocation match the "no token" branch. There is no new legitimate input rejected by this change.
21
+
22
+ ## 2. Under-block
23
+
24
+ This does not attempt to make every unit test hermetic in perpetuity. It fixes the local-red failures observed in this run: real-config/framework leakage, live tunnel leakage already addressed on current main, Node 25 native-module setup, the watchdog no-auth script bug, and the export-test timeout. Future tests can still leak live machine state if they read real config or network state without fixtures; that remains a suite hygiene class, not a new runtime gap introduced here.
25
+
26
+ ## 3. Level-of-abstraction fit
27
+
28
+ The watchdog fix is at the right layer: the bug is in the shell template's curl argument construction, so the correction belongs in the shipped template rather than in the unit test. The config and export changes are correctly test-local: they do not ask production code to grow a seam just to satisfy this suite. Current main already provides the tunnel-provider and worktree cwd seams that absorbed the earlier tunnel/worktree local-reds, so this patch does not duplicate those abstractions.
29
+
30
+ ## 4. Signal vs authority compliance
31
+
32
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
33
+
34
+ - [x] No — this change has no new block/allow surface.
35
+
36
+ The watchdog path has existing operational authority to classify the server it probes, but this patch does not add a brittle new authority. It removes an accidental argument-shape dependency in the existing probe. The other two files are tests and have no runtime authority.
37
+
38
+ ## 5. Interactions
39
+
40
+ - **Shadowing:** The watchdog no-auth branch now bypasses `auth_args` entirely when no token exists. It does not shadow the authenticated path; the authenticated path is unchanged.
41
+ - **Double-fire:** No new timers, retries, or events are introduced.
42
+ - **Races:** No persistent state or concurrent path changes are introduced. The generated `src/data/builtin-manifest.json` was primed locally by the manifest test and remains ignored.
43
+ - **Feedback loops:** No release/update/job feedback loop changes.
44
+
45
+ ## 6. External surfaces
46
+
47
+ Existing installed agents receive the corrected watchdog template when the template is shipped and applied. The visible behavior is narrower and intended: a no-auth probe should be genuinely no-auth. There is no database migration, ledger write, config-field change, public API change, or Telegram/Slack surface change. The local Node 25 dependency repair required `npm install --include=dev` on the dev box, but it did not modify `package.json` or `package-lock.json`.
48
+
49
+ ## 7. Rollback cost
50
+
51
+ Rollback is a normal hot-fix revert. The source change is a shell-template branch, and the test changes are fixture/import isolation only. No persistent state is written, and no existing agent state needs repair. If the watchdog change were wrong, reverting it restores the prior curl invocation shape.
52
+
53
+ ## Conclusion
54
+
55
+ The change is clear to ship as Tier 1. It fixes one real watchdog script bug and isolates two unit-suite failures without skipping tests, suppressing failures, or weakening assertions. The full unit-only run on the live-agent Node 25 box had one failure: a generated built-in manifest was stale because source was dirty; the manifest test regenerated that ignored file and its immediate rerun passed. Focused post-rebase validation passed on the edited/failure-class files.
56
+
57
+ ## Second-pass review (if required)
58
+
59
+ **Reviewer:** not required for this Tier-1 patch.
60
+ **Independent read of the artifact:** not run.
61
+
62
+ The watchdog surface is documented above because it is the only runtime path touched. No new watchdog decision or recovery authority was added.
63
+
64
+ ## Evidence pointers
65
+
66
+ - Full unit-only local run: 1,241/1,242 files passed; 23,548/23,549 tests passed. The only failure was `tests/unit/builtin-manifest.test.ts` because the generated ignored manifest was stale after source changes.
67
+ - Targeted manifest rerun after local generation: `tests/unit/builtin-manifest.test.ts` passed, 9/9.
68
+ - Focused post-rebase run: `AgentWorktreeDetector`, `Config`, `TunnelManager`, `watchdog-bind-probe`, `index-exports`, `coherence-gate-escalation`, and `builtin-manifest` passed, 124/124.
69
+ - Claim-check: path advisory found merged PR #842 on the watchdog template and many keyword specs, with no open sibling claim requiring a different layer.
@@ -0,0 +1,64 @@
1
+ # Side-Effects Review - post-drive transcript auditor
2
+
3
+ **Version / slug:** `post-drive-transcript-audit`
4
+ **Date:** `2026-06-05`
5
+ **Author:** `instar-codey`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ This change adds a standalone post-drive transcript auditor and CLI command. It reads existing topic message history for specified topics and a time window, classifies operator-seat UX antipatterns, prints a structured report, and writes each finding to the existing framework issue ledger. It also fixes the ledger so a `relatedSpec` citation passed to the write path is persisted on new issues or backfilled on later matching observations.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `classifyTranscriptUx` - add - deterministic signal classifier for transcript messages.
15
+ - `runPostDriveTranscriptAudit` - add - decides whether to file each classified finding, with dry-run support.
16
+ - Framework issue ledger `recordObservation` - modify - preserves related-spec citation metadata; no new authority or route.
17
+
18
+ ## 1. Over-block
19
+
20
+ No block/allow surface - over-block is not applicable. The auditor can produce false-positive findings, but those are ledger signals for review, not user-message blocks.
21
+
22
+ The main false-positive risk is classifying a legitimate short status message as content-free. The live fixture dry-run exposed this for normal acknowledgements, so the heuristic was narrowed to repeated/status chatter such as "actively working", "still working", or "no terminal output", and repeated identical notices are grouped.
23
+
24
+ ## 2. Under-block
25
+
26
+ The auditor still misses UX issues that require deeper conversational interpretation. For example, it will not detect a polite but confusing request unless it contains resend/retry/re-paste language, and it will not detect subtle infrastructure leakage unless it uses the configured infrastructure terms. That is acceptable for this slice because the output is a structured starting signal, not a mentor judgment loop.
27
+
28
+ The message-history route currently returns a bounded recent history. A large topic with more than the cap between the drive window and audit time could under-report old messages. The command makes the limit explicit and clamps it to the existing server cap; a future slice can add a broader archival reader if needed.
29
+
30
+ ## 3. Level-of-abstraction fit
31
+
32
+ This is intentionally a low-level detector. It belongs after a drive, not in the live send path, because it is looking for transcript evidence to file. It does not duplicate the tone gate or messaging authority; it feeds the framework issue ledger with evidence pointers so later human or process review has a durable artifact.
33
+
34
+ The ledger citation fix is at the right layer because the route already accepted `relatedSpec`; losing it inside the storage layer meant callers could do the right thing and still end up with a blind record.
35
+
36
+ ## 4. Signal vs authority compliance
37
+
38
+ - [x] No - this change produces a signal consumed by an existing ledger.
39
+ - [ ] No - this change has no block/allow surface.
40
+ - [ ] Yes - but the logic is a smart gate with full conversational context.
41
+ - [ ] Yes, with brittle logic - STOP.
42
+
43
+ The classifier is deliberately brittle and therefore holds no authority. It cannot block, retry, resend, escalate, or alter a transcript. Its only side effect is filing reviewable observations with stable dedupe keys.
44
+
45
+ ## 5. Interactions
46
+
47
+ - **Shadowing:** no live messaging check is shadowed. The command runs manually after the drive and reads existing history.
48
+ - **Double-fire:** repeated runs file the same canonical issue because the dedupe key includes topic, window, category, and message evidence. The live fixture was run twice; the second write deduped.
49
+ - **Races:** the only shared state is the framework issue ledger. The ledger already owns SQLite write serialization and episode dedupe.
50
+ - **Feedback loops:** there is no mentor judgment loop. Findings do not automatically alter future classifications or message behavior.
51
+
52
+ ## 6. External surfaces
53
+
54
+ The command reads local server topic history and writes to the local framework issue ledger. That creates persistent state: open framework issue rows and observations. The live fixture run filed three observations for topics 2278 and 2271 in the 11:15-11:21 PDT window. Because the running server still had the pre-fix ledger code loaded, those three rows were updated directly with the related-spec citation after the code fix; future runs through this PR path persist it normally.
55
+
56
+ No Telegram messages are sent by the command. No GitHub, Cloudflare, or third-party systems are called. The CLI output can include short excerpts, so operators should treat reports as local/private unless deliberately published.
57
+
58
+ ## 7. Rollback cost
59
+
60
+ Code rollback is a normal revert. The command is additive, and removing it does not affect live messaging. The ledger citation change is backward-compatible: it only fills an existing nullable column. If a filed observation is wrong, the durable record can be closed, marked fixed, or superseded through the existing ledger workflow; no schema rollback is needed.
61
+
62
+ ## Conclusion
63
+
64
+ This slice is clear to ship as Tier 1. It adds a narrow, post-drive observation tool; keeps classification signal-only; files findings through the existing ledger; and fixes the storage bug that would otherwise erase the parent-principle citation required by the UX-blindspot work.