instar 1.3.1007 → 1.3.1008

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1007",
3
+ "version": "1.3.1008",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-27T17:44:44.950Z",
5
- "instarVersion": "1.3.1007",
4
+ "generatedAt": "2026-07-27T18:15:59.710Z",
5
+ "instarVersion": "1.3.1008",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -1530,7 +1530,7 @@
1530
1530
  "type": "subsystem",
1531
1531
  "domain": "server",
1532
1532
  "sourcePath": "src/server/AgentServer.ts",
1533
- "contentHash": "b9037bc4bf60a2fb1a9a949e00e2453cf93069a6a40825cbffbc5177f6309043",
1533
+ "contentHash": "a96f5e8942bb9a56eba284e59992f5f027a249cb7e600ae08db78a579764572e",
1534
1534
  "since": "2025-01-01"
1535
1535
  },
1536
1536
  "subsystem:session-manager": {
@@ -0,0 +1,39 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The live mentor-onboarding delivery path now places a durable content-keyed retry brake in front of every outbound prompt.
9
+
10
+ - Identical unanswered content is limited to three attempts.
11
+ - The attempt is persisted before transport actuation.
12
+ - A transport refusal consumes the same bounded budget as an unacknowledged send.
13
+ - The fourth identical attempt is suppressed.
14
+ - A different agenda item receives an independent budget.
15
+ - Exhaustion emits one distinct delivery-degradation signal, protected by a restart-surviving latch.
16
+ - The retry ledger stores hashes rather than prompt text and refuses growth beyond 64 unresolved keys.
17
+
18
+ The mentor tick now awaits the delivery callback and records a specific `deliveryReason` when the delivery layer refuses or fails. It no longer marks an asynchronous send as delivered before the transport has answered.
19
+
20
+ ## What to Tell Your User
21
+
22
+ Mentor onboarding will no longer keep reposting the same unanswered question forever. It makes at most three attempts for identical content, remembers that limit across restarts, and reports one distinct delivery failure when the limit is reached. A genuinely new agenda item can still proceed.
23
+
24
+ The prior anti-ping-pong guard was correlation-scoped. Once an unanswered correlation aged past the reply timeout, the guard deleted it and the next tick could post the same generated question again. A bot-to-bot receive-path failure therefore produced about twenty-four visible copies over twelve hours.
25
+
26
+ ## Summary of New Capabilities
27
+
28
+ - Durable, normalized-content deduplication bounds identical unanswered mentor prompts at three attempts.
29
+ - Retry exhaustion and transport failures are visible as structured delivery outcomes with one restart-surviving escalation.
30
+ - New agenda content remains independently eligible while an exhausted item stays suppressed.
31
+ - Existing version-1 outstanding-prompt files load normally and upgrade on their next write.
32
+
33
+ ## Compatibility
34
+
35
+ Existing version-1 outstanding-prompt files continue to load. The next write upgrades the file to version 2. No config, route, migration job, tick cadence, agenda rule, or reply timeout changes.
36
+
37
+ ## Validation
38
+
39
+ Refusal-first unit tests failed on unmodified source, then passed with the implementation. Unit, integration, and end-to-end coverage pins the bounded attempts, novel-content independence, restart durability, one-shot escalation, production transport-failure behavior, and status visibility.
@@ -0,0 +1,53 @@
1
+ # Bounded mentor-onboarding retries — Plain-English Overview
2
+
3
+ > The one-line version: an unanswered mentor prompt can now be sent at most three times, the limit survives a restart, and the system reports delivery trouble instead of posting the same question forever.
4
+
5
+ ## The problem
6
+
7
+ The mentor loop already avoided sending a second prompt while the first one was waiting for a reply. That protection had a hole: after twenty minutes, the old correlation was declared expired and removed. The next tick then treated the same words as a brand-new prompt.
8
+
9
+ That is how one permission question appeared about every thirty minutes for roughly twelve hours. Each individual send looked legal because the previous correlation had expired. Across the whole episode, however, there was no content-level limit, so the system could repeat its own action indefinitely.
10
+
11
+ The visible Telegram post also did not prove that the mentee could receive it. Telegram can display a message from one bot while withholding that bot-authored message from another bot's update stream. The old loop interpreted the missing reply as an unanswered coaching question and retried. It needed to recognize the repeated lack of confirmation as a delivery problem.
12
+
13
+ ## What changes
14
+
15
+ Before any live mentor send, the existing outstanding-prompt tracker now normalizes the message, combines it with the mentee identity, and hashes that pair into a content key. The tracker durably reserves the attempt before it calls the transport.
16
+
17
+ Each content key gets three attempts:
18
+
19
+ - Attempt one is allowed.
20
+ - Attempts two and three are allowed after the earlier correlation expires or the transport refuses it.
21
+ - A fourth attempt with the same unanswered content is refused.
22
+ - Different content gets a different key and remains eligible.
23
+
24
+ The state file is upgraded in place from version 1 to version 2. It keeps the existing outstanding correlations and adds a bounded retry ledger. Only hashes and timing/count metadata are stored; the prompt text is not copied into this state.
25
+
26
+ ## Why the ordering matters
27
+
28
+ The reservation is written before the send. If the retry ledger cannot be persisted, the transport is not called. This prevents a disk or state failure from silently removing the very brake that makes the self-action bounded.
29
+
30
+ A transport refusal still consumes an attempt. Otherwise an unreachable destination could be retried forever while the counter remained at zero. A confirmed correlated reply clears that content episode, because repeating the same words after an actual reply is a new conversation rather than an unanswered retry.
31
+
32
+ ## What the operator sees
33
+
34
+ The normal first attempts remain unchanged. When the content budget is exhausted, the mentor tick reports a distinct delivery reason instead of claiming success or folding the event into a generic unanswered-question state.
35
+
36
+ The first exhaustion also emits one degradation signal explaining that delivery could not be confirmed and that identical sends are now suppressed. A persisted `escalatedAt` latch prevents the escalation itself from becoming another flood, including across a restart.
37
+
38
+ ## Boundaries
39
+
40
+ This change does not alter Threadline identity resolution, Telegram's bot-to-bot behavior, the process-wide LLM circuit breaker, the mentor agenda, the reply timeout, the tick cadence, or budget limits. It does not add a route or configuration switch.
41
+
42
+ The retry ledger is capped at 64 unresolved content keys. Reaching that cap refuses new mentor sends rather than growing state without limit. Version-1 files remain readable and are rewritten as version 2 on the next state change.
43
+
44
+ ## Proof
45
+
46
+ The four requested refusal-first tests were added before implementation and failed against the original source because `reserveSend` did not exist. After implementation they prove:
47
+
48
+ - first content is allowed;
49
+ - identical unanswered content is refused after three attempts;
50
+ - a different agenda item remains allowed;
51
+ - the breaker and its one-shot escalation survive a reconstructed tracker using the same state file.
52
+
53
+ Additional coverage proves whitespace-normalized dedupe, raw prompt text exclusion, the 64-key state bound, asynchronous delivery outcome handling, HTTP status propagation, and the real production delivery closure over three transport failures plus a fourth-send refusal.
@@ -0,0 +1,142 @@
1
+ # Side-Effects Review — Bounded mentor-onboarding retries
2
+
3
+ **Version / slug:** `bounded-mentor-onboarding-retries`
4
+ **Date:** `2026-07-27`
5
+ **Author:** `Instar Agent (instar-codey)`
6
+ **Review tier:** Tier 1, user-directed
7
+
8
+ ## Summary of the change
9
+
10
+ `OutstandingPromptTracker` extends its existing durable correlation ledger with a content-keyed retry ledger. Live mentor delivery reserves an attempt before transport, permits at most three attempts for the same unanswered normalized content, keeps new content independent, and persists a one-shot exhaustion escalation. `runMentorTick` now awaits the delivery callback and exposes the delivery layer's structured reason.
11
+
12
+ The tracker persists only SHA-256 content keys plus mentee, attempt, timestamp, and escalation metadata. The ledger holds at most 64 unresolved content keys. Existing version-1 files load and upgrade on the next write.
13
+
14
+ ## Decision-point inventory
15
+
16
+ - `OutstandingPromptTracker.reserveSend` — **new authority inside an existing authority** — permits or refuses one mentor send based on in-flight state, content-key attempts, storage availability, and the fixed ledger capacity.
17
+ - `OutstandingPromptTracker.clearByCorr` — **modified** — a correlated reply now closes both the outstanding correlation and that content's retry episode.
18
+ - `OutstandingPromptTracker.markDeliveryFailed` — **new transition** — removes the in-flight correlation while retaining the consumed attempt.
19
+ - `AgentServer.deliverToMentee` — **modified actuation boundary** — durably reserves before transport and returns a structured delivery outcome.
20
+ - `runMentorTick` — **modified observer** — awaits the delivery boundary and records its reason; it does not decide the retry policy.
21
+ - `DegradationReporter.report` — **existing signal path** — emits one delivery-exhaustion event after the durable latch admits it.
22
+
23
+ ---
24
+
25
+ ## 1. Over-block
26
+
27
+ The brake can suppress a prompt whose wording is identical even if the mentor intended a semantically separate repetition. That only happens after three sends without a correlated reply. A confirmed reply deletes the content episode, so later reuse after a real conversation is allowed. A genuinely different agenda item hashes separately and remains eligible.
28
+
29
+ Whitespace is normalized before hashing. Cosmetic spacing cannot evade the brake, but punctuation or wording changes produce a new key. This is deliberate: the gate refuses exact normalized repetition, not semantic similarity judged by a brittle classifier.
30
+
31
+ The 64-key ledger cap can refuse a novel prompt after 64 unresolved content episodes. That is a fail-closed capacity bound. It prefers pausing the autonomous mentor over allowing either unbounded state growth or eviction that would silently reopen old breakers.
32
+
33
+ ---
34
+
35
+ ## 2. Under-block
36
+
37
+ An LLM can paraphrase the same intent and receive a new content key. This patch closes the observed identical-content loop, not semantic-repetition detection. Semantic dedupe would require judgment and risks suppressing legitimately revised questions; it is intentionally outside this Tier 1 correction.
38
+
39
+ A corrupt version-2 file follows the tracker's existing corruption behavior and starts with fresh in-memory state. Normal restarts over valid state preserve the brake, which is the requested failure mode. Hardening corrupt-state recovery into a fail-closed operator repair state is a broader storage-policy change and is not smuggled into this patch.
40
+
41
+ Version-1 outstanding entries have no historical content key. They preserve the existing in-flight refusal but cannot retroactively consume a content attempt. The first post-upgrade content reservation begins the new bounded history.
42
+
43
+ ---
44
+
45
+ ## 3. Level-of-abstraction fit
46
+
47
+ The retry authority belongs in `OutstandingPromptTracker`, which already owns the durable question “may this mentor send another prompt to this mentee?” Adding a second disconnected store would create competing truth for the same actuation boundary.
48
+
49
+ Content normalization and hashing live beside the attempt state. `AgentServer` owns orchestration: reserve, call transport, mark immediate failure, append sent history, and emit degradation. `runMentorTick` only awaits and surfaces the structured outcome. No transport adapter is taught mentor-specific policy.
50
+
51
+ ---
52
+
53
+ ## 4. Signal vs authority compliance
54
+
55
+ **Required reference:** `docs/signal-vs-authority.md`
56
+
57
+ The static retry count is appropriate hard authority because “never perform identical autonomous sends without a bound” is a safety invariant, not a competing-signals judgment. The gate uses exact normalized content, explicit counters, and durable state. It does not guess user intent, message quality, or semantic equivalence.
58
+
59
+ The degradation event is signal-only. It cannot reopen the breaker, alter the agenda, change transport routing, or authorize another send. The durable tracker remains the sole authority.
60
+
61
+ ---
62
+
63
+ ## 4b. Judgment-point check
64
+
65
+ No LLM or heuristic decides whether the retry budget is exhausted. The decision inputs are a stable content key, integer attempt count, fixed maximum, outstanding correlation, and store health.
66
+
67
+ The number three is a conservative structural ceiling for an existing retry loop that previously had no ceiling. It is not exposed as configuration in this patch, avoiding a migration surface and preventing an operator from accidentally configuring the invariant away.
68
+
69
+ ---
70
+
71
+ ## 5. Interactions
72
+
73
+ - **Outstanding timeout:** an expired correlation is still swept, but its content attempt remains. Expiry permits evaluation of the next attempt; it no longer resets history.
74
+ - **Immediate transport refusal:** the pre-send reservation remains counted while the outstanding correlation is removed, so a dead transport reaches the same breaker without waiting twenty minutes per attempt.
75
+ - **Successful delivery:** the correlation stays outstanding until its matching reply or timeout.
76
+ - **Matching reply:** clears the outstanding row and content retry episode.
77
+ - **Late reply after timeout:** remains classified by the existing late/unknown-correlation behavior and does not silently reopen an exhausted content key.
78
+ - **Restart:** entries, retry counts, and `escalatedAt` reload from one atomic JSON file.
79
+ - **Concurrent tick:** the runner's existing single in-flight guard plus the tracker's per-mentee outstanding check prevents overlapping reservations in this process.
80
+ - **Multi-machine:** state remains machine-local, matching the existing mentor runner's single active process. This patch adds no replicated authority.
81
+ - **Escalation flood:** `recordRetryExhaustionEscalated` persists the latch before the degradation call. Repeated ticks see the open breaker and decline the signal.
82
+ - **State growth:** 64 unresolved keys is a hard ceiling; raw message content is absent from this store.
83
+
84
+ ---
85
+
86
+ ## 6. External surfaces
87
+
88
+ `GET /mentor/status.lastResult` can now include `deliveryReason` for a live tick. Existing fields and status codes remain unchanged; JSON omits the optional field when no delivery-layer reason exists.
89
+
90
+ Operators may receive one existing-style degradation alert under the new feature name `mentor.delivery-unconfirmed-retry-exhausted`. Its content describes a delivery failure and the automatic suppression. It does not ask the operator to edit files, run commands, or diagnose raw internals.
91
+
92
+ No Telegram API call shape, Threadline identity rule, bot token handling, topic selection, endpoint, config key, or dashboard surface changes.
93
+
94
+ ---
95
+
96
+ ## 6b. Operator-surface quality
97
+
98
+ The only operator-facing addition is the existing degradation channel's plain-language event. It leads with the condition and effect: prompt delivery could not be confirmed, so identical sends stopped. It exposes no hash, correlation id, state path, token, or stack trace as primary content. There is no destructive action. The message is short enough for phone width and introduces no form or technical input.
99
+
100
+ ---
101
+
102
+ ## 7. Multi-machine posture
103
+
104
+ **Posture: intentionally machine-local.** The mentor runner and its outstanding-prompt tracker already live on the machine executing Echo's mentor tick. A send is reserved and actuated by that same process. Replicating attempt authority without a cross-machine single-writer contract would create two counters that could each admit three sends.
105
+
106
+ This patch preserves the existing one-process ownership boundary. If mentor execution becomes active-active in the future, the tracker must move behind a shared claim/lease before that rollout; this change does not claim cross-machine safety for a topology that is not currently enabled.
107
+
108
+ ---
109
+
110
+ ## 8. Rollback cost
111
+
112
+ Reverting the code restores version-1 behavior. Older code reads the version-2 file as unsupported and starts fresh, so rollback removes the brake until the prior version is restored. No database migration or user-data conversion is required. The file contains only machine-local mentor retry metadata and can be regenerated.
113
+
114
+ The additive `deliveryReason` field disappears on rollback. Existing consumers already tolerate its absence.
115
+
116
+ ---
117
+
118
+ ## Class-Closure Declaration
119
+
120
+ **Defect class:** `unbounded-self-action`
121
+ **Closure:** `guard`
122
+
123
+ The guard is the durable pre-transport reservation plus the three-attempt content-key breaker. Unit tests prove the first send, cap, independent novel content, restart persistence, one-shot escalation, normalization, and capacity bound. The production-wiring E2E test drives three refused transport attempts, requires the fourth identical attempt to be suppressed, and requires a new message to retain an independent attempt.
124
+
125
+ Steady state for one unanswered content key is therefore: at most three outbound attempts, one exhaustion signal, then permanent suppression in valid durable state. The escalation path cannot recursively send another mentor prompt.
126
+
127
+ ---
128
+
129
+ ## Evidence pointers
130
+
131
+ - Refusal-first: four new tracker tests failed against unmodified source with `reserveSend is not a function`; ten pre-existing tracker tests remained green.
132
+ - Focused proof after implementation: 77/77 across tracker, tick, runner, route integration, production lifecycle, and mentor config hot-read coverage.
133
+ - Static validation: `npm run build` and `npm run lint` pass.
134
+ - No route, config, transport identity, LLM breaker, cadence, budget, or agenda change.
135
+
136
+ ---
137
+
138
+ ## Causal autopsy
139
+
140
+ **Origin:** latent.
141
+
142
+ The correlation-scoped anti-ping-pong guard was correct within one reply window but treated timeout expiry as the end of all retry history. That latent reset became an unbounded loop when Telegram visibly accepted bot-authored posts that the mentee bot could not ingest. Every correlation expired normally, so the system repeatedly regenerated and resent identical content while believing each attempt was new.