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.
- package/dist/core/FeedbackManager.d.ts +9 -0
- package/dist/core/FeedbackManager.d.ts.map +1 -1
- package/dist/core/FeedbackManager.js +54 -7
- package/dist/core/FeedbackManager.js.map +1 -1
- package/dist/core/feedbackBackoff.d.ts +58 -0
- package/dist/core/feedbackBackoff.d.ts.map +1 -0
- package/dist/core/feedbackBackoff.js +81 -0
- package/dist/core/feedbackBackoff.js.map +1 -0
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.633.md +37 -0
- package/upgrades/eli16/feedback-429-backoff.eli16.md +47 -0
- package/upgrades/side-effects/feedback-429-backoff.md +71 -0
|
@@ -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;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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,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-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.
|