instar 1.3.632 → 1.3.633

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.
@@ -22,6 +22,15 @@ export declare class FeedbackManager {
22
22
  private version;
23
23
  /** Cache of agentName -> pseudonym for resolvePseudonym reverse lookups */
24
24
  private pseudonymMap;
25
+ /**
26
+ * Webhook backoff state (L364). When the canonical feedback endpoint rate-limits
27
+ * us (429/503), we stop POSTing until `webhookNextRetryAtMs` and grow the wait
28
+ * with `webhookConsecutive429s`. In-memory by design: a restart re-probes once
29
+ * (one cycle) then re-backs-off — back-compatible and self-correcting. This is
30
+ * what stops `retryUnforwarded()` from re-POSTing the whole backlog every cycle.
31
+ */
32
+ private webhookNextRetryAtMs;
33
+ private webhookConsecutive429s;
25
34
  constructor(config: FeedbackConfig);
26
35
  /** Standard headers that identify this as a legitimate Instar agent. */
27
36
  private getWebhookHeaders;
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackManager.d.ts","sourceRoot":"","sources":["../../src/core/FeedbackManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAS/D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,2EAA2E;IAC3E,OAAO,CAAC,YAAY,CAAkC;gBAE1C,MAAM,EAAE,cAAc;IASlC,wEAAwE;IACxE,OAAO,CAAC,iBAAiB;IAoBzB,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAkBjC;;;OAGG;IACH,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,qBAAqB;IAuBlF;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAS5C;;;OAGG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAoBlD;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,aAAa,GAAG,WAAW,GAAG,gBAAgB,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAqDpH;;OAEG;IACH,IAAI,IAAI,YAAY,EAAE;IAItB;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAKpC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAiDzE,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;CAQvB"}
1
+ {"version":3,"file":"FeedbackManager.d.ts","sourceRoot":"","sources":["../../src/core/FeedbackManager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAU/D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,2EAA2E;IAC3E,OAAO,CAAC,YAAY,CAAkC;IACtD;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,sBAAsB,CAAK;gBAEvB,MAAM,EAAE,cAAc;IASlC,wEAAwE;IACxE,OAAO,CAAC,iBAAiB;IAoBzB,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAkBjC;;;OAGG;IACH,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,qBAAqB;IAuBlF;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAS5C;;;OAGG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAoBlD;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,aAAa,GAAG,WAAW,GAAG,gBAAgB,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAiEpH;;OAEG;IACH,IAAI,IAAI,YAAY,EAAE;IAItB;;OAEG;IACH,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAKpC;;OAEG;IACG,gBAAgB,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA0EzE,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,cAAc;CAQvB"}
@@ -15,6 +15,7 @@ import fs from 'node:fs';
15
15
  import path from 'node:path';
16
16
  import { randomUUID, createHmac, createHash } from 'node:crypto';
17
17
  import { SafeFsExecutor } from './SafeFsExecutor.js';
18
+ import { decideFeedbackRetry, parseRetryAfterSeconds } from './feedbackBackoff.js';
18
19
  /** Maximum number of feedback items stored locally. */
19
20
  const MAX_FEEDBACK_ITEMS = 1000;
20
21
  /** Default salt for pseudonym generation when no shared secret is configured. */
@@ -25,6 +26,15 @@ export class FeedbackManager {
25
26
  version;
26
27
  /** Cache of agentName -> pseudonym for resolvePseudonym reverse lookups */
27
28
  pseudonymMap = new Map();
29
+ /**
30
+ * Webhook backoff state (L364). When the canonical feedback endpoint rate-limits
31
+ * us (429/503), we stop POSTing until `webhookNextRetryAtMs` and grow the wait
32
+ * with `webhookConsecutive429s`. In-memory by design: a restart re-probes once
33
+ * (one cycle) then re-backs-off — back-compatible and self-correcting. This is
34
+ * what stops `retryUnforwarded()` from re-POSTing the whole backlog every cycle.
35
+ */
36
+ webhookNextRetryAtMs = 0;
37
+ webhookConsecutive429s = 0;
28
38
  constructor(config) {
29
39
  if (config.webhookUrl) {
30
40
  FeedbackManager.validateWebhookUrl(config.webhookUrl);
@@ -138,8 +148,11 @@ export class FeedbackManager {
138
148
  submittedAt: new Date().toISOString(),
139
149
  forwarded: false,
140
150
  };
141
- // Forward to webhook if enabled (before persisting, so we know result)
142
- if (this.config.enabled && this.config.webhookUrl) {
151
+ // Forward to webhook if enabled (before persisting, so we know result).
152
+ // Skip the POST entirely while we're in a rate-limit backoff window (L364):
153
+ // hammering a 429-ing endpoint only makes it worse. The local record is still
154
+ // written below, so retryUnforwarded() will pick it up once the window passes.
155
+ if (this.config.enabled && this.config.webhookUrl && Date.now() >= this.webhookNextRetryAtMs) {
143
156
  try {
144
157
  const payload = {
145
158
  feedbackId: feedback.id,
@@ -161,12 +174,21 @@ export class FeedbackManager {
161
174
  body,
162
175
  signal: AbortSignal.timeout(10000), // 10s timeout
163
176
  });
164
- if (response.ok) {
177
+ const decision = decideFeedbackRetry({
178
+ ok: response.ok,
179
+ status: typeof response.status === 'number' ? response.status : null,
180
+ retryAfterSec: parseRetryAfterSeconds(response.headers?.get?.('retry-after')),
181
+ nowMs: Date.now(),
182
+ consecutive429s: this.webhookConsecutive429s,
183
+ });
184
+ this.webhookNextRetryAtMs = decision.nextRetryAtMs;
185
+ this.webhookConsecutive429s = decision.consecutive429s;
186
+ if (decision.markForwarded) {
165
187
  feedback.forwarded = true;
166
188
  console.log(`[feedback] Forwarded to webhook`);
167
189
  }
168
190
  else {
169
- console.error(`[feedback] Webhook returned ${response.status}: ${response.statusText}`);
191
+ console.error(`[feedback] Webhook returned ${response.status}: ${response.statusText} — ${decision.reason}`);
170
192
  }
171
193
  }
172
194
  catch (err) {
@@ -200,8 +222,17 @@ export class FeedbackManager {
200
222
  if (!this.config.enabled || !this.config.webhookUrl || unforwarded.length === 0) {
201
223
  return { retried: 0, succeeded: 0 };
202
224
  }
225
+ // Respect an active rate-limit backoff window (L364): if the endpoint just
226
+ // 429'd us, do NOT re-POST the whole backlog this cycle — that is exactly the
227
+ // self-reinforcing storm this fixes (661 items × every cycle = thousands of 429s).
228
+ if (Date.now() < this.webhookNextRetryAtMs) {
229
+ return { retried: 0, succeeded: 0 };
230
+ }
203
231
  let succeeded = 0;
232
+ let attempted = 0;
204
233
  for (const item of unforwarded) {
234
+ attempted++;
235
+ let decisionBreak = false;
205
236
  try {
206
237
  const payload = {
207
238
  feedbackId: item.id,
@@ -222,19 +253,35 @@ export class FeedbackManager {
222
253
  body,
223
254
  signal: AbortSignal.timeout(10000),
224
255
  });
225
- if (response.ok) {
256
+ const decision = decideFeedbackRetry({
257
+ ok: response.ok,
258
+ status: typeof response.status === 'number' ? response.status : null,
259
+ retryAfterSec: parseRetryAfterSeconds(response.headers?.get?.('retry-after')),
260
+ nowMs: Date.now(),
261
+ consecutive429s: this.webhookConsecutive429s,
262
+ });
263
+ this.webhookNextRetryAtMs = decision.nextRetryAtMs;
264
+ this.webhookConsecutive429s = decision.consecutive429s;
265
+ if (decision.markForwarded) {
226
266
  item.forwarded = true;
227
267
  succeeded++;
228
268
  }
269
+ // Rate-limited → stop the batch NOW; the rest retry after the backoff window.
270
+ if (decision.breakBatch) {
271
+ console.error(`[feedback] retry batch halted after ${attempted}/${unforwarded.length}: ${decision.reason}`);
272
+ decisionBreak = true;
273
+ }
229
274
  }
230
275
  catch {
231
- // @silent-fallback-ok — retry on next attempt
276
+ // @silent-fallback-ok — network/timeout: retry on next cycle
232
277
  }
278
+ if (decisionBreak)
279
+ break;
233
280
  }
234
281
  if (succeeded > 0) {
235
282
  this.saveFeedback(items);
236
283
  }
237
- return { retried: unforwarded.length, succeeded };
284
+ return { retried: attempted, succeeded };
238
285
  }
239
286
  // ── Private helpers ──────────────────────────────────────────────
240
287
  loadFeedback() {
@@ -1 +1 @@
1
- {"version":3,"file":"FeedbackManager.js","sourceRoot":"","sources":["../../src/core/FeedbackManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FeedbackManager.js","sourceRoot":"","sources":["../../src/core/FeedbackManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Feedback webhook retry/backoff decision (L364 — No Unbounded Self-Reinforcing
3
+ * Loops; Responsible Resource).
4
+ *
5
+ * THE BUG THIS FIXES (observed live 2026-06-20, topic 13481): the agent had a
6
+ * backlog of 661 un-forwarded feedback items and a canonical feedback endpoint
7
+ * that was returning 429 (Too Many Requests). `retryUnforwarded()` looped the
8
+ * ENTIRE backlog every scheduled cycle, POSTing all 661, getting 429 on each,
9
+ * marking none forwarded — so the next cycle re-POSTed all 661 again, forever
10
+ * (2,384 429s and climbing). A loop hammering a rate-limited external endpoint
11
+ * with no backoff: bad-citizenship to the external service AND wasted local work
12
+ * that contributed to event-loop pressure.
13
+ *
14
+ * This pure decider answers, per webhook response, three questions:
15
+ * - markForwarded — did this item land (2xx)?
16
+ * - breakBatch — are we rate-limited (429/503)? Then STOP the rest of this
17
+ * batch immediately; sending more only makes the 429 worse.
18
+ * - nextRetryAtMs — don't touch the webhook again until this wall-clock ms
19
+ * (honors a Retry-After header, else exponential backoff,
20
+ * capped). The caller gates BOTH submit() and the next
21
+ * retry cycle on this.
22
+ *
23
+ * Pure + deterministic → fully unit-testable. SIGNAL-style: it decides cadence,
24
+ * it never blocks the local record (the local feedback store is always written).
25
+ */
26
+ export interface FeedbackRetryInputs {
27
+ /** `response.ok` — the success signal. Robust: every real fetch Response has it,
28
+ * and we never depend on a numeric status being present to decide "forwarded". */
29
+ ok: boolean;
30
+ /** HTTP status of the webhook POST, or null on a network/timeout error / absent.
31
+ * Used ONLY to classify a rate-limit (429/503) for backoff — never for success. */
32
+ status: number | null;
33
+ /** Parsed Retry-After header in seconds, if the server sent one (429/503). */
34
+ retryAfterSec?: number;
35
+ /** Wall clock now (ms). */
36
+ nowMs: number;
37
+ /** Consecutive rate-limit (429/503) responses seen so far (for the exp curve). */
38
+ consecutive429s: number;
39
+ /** Base backoff (ms) for the exponential schedule. Default caller: 60_000. */
40
+ baseBackoffMs?: number;
41
+ /** Cap on the backoff (ms). Default caller: 3_600_000 (1h). */
42
+ maxBackoffMs?: number;
43
+ }
44
+ export interface FeedbackRetryDecision {
45
+ /** The item forwarded successfully (2xx) → mark it forwarded. */
46
+ markForwarded: boolean;
47
+ /** Rate-limited → STOP this retry batch (do not hammer the remaining items). */
48
+ breakBatch: boolean;
49
+ /** Do not POST the webhook again until this wall-clock ms. 0 = no hold. */
50
+ nextRetryAtMs: number;
51
+ /** New consecutive-429 count for the caller to persist. */
52
+ consecutive429s: number;
53
+ reason: string;
54
+ }
55
+ export declare function decideFeedbackRetry(i: FeedbackRetryInputs): FeedbackRetryDecision;
56
+ /** Parse a Retry-After header value (delta-seconds form only) → seconds | undefined. */
57
+ export declare function parseRetryAfterSeconds(headerValue: string | null | undefined): number | undefined;
58
+ //# sourceMappingURL=feedbackBackoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedbackBackoff.d.ts","sourceRoot":"","sources":["../../src/core/feedbackBackoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,mBAAmB;IAClC;uFACmF;IACnF,EAAE,EAAE,OAAO,CAAC;IACZ;wFACoF;IACpF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,eAAe,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,iEAAiE;IACjE,aAAa,EAAE,OAAO,CAAC;IACvB,gFAAgF;IAChF,UAAU,EAAE,OAAO,CAAC;IACpB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,mBAAmB,GAAG,qBAAqB,CAgDjF;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAIjG"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Feedback webhook retry/backoff decision (L364 — No Unbounded Self-Reinforcing
3
+ * Loops; Responsible Resource).
4
+ *
5
+ * THE BUG THIS FIXES (observed live 2026-06-20, topic 13481): the agent had a
6
+ * backlog of 661 un-forwarded feedback items and a canonical feedback endpoint
7
+ * that was returning 429 (Too Many Requests). `retryUnforwarded()` looped the
8
+ * ENTIRE backlog every scheduled cycle, POSTing all 661, getting 429 on each,
9
+ * marking none forwarded — so the next cycle re-POSTed all 661 again, forever
10
+ * (2,384 429s and climbing). A loop hammering a rate-limited external endpoint
11
+ * with no backoff: bad-citizenship to the external service AND wasted local work
12
+ * that contributed to event-loop pressure.
13
+ *
14
+ * This pure decider answers, per webhook response, three questions:
15
+ * - markForwarded — did this item land (2xx)?
16
+ * - breakBatch — are we rate-limited (429/503)? Then STOP the rest of this
17
+ * batch immediately; sending more only makes the 429 worse.
18
+ * - nextRetryAtMs — don't touch the webhook again until this wall-clock ms
19
+ * (honors a Retry-After header, else exponential backoff,
20
+ * capped). The caller gates BOTH submit() and the next
21
+ * retry cycle on this.
22
+ *
23
+ * Pure + deterministic → fully unit-testable. SIGNAL-style: it decides cadence,
24
+ * it never blocks the local record (the local feedback store is always written).
25
+ */
26
+ const RATE_LIMIT_STATUSES = new Set([429, 503]);
27
+ export function decideFeedbackRetry(i) {
28
+ const base = i.baseBackoffMs ?? 60_000;
29
+ const cap = i.maxBackoffMs ?? 3_600_000;
30
+ // Success → forwarded, clear any backoff. Driven by response.ok (always present),
31
+ // NOT by a numeric status, so it is robust to any response shape.
32
+ if (i.ok) {
33
+ return {
34
+ markForwarded: true,
35
+ breakBatch: false,
36
+ nextRetryAtMs: 0,
37
+ consecutive429s: 0,
38
+ reason: `forwarded${i.status !== null ? ` (${i.status})` : ''}`,
39
+ };
40
+ }
41
+ // Rate-limited (429) or service-unavailable (503) → back off AND halt the batch.
42
+ if (i.status !== null && RATE_LIMIT_STATUSES.has(i.status)) {
43
+ const n = i.consecutive429s + 1;
44
+ let waitMs;
45
+ if (i.retryAfterSec !== undefined && Number.isFinite(i.retryAfterSec) && i.retryAfterSec > 0) {
46
+ waitMs = Math.min(i.retryAfterSec * 1000, cap);
47
+ }
48
+ else {
49
+ // Exponential from base: base, 2×base, 4×base, … capped.
50
+ waitMs = Math.min(base * 2 ** (n - 1), cap);
51
+ }
52
+ return {
53
+ markForwarded: false,
54
+ breakBatch: true,
55
+ nextRetryAtMs: i.nowMs + waitMs,
56
+ consecutive429s: n,
57
+ reason: `rate-limited (${i.status}) — backing off ${Math.round(waitMs / 1000)}s, batch halted`,
58
+ };
59
+ }
60
+ // Any other non-2xx, or a network/timeout error: leave the item un-forwarded so
61
+ // it retries on the next cycle (today's behavior), but do NOT halt the batch —
62
+ // a per-item error is not a pool-wide rate-limit. PRESERVE the 429 streak (do not
63
+ // reset it): an endpoint flapping between 429 and 500 must keep climbing the
64
+ // exponential curve, not restart it at base on every interleaved 500. Only a
65
+ // genuine 2xx success (above) clears the streak.
66
+ return {
67
+ markForwarded: false,
68
+ breakBatch: false,
69
+ nextRetryAtMs: 0,
70
+ consecutive429s: i.consecutive429s,
71
+ reason: i.status === null ? 'network/timeout error — retry next cycle' : `error ${i.status} — retry next cycle`,
72
+ };
73
+ }
74
+ /** Parse a Retry-After header value (delta-seconds form only) → seconds | undefined. */
75
+ export function parseRetryAfterSeconds(headerValue) {
76
+ if (!headerValue)
77
+ return undefined;
78
+ const n = Number(headerValue.trim());
79
+ return Number.isFinite(n) && n >= 0 ? n : undefined;
80
+ }
81
+ //# sourceMappingURL=feedbackBackoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedbackBackoff.js","sourceRoot":"","sources":["../../src/core/feedbackBackoff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAiCH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAEhD,MAAM,UAAU,mBAAmB,CAAC,CAAsB;IACxD,MAAM,IAAI,GAAG,CAAC,CAAC,aAAa,IAAI,MAAM,CAAC;IACvC,MAAM,GAAG,GAAG,CAAC,CAAC,YAAY,IAAI,SAAS,CAAC;IAExC,kFAAkF;IAClF,kEAAkE;IAClE,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;QACT,OAAO;YACL,aAAa,EAAE,IAAI;YACnB,UAAU,EAAE,KAAK;YACjB,aAAa,EAAE,CAAC;YAChB,eAAe,EAAE,CAAC;YAClB,MAAM,EAAE,YAAY,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;SAChE,CAAC;IACJ,CAAC;IAED,iFAAiF;IACjF,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,eAAe,GAAG,CAAC,CAAC;QAChC,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC,CAAC,aAAa,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YAC7F,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,yDAAyD;YACzD,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO;YACL,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,IAAI;YAChB,aAAa,EAAE,CAAC,CAAC,KAAK,GAAG,MAAM;YAC/B,eAAe,EAAE,CAAC;YAClB,MAAM,EAAE,iBAAiB,CAAC,CAAC,MAAM,mBAAmB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,iBAAiB;SAC/F,CAAC;IACJ,CAAC;IAED,gFAAgF;IAChF,+EAA+E;IAC/E,kFAAkF;IAClF,6EAA6E;IAC7E,6EAA6E;IAC7E,iDAAiD;IACjD,OAAO;QACL,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,CAAC;QAChB,eAAe,EAAE,CAAC,CAAC,eAAe;QAClC,MAAM,EAAE,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,qBAAqB;KAChH,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,sBAAsB,CAAC,WAAsC;IAC3E,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAC;IACnC,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.632",
3
+ "version": "1.3.633",
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-06-20T18:23:55.492Z",
5
- "instarVersion": "1.3.632",
4
+ "generatedAt": "2026-06-20T22:29:33.870Z",
5
+ "instarVersion": "1.3.633",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,37 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ `FeedbackManager` now treats a `429`/`503` from the canonical feedback endpoint as a
9
+ stop-signal: it HALTS the current retry batch and waits (honoring `Retry-After`, else
10
+ exponential 60s→1h) before POSTing again. Previously `retryUnforwarded()` re-POSTed the
11
+ ENTIRE un-forwarded backlog every scheduled cycle regardless of rate-limiting — against
12
+ a 429-ing endpoint that re-sent the whole backlog forever (observed live: 661 backlog
13
+ items → 2,384+ failed POSTs). A pure `decideFeedbackRetry()` helper makes the cadence
14
+ decision; the local feedback record is always written (nothing is lost or dropped).
15
+
16
+ ## What to Tell Your User
17
+
18
+ If your agent had been quietly retrying feedback against a busy endpoint, it now backs
19
+ off politely instead of hammering it — fewer wasted network calls and less background
20
+ churn. Nothing you do changes; no feedback is lost (notes are still saved locally and
21
+ sent once the endpoint is ready).
22
+
23
+ ## Summary of New Capabilities
24
+
25
+ - Rate-limit-aware feedback forwarding: halts on 429/503, honors `Retry-After`, backs
26
+ off exponentially (capped), and never re-sends the whole backlog against a limited
27
+ endpoint. Back-compatible on a healthy endpoint (forwards immediately as before).
28
+
29
+ ## Evidence
30
+
31
+ - New `tests/unit/feedbackBackoff.test.ts` (11 cases): 2xx clears backoff; 429/503 halt
32
+ + exponential backoff capped at 1h; `Retry-After` honored + capped; non-429 errors
33
+ retry-next-cycle and PRESERVE the 429 streak (flap protection); junk/negative
34
+ `Retry-After` rejected.
35
+ - `tests/unit/FeedbackManager.test.ts` (+2 cases): a 429 halts the batch after ONE POST
36
+ (not the whole backlog) and the next cycle POSTs zero times while backed off; no item
37
+ lost. Independent second-pass review concurred.
@@ -0,0 +1,47 @@
1
+ # Feedback retry storm fix — in plain terms
2
+
3
+ ## What this is
4
+
5
+ Your agent has a little "phone home" feature: when something noteworthy happens, it
6
+ saves a feedback note locally and tries to send a copy to a central feedback inbox
7
+ over the internet. A background job periodically retries any notes that haven't been
8
+ sent yet.
9
+
10
+ ## What was broken
11
+
12
+ The central inbox started replying "429 — too many requests" (it was rate-limiting
13
+ us). The retry job didn't understand "429" as "slow down." It just kept re-sending
14
+ the **entire** backlog of unsent notes — 661 of them — every single cycle. Each one
15
+ got a 429, none were marked as sent, so the next cycle tried all 661 again. Over time
16
+ that piled up to **2,384+ failed sends**, and the repeated bursts of work were one of
17
+ the things briefly freezing the agent's main loop (which, knock-on, made the two
18
+ machines' clocks look out of sync and broke their handshake — the very problem the
19
+ larger project is fixing).
20
+
21
+ ## What's new
22
+
23
+ The retry now reads the inbox's reply and reacts like a polite client:
24
+ - If a note sends fine, it's marked done.
25
+ - If the inbox says "429 / try later," the agent **stops the batch immediately**
26
+ (no point hammering a server that's asking us to back off) and **waits** before
27
+ trying again. If the server says exactly how long to wait, it obeys that; otherwise
28
+ it waits a minute, then two, then four… up to an hour, then settles there.
29
+ - New notes submitted during a backoff are still saved locally and just wait their
30
+ turn — nothing is lost.
31
+
32
+ ## The safeguards
33
+
34
+ - **Nothing is dropped.** Every note is still stored locally; backoff only delays
35
+ *sending*, never *recording*.
36
+ - **Self-correcting.** The backoff lives in memory; after a restart it tries once and
37
+ re-learns the backoff — no stuck state.
38
+ - **Back-compatible.** When the inbox is healthy, behavior is identical to before
39
+ (send immediately, never wait).
40
+ - **Reversible.** It's two files; reverting restores the old behavior exactly.
41
+
42
+ ## What you need to decide
43
+
44
+ Nothing — it's a contained, reversible fix that only makes the agent a better
45
+ internet citizen and stops wasted work. The only judgment call baked in: we treat the
46
+ two standard "slow down" replies (429 and 503) as stop-signals, and treat other
47
+ errors as one-off retries — matching how the wider web expects clients to behave.
@@ -0,0 +1,71 @@
1
+ # Side-Effects Review — Feedback webhook 429 backoff (stop the retry storm)
2
+
3
+ **Tier:** 1 (contained fix to one manager + a pure helper).
4
+ **Files:** `src/core/feedbackBackoff.ts` (new pure helper), `src/core/FeedbackManager.ts` (wiring), `tests/unit/feedbackBackoff.test.ts`, `tests/unit/FeedbackManager.test.ts`.
5
+
6
+ ## What changed
7
+
8
+ `FeedbackManager.retryUnforwarded()` previously looped the ENTIRE un-forwarded
9
+ backlog every scheduled cycle, POSTing each item; on a non-2xx it simply left the
10
+ item un-forwarded — so against a 429-ing endpoint it re-POSTed the whole backlog
11
+ forever (observed live 2026-06-20, topic 13481: 661 un-forwarded items, 2,384+ 429s).
12
+
13
+ Now a pure `decideFeedbackRetry()` classifies each webhook response:
14
+ - 2xx → mark forwarded, clear backoff.
15
+ - **429/503 → HALT the batch immediately** and set a backoff window (`Retry-After`
16
+ if present, else exponential from 60s, capped at 1h).
17
+ - other non-2xx / network error → leave un-forwarded, retry next cycle (unchanged),
18
+ no batch halt.
19
+
20
+ `submit()` and `retryUnforwarded()` both skip the webhook entirely while inside the
21
+ backoff window. State (`webhookNextRetryAtMs`, `webhookConsecutive429s`) is in-memory.
22
+
23
+ ## The 8 questions
24
+
25
+ 1. **Over-block.** While backed off, `submit()` skips the live POST and the item is
26
+ stored locally un-forwarded (picked up by the next allowed retry cycle). No
27
+ feedback is lost — only deferred. The local store is always written, exactly as
28
+ before. Worst case: a feedback item is forwarded minutes later instead of
29
+ instantly, during an active rate-limit — acceptable and correct.
30
+ 2. **Under-block.** A non-429/503 error (e.g. a one-off 500) does NOT halt the batch
31
+ — by design, since it is a per-item issue, not a pool-wide rate-limit. If an
32
+ endpoint signalled overload with a bare 500 (not 503/429) the storm guard would
33
+ not engage; this is the documented trade (we only treat the standard rate-limit
34
+ statuses as "stop"). The exponential cap still bounds total backoff growth.
35
+ 3. **Level-of-abstraction fit.** Correct layer: the decision is a pure helper; the
36
+ FeedbackManager owns the I/O and the (in-memory) backoff state. No new subsystem.
37
+ 4. **Signal vs authority.** It governs the webhook POST cadence only. It NEVER blocks
38
+ the local feedback record (always written) and never gates anything else. It is
39
+ the "Responsible Resource" / L364 (No Unbounded Self-Reinforcing Loops) standard
40
+ made real for this loop.
41
+ 5. **Interactions.** No shadowing. The scheduled `feedback-retry` job still drives
42
+ `retryUnforwarded()`; this only changes what one cycle does (halt-on-429 instead
43
+ of POST-all). The `feedback-factory` receiver/processor are unaffected (different
44
+ path). In-memory state means a server restart re-probes once then re-backs-off —
45
+ self-correcting, no persistence coupling.
46
+ 6. **External surfaces.** This DECREASES external load (fewer POSTs to the canonical
47
+ feedback endpoint) — strictly better citizenship. No new external call. Honors the
48
+ server's `Retry-After` when provided.
49
+ 7. **Multi-machine posture.** Machine-local BY DESIGN: each machine forwards its own
50
+ local feedback store and keeps its own in-memory backoff. There is no shared state
51
+ to replicate (the backoff is about THIS machine's POST cadence to the endpoint).
52
+ No topic-transfer or URL-survival concern (no user-facing surface).
53
+ 8. **Rollback cost.** Trivial: revert the two files. No migration, no persisted state,
54
+ no config. Back-compatible — on a healthy (2xx) endpoint behavior is identical to
55
+ before (forward immediately, no backoff ever set).
56
+
57
+ ## Second-pass
58
+
59
+ Requested (retry/recovery loop with external side-effects).
60
+
61
+ **Reviewer verdict (independent): Concur with the review.** Confirmed: (1) stop-after-
62
+ first-429 is correct (`breakBatch`→`break` before any further POST); (2) next-cycle
63
+ gating is symmetric (submit `>= nextRetryAtMs`, retry early-returns on `<`); (3) no
64
+ item loss (un-forwarded items stay persisted+retryable, success-only save is safe);
65
+ (4) no stuck-forever (a 2xx always returns `nextRetryAtMs:0`+`consecutive429s:0`).
66
+ Two non-blocking notes: (a) the load→fetch→full-overwrite race in `retryUnforwarded()`
67
+ is **pre-existing** (`appendFeedback` already read-modify-writes) and untouched here —
68
+ not a regression; (b) a non-429 error mid-recovery reset the 429 streak, softening the
69
+ curve on a flapping endpoint. **Note (b) addressed in code**: the helper now PRESERVES
70
+ `consecutive429s` on a non-429 error and clears it only on a genuine 2xx, with a
71
+ flap-protection test. Note (a) is logged as a separate pre-existing item, out of scope.