instar 1.3.70 → 1.3.72
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/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +20 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/messaging/AttentionTopicGuard.d.ts +88 -0
- package/dist/messaging/AttentionTopicGuard.d.ts.map +1 -0
- package/dist/messaging/AttentionTopicGuard.js +154 -0
- package/dist/messaging/AttentionTopicGuard.js.map +1 -0
- package/dist/messaging/TelegramAdapter.d.ts +39 -0
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +142 -1
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/monitoring/SessionReplyExtractor.d.ts +18 -0
- package/dist/monitoring/SessionReplyExtractor.d.ts.map +1 -1
- package/dist/monitoring/SessionReplyExtractor.js +48 -0
- package/dist/monitoring/SessionReplyExtractor.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +60 -22
- package/dist/server/AgentServer.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +19 -19
- package/upgrades/1.3.71.md +58 -0
- package/upgrades/1.3.72.md +65 -0
- package/upgrades/side-effects/attention-topic-flood-guard.md +74 -0
- package/upgrades/side-effects/stage-a-transcript-capture.md +76 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-05-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-05-29T01:04:44.834Z",
|
|
5
|
+
"instarVersion": "1.3.72",
|
|
6
6
|
"entryCount": 193,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"domain": "identity",
|
|
12
12
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
13
13
|
"installedPath": ".instar/hooks/instar/session-start.sh",
|
|
14
|
-
"contentHash": "
|
|
14
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
15
15
|
"since": "2025-01-01"
|
|
16
16
|
},
|
|
17
17
|
"hook:dangerous-command-guard": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"domain": "safety",
|
|
21
21
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
22
22
|
"installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
|
|
23
|
-
"contentHash": "
|
|
23
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
24
24
|
"since": "2025-01-01"
|
|
25
25
|
},
|
|
26
26
|
"hook:grounding-before-messaging": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"domain": "safety",
|
|
30
30
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
31
31
|
"installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
|
|
32
|
-
"contentHash": "
|
|
32
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
33
33
|
"since": "2025-01-01"
|
|
34
34
|
},
|
|
35
35
|
"hook:compaction-recovery": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"domain": "identity",
|
|
39
39
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
40
40
|
"installedPath": ".instar/hooks/instar/compaction-recovery.sh",
|
|
41
|
-
"contentHash": "
|
|
41
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
42
42
|
"since": "2025-01-01"
|
|
43
43
|
},
|
|
44
44
|
"hook:external-operation-gate": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"domain": "safety",
|
|
48
48
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
49
49
|
"installedPath": ".instar/hooks/instar/external-operation-gate.js",
|
|
50
|
-
"contentHash": "
|
|
50
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
51
51
|
"since": "2025-01-01"
|
|
52
52
|
},
|
|
53
53
|
"hook:deferral-detector": {
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"domain": "safety",
|
|
57
57
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
58
58
|
"installedPath": ".instar/hooks/instar/deferral-detector.js",
|
|
59
|
-
"contentHash": "
|
|
59
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
60
60
|
"since": "2025-01-01"
|
|
61
61
|
},
|
|
62
62
|
"hook:post-action-reflection": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"domain": "evolution",
|
|
66
66
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
67
67
|
"installedPath": ".instar/hooks/instar/post-action-reflection.js",
|
|
68
|
-
"contentHash": "
|
|
68
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
69
69
|
"since": "2025-01-01"
|
|
70
70
|
},
|
|
71
71
|
"hook:external-communication-guard": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"domain": "safety",
|
|
75
75
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
76
76
|
"installedPath": ".instar/hooks/instar/external-communication-guard.js",
|
|
77
|
-
"contentHash": "
|
|
77
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
78
78
|
"since": "2025-01-01"
|
|
79
79
|
},
|
|
80
80
|
"hook:scope-coherence-collector": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"domain": "coherence",
|
|
84
84
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
85
85
|
"installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
|
|
86
|
-
"contentHash": "
|
|
86
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
87
87
|
"since": "2025-01-01"
|
|
88
88
|
},
|
|
89
89
|
"hook:scope-coherence-checkpoint": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"domain": "coherence",
|
|
93
93
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
94
94
|
"installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
|
|
95
|
-
"contentHash": "
|
|
95
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
96
96
|
"since": "2025-01-01"
|
|
97
97
|
},
|
|
98
98
|
"hook:free-text-guard": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"domain": "safety",
|
|
102
102
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
103
103
|
"installedPath": ".instar/hooks/instar/free-text-guard.sh",
|
|
104
|
-
"contentHash": "
|
|
104
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
105
105
|
"since": "2025-01-01"
|
|
106
106
|
},
|
|
107
107
|
"hook:claim-intercept": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"domain": "coherence",
|
|
111
111
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
112
112
|
"installedPath": ".instar/hooks/instar/claim-intercept.js",
|
|
113
|
-
"contentHash": "
|
|
113
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
114
114
|
"since": "2025-01-01"
|
|
115
115
|
},
|
|
116
116
|
"hook:claim-intercept-response": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"domain": "coherence",
|
|
120
120
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
121
121
|
"installedPath": ".instar/hooks/instar/claim-intercept-response.js",
|
|
122
|
-
"contentHash": "
|
|
122
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
123
123
|
"since": "2025-01-01"
|
|
124
124
|
},
|
|
125
125
|
"hook:stop-gate-router": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"domain": "safety",
|
|
129
129
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
130
130
|
"installedPath": ".instar/hooks/instar/stop-gate-router.js",
|
|
131
|
-
"contentHash": "
|
|
131
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
132
132
|
"since": "2025-01-01"
|
|
133
133
|
},
|
|
134
134
|
"hook:auto-approve-permissions": {
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"domain": "safety",
|
|
138
138
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
139
139
|
"installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
|
|
140
|
-
"contentHash": "
|
|
140
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
141
141
|
"since": "2025-01-01"
|
|
142
142
|
},
|
|
143
143
|
"job:health-check": {
|
|
@@ -1457,7 +1457,7 @@
|
|
|
1457
1457
|
"type": "subsystem",
|
|
1458
1458
|
"domain": "server",
|
|
1459
1459
|
"sourcePath": "src/server/AgentServer.ts",
|
|
1460
|
-
"contentHash": "
|
|
1460
|
+
"contentHash": "88cfc6c3397a04f59444a78fe95cd23a3d1805a64476f175123fbb59373c1a07",
|
|
1461
1461
|
"since": "2025-01-01"
|
|
1462
1462
|
},
|
|
1463
1463
|
"subsystem:session-manager": {
|
|
@@ -1489,7 +1489,7 @@
|
|
|
1489
1489
|
"type": "subsystem",
|
|
1490
1490
|
"domain": "updates",
|
|
1491
1491
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1492
|
-
"contentHash": "
|
|
1492
|
+
"contentHash": "cf0c9bfcfa78083bb0a5f6cd2e0f1f175b16204178f373c95cca674e33eae52a",
|
|
1493
1493
|
"since": "2025-01-01"
|
|
1494
1494
|
},
|
|
1495
1495
|
"subsystem:scheduler": {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Instar Upgrade Guide — NEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**Mentor cycle: Stage-A prompt capture no longer silently returns empty.**
|
|
8
|
+
|
|
9
|
+
The mentor tick's Stage-A step spawns a short haiku session to *generate* the
|
|
10
|
+
mentor prompt, then reads that session's output before delivering it to the
|
|
11
|
+
mentee. Two bugs made that capture silently return empty — so a tick "ran" but
|
|
12
|
+
delivered nothing (`delivered:false`, `stageAMsgLen:0`):
|
|
13
|
+
|
|
14
|
+
1. **Transcript lookup got lost in a huge directory tree.** The Claude path of
|
|
15
|
+
`extractMenteeReplyFromTranscript` located the session transcript with a
|
|
16
|
+
*recursive* walk of `~/.claude/projects` bounded by a 10,000-step guard. On
|
|
17
|
+
a busy agent that folder holds far more than 10k nested directories, so the
|
|
18
|
+
depth-first walk burned its whole budget inside an unrelated subtree and gave
|
|
19
|
+
up *before reaching the right file* — even though the file sits exactly one
|
|
20
|
+
level down. Replaced with `findClaudeTranscriptShallow`, which scans only the
|
|
21
|
+
immediate children (the layout Claude actually uses:
|
|
22
|
+
`<projects>/<encoded-cwd>/<sessionId>.jsonl`). Finds it in milliseconds.
|
|
23
|
+
|
|
24
|
+
2. **Capture raced the session lifecycle.** `spawnStageA` read the tmux pane
|
|
25
|
+
*after* the session completed (the reaper had already torn it down → empty),
|
|
26
|
+
and `claudeSessionId` is only flushed to the session record at completion —
|
|
27
|
+
a beat after the session leaves the running list. Now Stage-A (a) keeps the
|
|
28
|
+
last non-empty pane snapshot *while the session is alive* as a fallback, and
|
|
29
|
+
(b) prefers the persisted transcript, polling for `claudeSessionId` to land
|
|
30
|
+
and the final assistant block to be written (up to the session's own 5-min
|
|
31
|
+
max). It uses the *exact* `<claudeSessionId>.jsonl` — never newest-by-mtime,
|
|
32
|
+
since the agent runs many concurrent Claude sessions and mtime would grab an
|
|
33
|
+
unrelated transcript.
|
|
34
|
+
|
|
35
|
+
## What to Tell Your User
|
|
36
|
+
|
|
37
|
+
The scheduled mentor tick now reliably generates and delivers its prompt — the
|
|
38
|
+
last gap that made the tick "fire but deliver nothing" is closed. No config
|
|
39
|
+
changes; behavior is automatic.
|
|
40
|
+
|
|
41
|
+
## Summary of New Capabilities
|
|
42
|
+
|
|
43
|
+
| Capability | How to Use |
|
|
44
|
+
|-----------|-----------|
|
|
45
|
+
| Robust Stage-A prompt capture | Automatic — the generated mentor prompt is read from the session transcript (exact `<claudeSessionId>.jsonl`, depth-1 scan) with a capture-while-alive pane fallback. |
|
|
46
|
+
| `findClaudeTranscriptShallow` | Pure, exported helper in `SessionReplyExtractor` — locates a Claude transcript by session id at its real depth-1 layout (no recursive walk). Unit-tested incl. a regression for the deep-subtree case. |
|
|
47
|
+
|
|
48
|
+
## Evidence
|
|
49
|
+
|
|
50
|
+
- Unit: `tests/unit/SessionReplyExtractor.test.ts` — 5 new cases for
|
|
51
|
+
`findClaudeTranscriptShallow`, including a regression that builds a 50-deep
|
|
52
|
+
unrelated subtree + 30 sibling encoded-cwd dirs and proves the depth-1 file is
|
|
53
|
+
still found (the exact shape the old recursive walk failed on).
|
|
54
|
+
- Integration: `tests/integration/mentor-routes.test.ts` (the `/mentor/tick`
|
|
55
|
+
route) green; full mentor/mentee suite (63 tests) green.
|
|
56
|
+
- Live: tick-driven round-trip verified — `/mentor/tick` → Stage-A generates
|
|
57
|
+
the prompt → delivered to the mentee → a clean-prose reply persisted to
|
|
58
|
+
`mentor-replies.jsonl` (evidence captured in the PR).
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**Topic-spam, locked down structurally.** A second Telegram topic-flood (after
|
|
8
|
+
the 2026-05-22 sentinel flood) hit a live agent: a housekeeping feature raised one
|
|
9
|
+
attention item per failed peer-resolution every sweep, and because
|
|
10
|
+
`createAttentionItem` spawns a brand-new forum topic per item, that became a wall
|
|
11
|
+
of topics. PR #495 already fixed *that feature* (a per-peer escalation cooldown).
|
|
12
|
+
This change adds the **structural backstop** so the *class* of bug can't recur no
|
|
13
|
+
matter which feature misbehaves next.
|
|
14
|
+
|
|
15
|
+
**`AttentionTopicGuard` — a per-source + global circuit breaker** at the one
|
|
16
|
+
chokepoint, `TelegramAdapter.createAttentionItem`. If a single attention
|
|
17
|
+
`sourceContext` exceeds its topic budget within a rolling window (default 3 / 10
|
|
18
|
+
min) — or, via a **global ceiling**, all sources collectively exceed it — further
|
|
19
|
+
**non-critical** items are COALESCED into ONE reused "notices coalesced" topic and
|
|
20
|
+
recorded in `state/attention-suppressed.jsonl` — never a wall. Invariants:
|
|
21
|
+
HIGH/URGENT/CRITICAL items are **never** coalesced (critical messages always get
|
|
22
|
+
their own topic), and **no item is dropped** — only its per-item topic is withheld;
|
|
23
|
+
the item is still in the attention store. The global ceiling makes the protection
|
|
24
|
+
hold even when a feature varies its `sourceContext` per item to dodge a per-source
|
|
25
|
+
budget. Ships **enabled by default in code**, so every fleet agent is protected on
|
|
26
|
+
the dist update with zero config.
|
|
27
|
+
|
|
28
|
+
## What to Tell Your User
|
|
29
|
+
|
|
30
|
+
- The "wall of topics popping up out of nowhere" problem is now fixed at its root.
|
|
31
|
+
If any background feature ever tries to flood the chat again, it's capped
|
|
32
|
+
automatically: a few topics at most, then everything folds into one quiet
|
|
33
|
+
"notices coalesced" topic, with the detail kept in the logs. Genuinely critical
|
|
34
|
+
alerts (HIGH/URGENT) are never affected — they always come through on their own.
|
|
35
|
+
- No action or config needed; it's on by default.
|
|
36
|
+
|
|
37
|
+
## Summary of New Capabilities
|
|
38
|
+
|
|
39
|
+
| Capability | How to Use |
|
|
40
|
+
|-----------|-----------|
|
|
41
|
+
| Attention topic-flood circuit breaker | Automatic, on by default. Tune via `messaging[].config.attentionTopicGuard` = `{ "enabled": true, "windowMs": 600000, "maxTopicsPerSource": 3, "maxTopicsGlobal": 8 }`. |
|
|
42
|
+
| Suppressed-notice audit trail | When a source is coalesced, each item is logged to `state/attention-suppressed.jsonl` (size-capped). Read it to answer "why are my notices grouped / where did topic X go?" |
|
|
43
|
+
|
|
44
|
+
## Migration Notes
|
|
45
|
+
|
|
46
|
+
Pure `src/` logic, **default-ON in code** (`AttentionTopicGuard` +
|
|
47
|
+
`TelegramAdapter`) — no agent-installed file changed, so every agent receives the
|
|
48
|
+
protection through the normal dist update with nothing to patch. A
|
|
49
|
+
`migrateClaudeMd()` entry backfills the **Topic-Flood Guard** awareness section
|
|
50
|
+
into existing agents' CLAUDE.md (idempotent). The redrive-specific offender fix
|
|
51
|
+
shipped separately in PR #495.
|
|
52
|
+
|
|
53
|
+
## Evidence
|
|
54
|
+
|
|
55
|
+
- Unit: `tests/unit/AttentionTopicGuard.test.ts` (11) — budget / global-cap /
|
|
56
|
+
critical-bypass (case-insensitive) / per-source isolation / sustained-flood
|
|
57
|
+
single episode / post-silence reset / config-validation / key-eviction;
|
|
58
|
+
`tests/unit/PostUpdateMigrator-topicFloodGuard.test.ts` (2) — migrator backfill
|
|
59
|
+
+ idempotency.
|
|
60
|
+
- Integration: `tests/integration/attention-topic-flood-guard.test.ts` (4) — REAL
|
|
61
|
+
`TelegramAdapter`: a flooding source is capped at budget+1 topics, HIGH
|
|
62
|
+
bypasses, concurrent coalesced items create ONE topic, a different source is
|
|
63
|
+
unaffected, no item dropped, audit log populated.
|
|
64
|
+
- E2E: `tests/e2e/attention-topic-flood-guard-lifecycle.test.ts` (1) — fleet
|
|
65
|
+
default (NO config) still caps a flood exactly (migration-parity guarantee).
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Side-Effects Review — Attention Topic-Flood Guard
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/attention-topic-flood-guard.md` (converged, 4-reviewer panel)
|
|
4
|
+
**Change:** per-source + global forum-topic circuit breaker at
|
|
5
|
+
`TelegramAdapter.createAttentionItem` (the structural backstop). The redrive
|
|
6
|
+
offender fix shipped separately in PR #495 (merged); the redrive edits originally
|
|
7
|
+
bundled here were dropped to defer to it.
|
|
8
|
+
**Files:** `src/messaging/AttentionTopicGuard.ts` (new),
|
|
9
|
+
`src/messaging/TelegramAdapter.ts`, `src/core/PostUpdateMigrator.ts`, tests,
|
|
10
|
+
`tests/unit/feature-delivery-completeness.test.ts`, `upgrades/NEXT.md`.
|
|
11
|
+
|
|
12
|
+
## Phase 4 — the seven questions
|
|
13
|
+
|
|
14
|
+
1. **Over-block.** The guard never blocks an agent action or drops an item — it
|
|
15
|
+
only changes *delivery form* (own topic vs. one coalesced topic + a log line)
|
|
16
|
+
for **non-critical** items. The one legitimate behavior it changes: a
|
|
17
|
+
non-critical source raising >3 items / 10 min has the surplus coalesced. That
|
|
18
|
+
is the *intended* behavior (the operator asked for exactly this) and is tunable
|
|
19
|
+
per adapter. HIGH/URGENT are never affected. No agent capability is rejected.
|
|
20
|
+
|
|
21
|
+
2. **Under-block.** Before the global ceiling was added, a source varying its
|
|
22
|
+
`sourceContext` per item would have dodged the per-source budget — the review
|
|
23
|
+
caught this; the global cap + key eviction now bound it regardless of source
|
|
24
|
+
cardinality. Remaining under-block: a flood composed entirely of HIGH/URGENT
|
|
25
|
+
items is not coalesced (by design — critical items must always be visible). A
|
|
26
|
+
feature mis-marking routine noise as HIGH would still flood; that is a
|
|
27
|
+
mis-classification bug in that feature, not in the guard, and is the correct
|
|
28
|
+
place to fix it.
|
|
29
|
+
|
|
30
|
+
3. **Level-of-abstraction fit.** Correct layer: the breaker sits at the single
|
|
31
|
+
chokepoint (`createAttentionItem`) where every attention item becomes a topic,
|
|
32
|
+
so it covers all current and future callers. It is deliberately *below* the
|
|
33
|
+
tone-gate authority on the `/attention` route (a transport-mechanics
|
|
34
|
+
rate-counter, not a content-judgment filter). The per-feature redrive fix
|
|
35
|
+
(PR #495) is at the feature layer; the guard is the substrate backstop — two
|
|
36
|
+
layers, by intent.
|
|
37
|
+
|
|
38
|
+
4. **Signal vs authority.** Compliant. The guard holds no blocking authority over
|
|
39
|
+
agent behavior or information flow; it is a delivery *shaper* (the rate-counter
|
|
40
|
+
/ transport-dedup carve-out in `docs/signal-vs-authority.md`), the same class as
|
|
41
|
+
`SentinelNotifier`. It never withholds a critical notice and never drops an
|
|
42
|
+
item.
|
|
43
|
+
|
|
44
|
+
5. **Interactions.** Audited against `SentinelNotifier` (separate path → the
|
|
45
|
+
single reused system topic; no collision — it never flows through the guard) and
|
|
46
|
+
the `agent-attention-topic` (not registered in the attention maps, untouched).
|
|
47
|
+
Restart interaction (coalesced items vs. `loadAttentionItems` reverse-map
|
|
48
|
+
corruption) and concurrency (double-create race) were both found by review and
|
|
49
|
+
fixed. `updateAttentionStatus` no longer closes a shared topic when one
|
|
50
|
+
coalesced sibling resolves (coalesced items aren't in the per-item maps).
|
|
51
|
+
|
|
52
|
+
6. **External surfaces.** User-visible change: a flooding source now produces one
|
|
53
|
+
"🔁 …: notices coalesced (flood guard)" topic instead of a wall; the rest goes
|
|
54
|
+
to `state/attention-suppressed.jsonl`. Fleet-wide via dist update, default-ON,
|
|
55
|
+
no config. No new network calls; no new external dependency. The CLAUDE.md
|
|
56
|
+
awareness section is backfilled to existing agents (idempotent migrator).
|
|
57
|
+
|
|
58
|
+
7. **Rollback cost.** Cheap. Single config flag:
|
|
59
|
+
`messaging[].config.attentionTopicGuard.enabled = false` restores per-item-topic
|
|
60
|
+
behavior. No data migration, no agent-state repair (the guard holds only
|
|
61
|
+
in-memory counters). Worst case is a `src/` revert + patch release.
|
|
62
|
+
|
|
63
|
+
## Phase 5 — second-pass review (REQUIRED: touches a "guard" + outbound messaging)
|
|
64
|
+
|
|
65
|
+
An independent four-reviewer convergence panel (adversarial/security, integration,
|
|
66
|
+
architecture, scalability) audited the change against the diff. It raised 7
|
|
67
|
+
material concerns (global-cap dodge, `/ack`+shared-topic-close, case-sensitive
|
|
68
|
+
critical bypass, double-create race, hex plaintext to unverified address, NaN
|
|
69
|
+
config disable, unbounded audit log) plus framing notes. **6 of the 7 were fixed
|
|
70
|
+
in code this iteration; the 7th (hex plaintext) was a finding on the redrive edits
|
|
71
|
+
that are now deferred to the merged PR #495.** Full record:
|
|
72
|
+
`docs/specs/attention-topic-flood-guard.convergence.md`. **Concur with the review —
|
|
73
|
+
the design after this iteration addresses every raised concern; no blocking
|
|
74
|
+
authority on brittle logic remains.**
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Side-effects review — Stage-A transcript capture (mentor cycle)
|
|
2
|
+
|
|
3
|
+
**Scope**: Close the last known mentor-cycle gap. The tick-driven path "ran but
|
|
4
|
+
delivered nothing" because the Stage-A prompt-generation session's output was
|
|
5
|
+
captured by (1) a recursive `~/.claude/projects` walk that exhausted its 10k
|
|
6
|
+
guard before reaching the file, and (2) a post-reap tmux read that raced the
|
|
7
|
+
session lifecycle. Make Stage-A capture deterministic and clean-prose.
|
|
8
|
+
|
|
9
|
+
**Files touched**:
|
|
10
|
+
- `src/monitoring/SessionReplyExtractor.ts` — new pure exported
|
|
11
|
+
`findClaudeTranscriptShallow(projectsDir, claudeSessionId)`: scans the
|
|
12
|
+
immediate children of `projects/` (+ root, defensively) for the exact
|
|
13
|
+
`<id>.jsonl`. Replaces the inline recursive walk. Adds `fs`/`path` imports.
|
|
14
|
+
- `src/server/AgentServer.ts` —
|
|
15
|
+
- `extractMenteeReplyFromTranscript` is now `async`; its Claude path polls
|
|
16
|
+
up to ~240s for `claudeSessionId` (re-fetched from `state.getSession`) and
|
|
17
|
+
the final assistant block, using `findClaudeTranscriptShallow`. Codex path
|
|
18
|
+
unchanged (rollout-by-mtime, returns before the poll).
|
|
19
|
+
Caller (mentee role-handler) now `await`s it.
|
|
20
|
+
- `spawnStageA` keeps the last non-empty pane snapshot while the session is
|
|
21
|
+
alive (fallback), then prefers the transcript via the same helper; falls
|
|
22
|
+
back to the snapshot/pane only if no transcript is found. Adds two
|
|
23
|
+
`[stage-a-diag]` log lines (low frequency — once per tick).
|
|
24
|
+
- `tests/unit/SessionReplyExtractor.test.ts` — 5 new cases for
|
|
25
|
+
`findClaudeTranscriptShallow` (depth-1 hit, root hit, deep-subtree
|
|
26
|
+
regression, no-descent guarantee, null-safety).
|
|
27
|
+
- `upgrades/NEXT.md` — release note (patch bump).
|
|
28
|
+
|
|
29
|
+
**Under-block (false negatives — does it ever now FAIL to capture a real reply?)**:
|
|
30
|
+
- The Claude path requires the exact `<claudeSessionId>.jsonl`. If a session
|
|
31
|
+
never flushes `claudeSessionId` (e.g. killed before completion), the poll
|
|
32
|
+
returns null after ~240s — but `spawnStageA` then falls back to the
|
|
33
|
+
capture-while-alive pane snapshot, so a completed session still yields its
|
|
34
|
+
text. Net: strictly more robust than before (which had only the post-reap
|
|
35
|
+
read). The mentee role-handler retains its own tmux-capture fallback too.
|
|
36
|
+
- The 240s poll only runs on the Claude branch. A codex mentee (Codey) returns
|
|
37
|
+
from the codex branch immediately — no added latency to the proven reply leg.
|
|
38
|
+
|
|
39
|
+
**Over-block (false positives — does it capture the WRONG thing?)**:
|
|
40
|
+
- Deliberately does NOT use newest-by-mtime for Claude: the agent runs many
|
|
41
|
+
concurrent Claude sessions, so mtime would grab an unrelated transcript. The
|
|
42
|
+
exact-id lookup is the correct disambiguator. This is the key reason the
|
|
43
|
+
helper is not symmetric with the codex (mtime) path.
|
|
44
|
+
- `findClaudeTranscriptShallow` intentionally does NOT recurse: a transcript
|
|
45
|
+
buried >1 level deep is not matched. Claude never writes there, so this is
|
|
46
|
+
correct, not a gap (unit-tested: `does NOT descend into nested subdirs`).
|
|
47
|
+
|
|
48
|
+
**Level-of-abstraction fit**: The transcript-locating logic moved OUT of an
|
|
49
|
+
inline closure in `AgentServer` INTO the `SessionReplyExtractor` module, which
|
|
50
|
+
already owns transcript reading. `AgentServer` keeps only the I/O orchestration
|
|
51
|
+
(poll + fall back). The pure locator is now independently unit-testable — the
|
|
52
|
+
root-cause fix has a real regression test instead of being trapped in a private
|
|
53
|
+
method.
|
|
54
|
+
|
|
55
|
+
**Signal vs authority**: No authority change. Stage-A capture is signal-only
|
|
56
|
+
into the mentor tick; it gates nothing else. `isMenteeBusy` /
|
|
57
|
+
OutstandingPromptTracker (the actual tick safe-window) is untouched.
|
|
58
|
+
|
|
59
|
+
**Interactions**:
|
|
60
|
+
- `extractMenteeReplyFromTranscript` becoming async ripples to exactly one
|
|
61
|
+
caller (the mentee role-handler), which now awaits it — verified by tsc.
|
|
62
|
+
- The mentee codex reply leg (the proven `FULL-…` round-trip path) is behavior-
|
|
63
|
+
unchanged: same codex rollout extraction, no poll.
|
|
64
|
+
- Adds two `console.log('[stage-a-diag] …')` lines in `spawnStageA`. They fire
|
|
65
|
+
once per mentor tick (low frequency) and carry only session id / framework /
|
|
66
|
+
lengths — no transcript content (no Stage-A leak surface).
|
|
67
|
+
|
|
68
|
+
**Migration parity**: Pure code change in shipped `dist/` — no agent-installed
|
|
69
|
+
files (settings hooks, config defaults, CLAUDE.md template, hook scripts,
|
|
70
|
+
skills) touched. Existing agents pick it up via the normal auto-update of the
|
|
71
|
+
`instar` package. No `PostUpdateMigrator` entry required.
|
|
72
|
+
|
|
73
|
+
**Spec**: MENTOR-LIVE-READINESS-SPEC §Recipient side (Stage-A is the
|
|
74
|
+
prompt-generation step that feeds `deliverToMentee`). This fix is the third
|
|
75
|
+
instance of the same capture-race class (#480 fixed the mentee-reply and
|
|
76
|
+
isMenteeBusy instances); it completes the §Recipient-side capture story.
|