instar 1.3.444 → 1.3.445
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/README.md +9 -1
- package/dist/commands/server.d.ts +20 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +64 -30
- package/dist/commands/server.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.445.md +99 -0
- package/upgrades/side-effects/fixcommand-gate-nonattention-fallthrough.md +93 -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-09T17:12:42.642Z",
|
|
5
|
+
"instarVersion": "1.3.445",
|
|
6
6
|
"entryCount": 199,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Scopes the emergency "fix command" gate to the **Agent Attention topic** so it can no longer swallow ordinary messages in other topics. The gate in `wireTelegramRouting` (`src/commands/server.ts`) used to intercept any message starting with `restart`, `fix `, or `clean ` in **every** topic, hand it to `handleFixCommand`, and `return` — but `handleFixCommand` only does anything in the Agent Attention topic and returns `false` everywhere else. So in a normal topic the message was bounced back with *"I didn't recognize that command. Available fix commands: …"* (a list that even advertised "restart sessions" as valid) **and never routed to the session**. A user typing "restart sessions" to revive a stuck session in that session's own topic was hit by exactly this: the gate ate the message. The decision is now a pure, unit-tested helper `shouldInterceptFixCommand(text, topicId, attentionTopicId)` that returns true only inside the attention topic; `wireTelegramRouting` resolves the attention topic via a late-bound `getAttentionTopicId` and both call sites pass it. Outside the attention topic the message falls through to normal session routing — including plain phrases like "restart the build" or "fix the login page" that were silently eaten before.
|
|
9
|
+
|
|
10
|
+
## What to Tell Your User
|
|
11
|
+
|
|
12
|
+
If you ever messaged a session something starting with "restart", "fix", or "clean" — including trying to revive a stuck session by typing "restart sessions" — and got a confusing *"I didn't recognize that command"* reply (with a list that literally showed the command you typed), that message was being intercepted and never reached the session. That's fixed: those messages now go through to the session like any other. The "fix command" shortcuts (restart, fix auth, clean processes, …) still work — they just only apply in the Agent Attention topic, which is where I post the notifications you tap to resolve.
|
|
13
|
+
|
|
14
|
+
## Summary of New Capabilities
|
|
15
|
+
|
|
16
|
+
| Capability | How to Use |
|
|
17
|
+
|-----------|-----------|
|
|
18
|
+
| Fix-command shortcuts scoped to the Agent Attention topic | unchanged — tap/reply in the Attention topic; everywhere else your message reaches the session |
|
|
19
|
+
| Ordinary "restart/fix/clean …" messages reach the session | just send them normally in any session topic |
|
|
20
|
+
|
|
21
|
+
## Evidence
|
|
22
|
+
|
|
23
|
+
Reproduction (live, 2026-06-09, topic 21624 "initiatives and maturation check-ins"): the user typed `restart sessions` to unstick a session and got *"I didn't recognize that command. Available fix commands: … • restart sessions — Restart stuck sessions"* — the gate swallowed the message (no `restart sessions` ever appeared in the session's tmux pane) while listing the exact command as valid. Root cause traced in code: the gate's `isFixCommand` verb test ran in all topics and `return`ed after `handleFixCommand` (which guards on `topicId === agent-attention-topic` and returns `false` otherwise).
|
|
24
|
+
|
|
25
|
+
After the fix: new unit suite `tests/unit/fix-command-routing.test.ts` (17 tests) pins both sides of the boundary — in the attention topic every fix verb intercepts (and verb-lookalikes "fixture"/"cleanup" do not), while in a non-attention topic "restart sessions", "restart the build", "fix the login page", "clean up this function" all return `false` (fall through to the session); a null/undefined attention topic never intercepts. `tsc --noEmit` clean; the full set of unit tests importing `commands/server` (38 files, 364 tests) green.
|
|
26
|
+
|
|
27
|
+
## The problem
|
|
28
|
+
|
|
29
|
+
You sent a session a message to wake it up — "restart sessions" — and instead
|
|
30
|
+
of doing anything, I replied *"I didn't recognize that command"* and showed you
|
|
31
|
+
a list of commands that literally included "restart sessions." That's
|
|
32
|
+
maddening: I rejected the exact thing I told you to type. Worse, your message
|
|
33
|
+
never actually reached the session at all.
|
|
34
|
+
|
|
35
|
+
Here's what was really happening under the hood.
|
|
36
|
+
|
|
37
|
+
I have a set of emergency "fix command" shortcuts — short things you can type
|
|
38
|
+
like "restart", "fix auth", "clean processes" — that I handle directly without
|
|
39
|
+
spinning up a whole AI session. They exist for one specific place: the **Agent
|
|
40
|
+
Attention topic**, where I post little "something needs fixing, tap to resolve"
|
|
41
|
+
notifications. In that topic, typing "restart" should just work.
|
|
42
|
+
|
|
43
|
+
The bug: the code that *catches* those shortcut words was running in **every
|
|
44
|
+
topic**, not just the Attention topic. So any message you sent that happened to
|
|
45
|
+
start with "restart", "fix ", or "clean " got grabbed by the shortcut-catcher
|
|
46
|
+
first. The catcher then asked the real handler to run it — but the real handler
|
|
47
|
+
checks "am I in the Attention topic?" and, if not, quietly says "not mine" and
|
|
48
|
+
does nothing. At that point the catcher gave up with the confusing "I didn't
|
|
49
|
+
recognize that command" message **and threw your message away** — it never got
|
|
50
|
+
passed along to the session you were actually talking to.
|
|
51
|
+
|
|
52
|
+
So two everyday things were broken:
|
|
53
|
+
1. Trying to revive a stuck session by typing "restart sessions" in that
|
|
54
|
+
session's own topic — eaten, with a misleading reply.
|
|
55
|
+
2. Just talking normally — "restart the build", "fix the login page", "clean up
|
|
56
|
+
this function" — anything that started with one of those words got silently
|
|
57
|
+
swallowed instead of reaching the session.
|
|
58
|
+
|
|
59
|
+
## What already exists
|
|
60
|
+
|
|
61
|
+
- The fix-command shortcuts ("restart", "fix auth", etc.) and the handler that
|
|
62
|
+
runs them. These were already correctly limited to the Attention topic *on
|
|
63
|
+
the execution side* — the handler refuses to act anywhere else.
|
|
64
|
+
- The normal path that routes a message to its session. That path was always
|
|
65
|
+
there; the shortcut-catcher was just jumping in front of it and stopping it.
|
|
66
|
+
|
|
67
|
+
## What's new
|
|
68
|
+
|
|
69
|
+
One small, surgical change: the shortcut-catcher now checks **which topic it's
|
|
70
|
+
in before grabbing the message.** It only intercepts inside the Agent Attention
|
|
71
|
+
topic. Everywhere else, the message flows straight through to the session like
|
|
72
|
+
any other message.
|
|
73
|
+
|
|
74
|
+
The check is a tiny pure function, `shouldInterceptFixCommand(text, topicId,
|
|
75
|
+
attentionTopicId)`, that returns "yes, intercept" only when the message is in
|
|
76
|
+
the Attention topic AND looks like a fix command. It's covered by 17 unit tests
|
|
77
|
+
that nail down both sides: in the Attention topic the shortcuts still fire (and
|
|
78
|
+
lookalike words like "fixture" or "cleanup" correctly don't); in any other
|
|
79
|
+
topic, "restart sessions" and friends fall through to the session.
|
|
80
|
+
|
|
81
|
+
## The safeguards in plain terms
|
|
82
|
+
|
|
83
|
+
- **Nothing is removed.** The fix-command shortcuts still work exactly as
|
|
84
|
+
before — they were always Attention-topic-only on the execution side; now the
|
|
85
|
+
catching side agrees. So no real capability is lost.
|
|
86
|
+
- **Fail-safe default.** If I don't yet know which topic is the Attention topic
|
|
87
|
+
(e.g. very early at startup), the catcher simply doesn't intercept — messages
|
|
88
|
+
go to the session. That's the safe direction: route, don't swallow.
|
|
89
|
+
- **It only makes the gate *less* aggressive.** This change can only let more
|
|
90
|
+
messages through to sessions; it can never block a message that wasn't already
|
|
91
|
+
being blocked. That's why the risk is low.
|
|
92
|
+
|
|
93
|
+
## What you need to decide
|
|
94
|
+
|
|
95
|
+
Nothing complicated. This is a bug fix that makes your messages reliably reach
|
|
96
|
+
your sessions. The only judgment call is whether to ship it as a normal patch
|
|
97
|
+
(yes) — there's no new setting to configure and no behavior you have to opt
|
|
98
|
+
into. After it deploys, "restart sessions" (and ordinary chat starting with
|
|
99
|
+
restart/fix/clean) will reach the session instead of being eaten.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Side-Effects Review — Scope the fix-command gate to the Agent Attention topic
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `fixcommand-gate-nonattention-fallthrough`
|
|
4
|
+
**Date:** `2026-06-09`
|
|
5
|
+
**Author:** `Instar Agent (echo)`
|
|
6
|
+
**Second-pass reviewer:** `independent reviewer subagent — concurred`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The emergency "fix command" gate in `wireTelegramRouting` (`src/commands/server.ts`) intercepted any inbound Telegram message whose text started with `restart`, `fix `, or `clean ` in **every** topic, dispatched it to `handleFixCommand`, and unconditionally `return`ed. But `handleFixCommand` only executes in the Agent Attention topic (`topicId === state.get('agent-attention-topic')`) and returns `false` everywhere else — so in a non-attention topic the gate sent the user an "I didn't recognize that command" help list **and swallowed the message** (it never reached the session). This change introduces a pure, exported helper `shouldInterceptFixCommand(text, topicId, attentionTopicId)` that returns true only when the message is in the Agent Attention topic and matches a fix verb. `wireTelegramRouting` gains a late-bound `getAttentionTopicId?: () => number | null | undefined` parameter; both call sites pass `() => state.get<number>('agent-attention-topic')`. The gate now fires only when `shouldInterceptFixCommand(...)` is true; otherwise the message falls through to normal session routing. Files: `src/commands/server.ts` (helper + signature + gate + 2 call sites), `tests/unit/fix-command-routing.test.ts` (new).
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
- `wireTelegramRouting` fix-command gate (`src/commands/server.ts`, inbound Telegram dispatch) — **modify** — the gate that decides whether a message is handled as a server-side fix command (and swallowed) vs routed to the session. Previously gated on a topic-agnostic verb test; now gated on `shouldInterceptFixCommand` which additionally requires the Agent Attention topic.
|
|
15
|
+
- `handleFixCommand`'s internal attention-topic guard (lines ~186) — **pass-through (kept)** — retained as defense-in-depth; it still returns `false` outside the attention topic, so even if the gate ever fired in the wrong topic nothing would execute.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 1. Over-block
|
|
20
|
+
|
|
21
|
+
**What legitimate inputs does this change reject that it shouldn't?**
|
|
22
|
+
|
|
23
|
+
This change strictly *reduces* blocking. Before: any message starting with `restart`/`fix `/`clean ` in a non-attention topic was swallowed (over-blocked). After: those messages route to the session. Inside the Agent Attention topic the behavior is unchanged. There is no new input that is now rejected that previously was accepted — the change can only let *more* messages through. So: no new over-block introduced; an existing over-block (the core bug) is removed.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. Under-block
|
|
28
|
+
|
|
29
|
+
**What failure modes does this still miss?**
|
|
30
|
+
|
|
31
|
+
Within the Agent Attention topic, the verb test is still a brittle prefix match (`startsWith('restart')`, etc.). A user in the Attention topic typing a non-command sentence that happens to start with "restart"/"fix "/"clean " (e.g. "restart the build") will still get the "I didn't recognize that command" help instead of being treated as chat. This is unchanged from before and is acceptable: the Attention topic is a control surface for tapping notifications, not a general chat thread, and `handleFixCommand` already only acts on the exact known commands. We are deliberately not widening or narrowing the in-attention-topic verb matching in this change (single-responsibility: fix the topic-scoping bug only). No tracked deferral — the in-topic verb matching is correct for its purpose, not an omission.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Level-of-abstraction fit
|
|
36
|
+
|
|
37
|
+
**Is this at the right layer?**
|
|
38
|
+
|
|
39
|
+
Yes. The routing decision belongs exactly where the gate sits — at the inbound message dispatch in `wireTelegramRouting`, before session routing. The change extracts the *decision* into a pure function (`shouldInterceptFixCommand`) at the same layer, which is the right altitude: it is a cheap, deterministic predicate, not a reasoning task, and it now consumes the same `agent-attention-topic` state that `handleFixCommand` already used as its own guard — so the gate and the handler now agree on the same authority (the attention topic) instead of the gate being topic-blind. No higher-level (LLM) gate is warranted: "is this the attention topic and a known verb" is objective.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 4. Signal vs authority compliance
|
|
44
|
+
|
|
45
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
46
|
+
|
|
47
|
+
- [x] No — this change has no NEW block/allow surface; it *narrows* an existing brittle authority so it no longer over-reaches.
|
|
48
|
+
|
|
49
|
+
The fix-command gate is a brittle (prefix-match) detector that holds blocking authority (it swallows the message). Per the signal-vs-authority principle, a brittle detector must not over-extend its blocking authority. This change does the principle-compliant thing: it constrains that brittle authority to the one topic where the action is actually valid (the Agent Attention control topic), and removes its authority everywhere else (fall through to session). It does not add new brittle blocking authority; it shrinks existing brittle blocking authority to its legitimate scope. No reshaping needed.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 5. Interactions
|
|
54
|
+
|
|
55
|
+
- **Shadowing:** The gate runs after the slash-command handler and the threadline hub-command intercept, and before the pipeline/session routing. Previously it *shadowed* session routing for any restart/fix/clean-prefixed message in every topic. After this change it only shadows session routing in the Agent Attention topic — which is correct, since fix commands there are not meant to spawn a session. No other check is newly shadowed.
|
|
56
|
+
- **Double-fire:** No. The gate `return`s on intercept (only in the attention topic now), so a message is either handled as a fix command OR routed to the session, never both. `handleFixCommand`'s own attention guard prevents double execution even if the gate condition were wrong.
|
|
57
|
+
- **Races:** The new param is a synchronous getter over `StateManager.get` (the same in-memory/JSON state the rest of routing reads). No new shared mutable state is introduced; `getAttentionTopicId` only reads.
|
|
58
|
+
- **Feedback loops:** None. The predicate reads state and returns a boolean; it feeds nothing back.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 6. External surfaces
|
|
63
|
+
|
|
64
|
+
- **Other agents / users:** This is instar source shipped to the whole install base. User-visible effect is strictly positive: messages starting with restart/fix/clean now reach the session in normal topics. The "I didn't recognize that command" reply will no longer appear in non-attention topics (it remains in the Attention topic for genuinely unknown commands).
|
|
65
|
+
- **External systems:** No change to Telegram API usage, payloads, or the fix-command actions themselves (restart/clean/etc. behave identically when invoked in the Attention topic).
|
|
66
|
+
- **Persistent state:** None. No new state keys, ledgers, or migrations. Reads the existing `agent-attention-topic` key only.
|
|
67
|
+
- **Timing/runtime:** If `agent-attention-topic` isn't set yet (early boot), the getter returns null/undefined and the gate simply doesn't intercept — messages route to the session. Safe direction.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 7. Rollback cost
|
|
72
|
+
|
|
73
|
+
Pure code change, no persistent state, no migration. Back-out = revert the commit and ship the next patch; behavior returns to the prior (buggy) state with no cleanup. No agent-state repair, no data migration. During the rollback window users would simply see the old swallow-and-bounce behavior again. Low rollback cost.
|
|
74
|
+
|
|
75
|
+
## Conclusion
|
|
76
|
+
|
|
77
|
+
The review confirms this is a scope-narrowing fix to a brittle blocking authority: it removes an over-block (the core bug — messages swallowed in non-attention topics) and adds no new blocking surface. The decision is extracted into a pure, fully unit-tested predicate, and the gate now agrees with the handler's own attention-topic guard. No design changes were required by the review. Because the change touches inbound message dispatch, a Phase-5 second-pass review is required before commit.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Second-pass review (if required)
|
|
82
|
+
|
|
83
|
+
**Reviewer:** independent reviewer subagent (general-purpose)
|
|
84
|
+
**Independent read of the artifact: concur**
|
|
85
|
+
|
|
86
|
+
Concur with the review. The reviewer independently verified: (1) the boundary — `shouldInterceptFixCommand` returns false for null/undefined attention topic and for any non-attention topic, true only in the attention topic with a matching verb, and the verb clause is byte-identical to the old inline test (no in-topic regression); (2) BOTH `wireTelegramRouting` call sites (server.ts:4062-4066 send-only and 4203-4207 full) pass the `() => state.get<number>('agent-attention-topic')` resolver — no path left on old behavior; (3) no new swallow/double-fire — the gate `return`s only on intercept, normal routing sits immediately below, and `handleFixCommand`'s internal attention guard is harmless redundant defense; (4) signal-vs-authority — strictly narrows existing brittle blocking authority, adds no new block surface. Additional checks: `wireWhatsAppRouting` has no parallel fix-command gate (no missed surface); the stuck-message replay path re-injects through the same handler so it inherits the corrected boundary; existing test callers omit the new optional arg safely (null-safe getter). One non-blocking observation: new coverage is unit-only (the pure predicate, both sides) — proportionate since this adds no API route or DI component; wiring verified correct by inspection.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Evidence pointers
|
|
91
|
+
|
|
92
|
+
- Live reproduction: 2026-06-09, topic 21624 — user typed `restart sessions`, received the "I didn't recognize that command" help list (which advertised "restart sessions"), and the text never appeared in the session's tmux pane.
|
|
93
|
+
- Tests: `tests/unit/fix-command-routing.test.ts` (17 tests, both sides of the boundary). `tsc --noEmit` clean; 364 unit tests across the 38 files importing `commands/server` green.
|