instar 1.3.345 → 1.3.346
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 +5 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +21 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts +8 -0
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +28 -9
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/monitoring/StuckSignatureClassifier.d.ts +52 -0
- package/dist/monitoring/StuckSignatureClassifier.d.ts.map +1 -0
- package/dist/monitoring/StuckSignatureClassifier.js +133 -0
- package/dist/monitoring/StuckSignatureClassifier.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +19 -19
- package/upgrades/1.3.346.md +57 -0
- package/upgrades/honest-turn-receipts.eli16.md +47 -0
- package/upgrades/side-effects/honest-turn-receipts.md +90 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-06T05:
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-06T05:44:57.394Z",
|
|
5
|
+
"instarVersion": "1.3.346",
|
|
6
6
|
"entryCount": 199,
|
|
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": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
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": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
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": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
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": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
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": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
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": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
60
60
|
"since": "2025-01-01"
|
|
61
61
|
},
|
|
62
62
|
"hook:self-stop-guard": {
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"domain": "coherence",
|
|
66
66
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
67
67
|
"installedPath": ".instar/hooks/instar/self-stop-guard.js",
|
|
68
|
-
"contentHash": "
|
|
68
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
69
69
|
"since": "2025-01-01"
|
|
70
70
|
},
|
|
71
71
|
"hook:post-action-reflection": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"domain": "evolution",
|
|
75
75
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
76
76
|
"installedPath": ".instar/hooks/instar/post-action-reflection.js",
|
|
77
|
-
"contentHash": "
|
|
77
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
78
78
|
"since": "2025-01-01"
|
|
79
79
|
},
|
|
80
80
|
"hook:external-communication-guard": {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"domain": "safety",
|
|
84
84
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
85
85
|
"installedPath": ".instar/hooks/instar/external-communication-guard.js",
|
|
86
|
-
"contentHash": "
|
|
86
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
87
87
|
"since": "2025-01-01"
|
|
88
88
|
},
|
|
89
89
|
"hook:scope-coherence-collector": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"domain": "coherence",
|
|
93
93
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
94
94
|
"installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
|
|
95
|
-
"contentHash": "
|
|
95
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
96
96
|
"since": "2025-01-01"
|
|
97
97
|
},
|
|
98
98
|
"hook:scope-coherence-checkpoint": {
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"domain": "coherence",
|
|
102
102
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
103
103
|
"installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
|
|
104
|
-
"contentHash": "
|
|
104
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
105
105
|
"since": "2025-01-01"
|
|
106
106
|
},
|
|
107
107
|
"hook:free-text-guard": {
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"domain": "safety",
|
|
111
111
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
112
112
|
"installedPath": ".instar/hooks/instar/free-text-guard.sh",
|
|
113
|
-
"contentHash": "
|
|
113
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
114
114
|
"since": "2025-01-01"
|
|
115
115
|
},
|
|
116
116
|
"hook:claim-intercept": {
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
"domain": "coherence",
|
|
120
120
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
121
121
|
"installedPath": ".instar/hooks/instar/claim-intercept.js",
|
|
122
|
-
"contentHash": "
|
|
122
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
123
123
|
"since": "2025-01-01"
|
|
124
124
|
},
|
|
125
125
|
"hook:claim-intercept-response": {
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
"domain": "coherence",
|
|
129
129
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
130
130
|
"installedPath": ".instar/hooks/instar/claim-intercept-response.js",
|
|
131
|
-
"contentHash": "
|
|
131
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
132
132
|
"since": "2025-01-01"
|
|
133
133
|
},
|
|
134
134
|
"hook:stop-gate-router": {
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
"domain": "safety",
|
|
138
138
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
139
139
|
"installedPath": ".instar/hooks/instar/stop-gate-router.js",
|
|
140
|
-
"contentHash": "
|
|
140
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
141
141
|
"since": "2025-01-01"
|
|
142
142
|
},
|
|
143
143
|
"hook:auto-approve-permissions": {
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
"domain": "safety",
|
|
147
147
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
148
148
|
"installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
|
|
149
|
-
"contentHash": "
|
|
149
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
150
150
|
"since": "2025-01-01"
|
|
151
151
|
},
|
|
152
152
|
"job:health-check": {
|
|
@@ -1538,7 +1538,7 @@
|
|
|
1538
1538
|
"type": "subsystem",
|
|
1539
1539
|
"domain": "updates",
|
|
1540
1540
|
"sourcePath": "src/core/PostUpdateMigrator.ts",
|
|
1541
|
-
"contentHash": "
|
|
1541
|
+
"contentHash": "2562b5b7c37deb568e00eefebc9acc07571a5e5ccc251f6e424e7e63039ee297",
|
|
1542
1542
|
"since": "2025-01-01"
|
|
1543
1543
|
},
|
|
1544
1544
|
"subsystem:scheduler": {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Honest turn-receipts — the standby (🔭) system now tells the truth about WHY a
|
|
9
|
+
turn failed instead of saying "actively working" while a session is dead.
|
|
10
|
+
|
|
11
|
+
Three incidents in two days had one symptom: a delivered message that never got
|
|
12
|
+
a reply, while the standby showed "🔭 actively working." Root: the tier-3
|
|
13
|
+
assessment classified a session "working" whenever it had a live child process
|
|
14
|
+
— but a rate-limited, policy-wedged, or context-exhausted session HAS a live
|
|
15
|
+
process (the model CLI is alive, just failing every turn). The live process
|
|
16
|
+
forced the lie. Separately, the "conversation too long" standby fired on that
|
|
17
|
+
phrase anywhere in the buffer, so a stale scrolled-past mention surfaced as
|
|
18
|
+
noise on healthy sessions.
|
|
19
|
+
|
|
20
|
+
New `StuckSignatureClassifier` (pure, tail-gated, signal-only) classifies a
|
|
21
|
+
live-but-failing session from its LIVE tmux tail — rate-limited / policy-wedge /
|
|
22
|
+
context-wedge / context-too-long — and PresenceProxy surfaces the real reason
|
|
23
|
+
instead of "working". Tail-gating (the signature must be the live tail, not a
|
|
24
|
+
scrollback mention) is the same discriminator that kills the "conversation too
|
|
25
|
+
long" noise. The classifier defers to any recovery sentinel that already owns a
|
|
26
|
+
session's recovery, so the user always hears one voice. Recovery itself is
|
|
27
|
+
unchanged — this only makes the messaging honest.
|
|
28
|
+
|
|
29
|
+
## What to Tell Your User
|
|
30
|
+
|
|
31
|
+
When a message of yours goes unanswered, I'll now tell you the real reason if I
|
|
32
|
+
can't reply — "I've hit the usage limit, resets 10:30pm", "my session got stuck
|
|
33
|
+
on a content-policy error, resend your last message" — instead of a misleading
|
|
34
|
+
"actively working." And the "conversation too long" messages that used to pop up
|
|
35
|
+
when nothing was wrong are gone: that only fires now when it's actually
|
|
36
|
+
happening.
|
|
37
|
+
|
|
38
|
+
## Summary of New Capabilities
|
|
39
|
+
|
|
40
|
+
- `StuckSignatureClassifier` — tail-gated classification of a live-but-failing
|
|
41
|
+
session (rate-limited / policy-wedge / context-wedge / context-too-long) with
|
|
42
|
+
an honest user-facing message per kind. Pure + signal-only.
|
|
43
|
+
- PresenceProxy tier-3 surfaces the honest reason instead of "working", defers
|
|
44
|
+
to an owning recovery sentinel (`isStuckRecoveryActive`), and no longer fires
|
|
45
|
+
the context-too-long notice on a stale scrollback mention.
|
|
46
|
+
- CLAUDE.md "Honest standby (turn-receipts)" section so agents can explain the
|
|
47
|
+
new behavior and the noise fix.
|
|
48
|
+
|
|
49
|
+
## Evidence
|
|
50
|
+
|
|
51
|
+
Grounded in the real 2026-06-04/05 incidents (rate-limit, AUP-wedge) using the
|
|
52
|
+
verbatim pane text. 30+ new unit tests both sides of every boundary
|
|
53
|
+
(honest-when-stuck AND quiet-when-fine, incl. the stale-scrollback noise case
|
|
54
|
+
and prose-mentions-a-limit false positive) + a behavioral test driving the real
|
|
55
|
+
fireTier3 with a live child process (wedge → honest, NOT "working"; deference →
|
|
56
|
+
silent) + migrator add/idempotent + server.ts wiring guard. All 119 existing
|
|
57
|
+
presence tests pass; tsc clean; preflight PASS.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# ELI16 — Honest Turn-Receipts
|
|
2
|
+
|
|
3
|
+
## The problem
|
|
4
|
+
|
|
5
|
+
Three times in two days, the same thing happened: you sent me a message, you
|
|
6
|
+
saw "✓ Delivered" and "🔭 actively working" — and then nothing. No reply. You
|
|
7
|
+
found out by screenshot each time. Three different reasons underneath (I'd hit
|
|
8
|
+
the usage limit, or my session got stuck on a content-policy error, or the
|
|
9
|
+
conversation ran out of room), but ONE misleading symptom: the system kept
|
|
10
|
+
telling you I was "actively working" when I was actually dead in the water.
|
|
11
|
+
|
|
12
|
+
Why did it lie? Because the way it checked "is this session working?" was "is
|
|
13
|
+
its program still running?" — and a stuck session's program IS still running.
|
|
14
|
+
It's alive, it's even printing stuff to the screen; it just can't answer. So
|
|
15
|
+
the live program fooled the check into saying "working."
|
|
16
|
+
|
|
17
|
+
You also noticed a related annoyance: "conversation too long" messages popping
|
|
18
|
+
up often even when the conversation was fine. Same kind of bug — the system was
|
|
19
|
+
finding that phrase ANYWHERE on the screen, including an old one from an hour
|
|
20
|
+
ago that had already been dealt with and scrolled up out of the way.
|
|
21
|
+
|
|
22
|
+
## What this fixes
|
|
23
|
+
|
|
24
|
+
Now, before the system says "working," it reads the bottom of the screen — the
|
|
25
|
+
LIVE part, what's happening right now — and checks for the known "alive but
|
|
26
|
+
can't reply" situations. If it finds one, it tells you the truth instead:
|
|
27
|
+
|
|
28
|
+
- "I've hit the usage limit (resets 10:30pm) — I'll pick back up automatically,
|
|
29
|
+
your messages aren't lost."
|
|
30
|
+
- "My session got stuck on a content-policy error — please resend your last
|
|
31
|
+
message."
|
|
32
|
+
- "This conversation got too long — I'm starting fresh, resend your last one."
|
|
33
|
+
|
|
34
|
+
And the "conversation too long" noise is gone: it only fires if that's what's
|
|
35
|
+
ACTUALLY happening right now at the bottom of the screen, not an old mention
|
|
36
|
+
that scrolled by.
|
|
37
|
+
|
|
38
|
+
## Two safety rules
|
|
39
|
+
|
|
40
|
+
1. **It only reads — it doesn't act.** Fixing the stuck session is still the
|
|
41
|
+
job of the recovery system. This part just stops lying about what's wrong.
|
|
42
|
+
2. **One voice.** If the recovery system is already telling you about a stuck
|
|
43
|
+
session, this stays quiet so you don't get two messages about the same thing.
|
|
44
|
+
|
|
45
|
+
Tested with the exact text from the real screenshots you sent — 30+ new checks
|
|
46
|
+
covering both "say the honest thing when stuck" and "stay quiet when fine,"
|
|
47
|
+
plus all 119 existing standby checks still pass.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Side-Effects Review — Honest Turn-Receipts
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `honest-turn-receipts`
|
|
4
|
+
**Date:** `2026-06-06`
|
|
5
|
+
**Author:** `Echo (instar-dev agent, session-robustness topic — Justin: "finish out item number four" + the "conversation too long is noise" observation)`
|
|
6
|
+
**Second-pass reviewer:** `self-adversarial pass over false-positive surface (the one way an honest classifier can become a new liar) + double-messaging`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
A pure tail-gated `StuckSignatureClassifier` recognizes a live-but-failing
|
|
11
|
+
session (rate-limited / policy-wedge / context-wedge / context-too-long) from
|
|
12
|
+
its LIVE tmux tail and returns an honest user-facing message. PresenceProxy's
|
|
13
|
+
`fireTier3` runs it after the existing quota check and before the process-tree
|
|
14
|
+
"working" assessment, surfacing the real reason instead of "working", deferring
|
|
15
|
+
to an owning recovery sentinel, and preserving the context-exhaustion recovery
|
|
16
|
+
path. The un-tail-gated context-exhaustion block it replaces was the source of
|
|
17
|
+
the "conversation too long" noise. Files: `StuckSignatureClassifier.ts` (new),
|
|
18
|
+
`PresenceProxy.ts`, `server.ts` wiring, `PostUpdateMigrator.ts` section, tests.
|
|
19
|
+
|
|
20
|
+
## Decision-point inventory
|
|
21
|
+
|
|
22
|
+
- Stuck classification — **add (detector)** — signal only; tail-gated.
|
|
23
|
+
- fireTier3 placement (after quota, before process-tree) — **modify** — the
|
|
24
|
+
exact seam where a live process forced the "working" lie.
|
|
25
|
+
- context-exhaustion block — **replace** — same recovery path, now tail-gated
|
|
26
|
+
(fixes the noise) and folded into the unified honest block.
|
|
27
|
+
- `isStuckRecoveryActive` deference — **add (suppression)** — net reduction in
|
|
28
|
+
messaging authority (yields to an owning sentinel).
|
|
29
|
+
|
|
30
|
+
## 1. Over-block
|
|
31
|
+
|
|
32
|
+
Nothing is blocked — no authority added. The honest message can only fire at
|
|
33
|
+
tier-3 (5 minutes of an unanswered user message), so a session that replied
|
|
34
|
+
promptly never reaches it. The deference callback REMOVES a double-message case
|
|
35
|
+
(standby + sentinel both speaking).
|
|
36
|
+
|
|
37
|
+
## 2. Under-block (false-positive surface — the real risk)
|
|
38
|
+
|
|
39
|
+
The danger of an honest classifier is becoming a NEW liar (saying "stuck" about
|
|
40
|
+
a healthy session). Defenses, each tested:
|
|
41
|
+
- **Tail-gating:** the signature must be the live tail, not scrollback — kills
|
|
42
|
+
the stale "conversation too long" mention (the reported noise) and a session
|
|
43
|
+
that quoted an error then kept working.
|
|
44
|
+
- **Prose-vs-block rate-limit patterns:** "you've hit your limit" / "limit ·
|
|
45
|
+
resets" match; "when you hit your usage limit, the session pauses" does not.
|
|
46
|
+
- **AUP repetition gate** (inherited from classifyWedgeTail): a single benign
|
|
47
|
+
policy rejection is not a wedge.
|
|
48
|
+
- **Normal-compaction suppression:** the compaction lifecycle banner is not
|
|
49
|
+
treated as context-too-long.
|
|
50
|
+
Residual under-block: a stuck session whose signature the provider rewords
|
|
51
|
+
escapes — inherent to signature matching; the tier-3 LLM path still runs as the
|
|
52
|
+
fallback for the unmatched case (unchanged).
|
|
53
|
+
|
|
54
|
+
## 3. Level-of-abstraction fit
|
|
55
|
+
|
|
56
|
+
The classifier is a pure module beside the sentinels whose detectors it reuses
|
|
57
|
+
(`classifyWedgeTail`). The wiring lives in `fireTier3` (which owns the
|
|
58
|
+
assessment) and reuses the existing `sendProxyMessage` surface and the composed
|
|
59
|
+
`wedgeRecoveryActive` checker (same one the SessionReaper veto uses). No new
|
|
60
|
+
message path, no new state store.
|
|
61
|
+
|
|
62
|
+
## 4. Signal vs authority compliance
|
|
63
|
+
|
|
64
|
+
**Required reference:** `docs/signal-vs-authority.md`
|
|
65
|
+
|
|
66
|
+
- [x] Pure signal. The classifier decides nothing; it answers a question.
|
|
67
|
+
Recovery is unchanged (the sentinels'). The only behavioral delta is WHICH
|
|
68
|
+
honest string the standby sends, plus a new SUPPRESSION (deference). No new
|
|
69
|
+
decision-maker, and a net reduction in messaging authority.
|
|
70
|
+
|
|
71
|
+
## 5. Interactions
|
|
72
|
+
|
|
73
|
+
- **Quota-exhaustion block (runs first):** owns the bare usage-limit form; the
|
|
74
|
+
honest classifier is the backstop for the forms it misses + the wedges +
|
|
75
|
+
tail-gated context-too-long. No double-handling (the first to match returns).
|
|
76
|
+
- **RateLimitSentinel:** already suppresses ALL tiers via
|
|
77
|
+
`hasActiveRateLimitRecovery` (unchanged); the honest rate-limit branch is the
|
|
78
|
+
backstop when no sentinel owns it (e.g. the cross-machine EXO case).
|
|
79
|
+
- **ContextWedgeSentinel:** when it is mid-recovery, `isStuckRecoveryActive`
|
|
80
|
+
makes the standby defer; otherwise the honest message is the only voice.
|
|
81
|
+
- **Existing tests:** all 119 presence-proxy tests pass unmodified; the
|
|
82
|
+
context-exhaustion test's source-grep section was updated to the new wiring.
|
|
83
|
+
|
|
84
|
+
## 6. External surfaces / 7. Rollback
|
|
85
|
+
|
|
86
|
+
No API, no route, no config key (default-on behavioral change; the new config
|
|
87
|
+
field is an optional injected callback wired in server.ts). One idempotent
|
|
88
|
+
CLAUDE.md section (marker 'Honest standby (turn-receipts)'). Rollback = revert;
|
|
89
|
+
the standby returns to classifying live-but-failing sessions as "working" and
|
|
90
|
+
the context-too-long noise returns.
|