instar 1.3.631 → 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/dashboard/subscriptions.js +8 -3
- 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.632.md +31 -0
- 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
- package/upgrades/side-effects/matrix-needs-signin-button.md +70 -0
|
@@ -457,13 +457,18 @@ export function renderAccountMatrix(doc, target, poolScope, pendingScope, transi
|
|
|
457
457
|
tr.appendChild(el(doc, 'th', 'sub-matrix-acct', sanitizeForDisplay(row.account.email, 'label')));
|
|
458
458
|
for (const c of row.cells) {
|
|
459
459
|
const td = el(doc, 'td', `sub-matrix-cell sub-matrix-${c.state}`);
|
|
460
|
-
if (c.state === 'empty' || c.state === 'held' || c.state === 'cant-resolve') {
|
|
461
|
-
// An actionable cell → a
|
|
462
|
-
|
|
460
|
+
if (c.state === 'empty' || c.state === 'needs-reauth' || c.state === 'held' || c.state === 'cant-resolve') {
|
|
461
|
+
// An actionable cell → a button that runs the SAME in-dashboard sign-in flow (PIN → link →
|
|
462
|
+
// paste code). empty → "Set up"; needs-reauth (an existing account whose login expired) →
|
|
463
|
+
// "Sign in"; held/cant-resolve → "Retry". A needs-reauth account already resolves to its
|
|
464
|
+
// email, so the start-cell orchestrator drives a real re-auth — never a cosmetic button.
|
|
465
|
+
const label = c.state === 'empty' ? 'Set up' : (c.state === 'needs-reauth' ? 'Sign in' : 'Retry');
|
|
466
|
+
const btn = el(doc, 'button', 'sub-matrix-setup', label);
|
|
463
467
|
btn.setAttribute('data-matrix-setup', '1');
|
|
464
468
|
btn.setAttribute('data-account-id', sanitizeForDisplay(c.accountId, 'label'));
|
|
465
469
|
btn.setAttribute('data-machine-id', sanitizeForDisplay(c.machineId, 'label'));
|
|
466
470
|
if (c.state !== 'empty') {
|
|
471
|
+
// Show the status word ("⟳ Needs sign-in" / "⚠ Didn't match…") ABOVE the button.
|
|
467
472
|
td.appendChild(el(doc, 'div', 'sub-matrix-glyph', `${MATRIX_CELL_GLYPH[c.state]} ${MATRIX_CELL_WORD[c.state]}`));
|
|
468
473
|
}
|
|
469
474
|
td.appendChild(btn);
|
|
@@ -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":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnF,uDAAuD;AACvD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,iFAAiF;AACjF,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAOrD,MAAM,OAAO,eAAe;IAClB,MAAM,CAAiB;IACvB,YAAY,CAAS;IACrB,OAAO,CAAS;IACxB,2EAA2E;IACnE,YAAY,GAAwB,IAAI,GAAG,EAAE,CAAC;IACtD;;;;;;OAMG;IACK,oBAAoB,GAAG,CAAC,CAAC;IACzB,sBAAsB,GAAG,CAAC,CAAC;IAEnC,YAAY,MAAsB;QAChC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;YACtB,eAAe,CAAC,kBAAkB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;QACxC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC;IAC3C,CAAC;IAED,wEAAwE;IAChE,iBAAiB,CAAC,IAAY;QACpC,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;YAClC,YAAY,EAAE,UAAU,IAAI,CAAC,OAAO,UAAU,OAAO,CAAC,OAAO,GAAG;YAChE,kBAAkB,EAAE,IAAI,CAAC,OAAO;SACjC,CAAC;QAEF,qDAAqD;QACrD,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;iBAC7D,MAAM,CAAC,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;iBAC9B,MAAM,CAAC,KAAK,CAAC,CAAC;YACjB,OAAO,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAC;YAC1C,OAAO,CAAC,oBAAoB,CAAC,GAAG,SAAS,CAAC;QAC5C,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,4EAA4E;IACpE,MAAM,CAAC,kBAAkB,CAAC,GAAW;QAC3C,IAAI,MAAW,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,SAAS;YACpF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAChF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,uBAAuB,CAAC,KAAa,EAAE,WAAmB;QACxD,oCAAoC;QACpC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,2CAA2C,EAAE,CAAC;QAC/E,CAAC;QAED,yFAAyF;QACzF,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,iEAAiE,EAAE,CAAC;QACrG,CAAC;QAED,mDAAmD;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9C,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACnD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,eAAe,CAAC,CAAC;QACvF,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,gDAAgD,EAAE,CAAC;QACpF,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,SAAiB;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,sBAAsB,CAAC;QAClE,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,SAAS,GAAG,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;QAC/C,wCAAwC;QACxC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC5C,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,SAAiB;QAChC,8BAA8B;QAC9B,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;QAC3C,CAAC;QAED,qCAAqC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBACzD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;oBAC5B,OAAO,IAAI,CAAC,SAAS,CAAC;gBACxB,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,IAA+E;QAC1F,MAAM,cAAc,GAAG,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAE9D,MAAM,QAAQ,GAAiB;YAC7B,GAAG,IAAI;YACP,EAAE,EAAE,MAAM,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;YACrC,cAAc;YACd,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,SAAS,EAAE,KAAK;SACjB,CAAC;QAEF,wEAAwE;QACxE,4EAA4E;QAC5E,8EAA8E;QAC9E,+EAA+E;QAC/E,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC7F,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG;oBACd,UAAU,EAAE,QAAQ,CAAC,EAAE;oBACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;oBACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;oBACrB,WAAW,EAAE,QAAQ,CAAC,WAAW;oBACjC,SAAS,EAAE,QAAQ,CAAC,SAAS;oBAC7B,cAAc;oBACd,aAAa,EAAE,IAAI,CAAC,OAAO;oBAC3B,WAAW,EAAE,OAAO,CAAC,OAAO;oBAC5B,EAAE,EAAE,QAAQ,CAAC,EAAE;oBACf,OAAO,EAAE,QAAQ,CAAC,OAAO;oBACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;iBAClC,CAAC;gBACF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;oBACnD,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;oBACrC,IAAI;oBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,cAAc;iBACnD,CAAC,CAAC;gBAEH,MAAM,QAAQ,GAAG,mBAAmB,CAAC;oBACnC,EAAE,EAAE,QAAQ,CAAC,EAAE;oBACf,MAAM,EAAE,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;oBACpE,aAAa,EAAE,sBAAsB,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;oBAC7E,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE;oBACjB,eAAe,EAAE,IAAI,CAAC,sBAAsB;iBAC7C,CAAC,CAAC;gBACH,IAAI,CAAC,oBAAoB,GAAG,QAAQ,CAAC,aAAa,CAAC;gBACnD,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,eAAe,CAAC;gBACvD,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;oBAC3B,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC;oBAC1B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;gBACjD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,+BAA+B,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC/G,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,iEAAiE;gBACjE,OAAO,CAAC,KAAK,CAAC,8BAA8B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClG,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;QAE9B,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,EAAU;QACZ,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChF,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QACtC,CAAC;QAED,2EAA2E;QAC3E,8EAA8E;QAC9E,mFAAmF;QACnF,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC3C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;QACtC,CAAC;QAED,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;YAC/B,SAAS,EAAE,CAAC;YACZ,IAAI,aAAa,GAAG,KAAK,CAAC;YAC1B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG;oBACd,UAAU,EAAE,IAAI,CAAC,EAAE;oBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,SAAS,EAAE,IAAI,CAAC,SAAS;oBACzB,aAAa,EAAE,IAAI,CAAC,OAAO;oBAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,WAAW,EAAE,IAAI,CAAC,WAAW;iBAC9B,CAAC;gBACF,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;oBACnD,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC;oBACrC,IAAI;oBACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;iBACnC,CAAC,CAAC;gBAEH,MAAM,QAAQ,GAAG,mBAAmB,CAAC;oBACnC,EAAE,EAAE,QAAQ,CAAC,EAAE;oBACf,MAAM,EAAE,OAAO,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;oBACpE,aAAa,EAAE,sBAAsB,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;oBAC7E,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE;oBACjB,eAAe,EAAE,IAAI,CAAC,sBAAsB;iBAC7C,CAAC,CAAC;gBACH,IAAI,CAAC,oBAAoB,GAAG,QAAQ,CAAC,aAAa,CAAC;gBACnD,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,eAAe,CAAC;gBACvD,IAAI,QAAQ,CAAC,aAAa,EAAE,CAAC;oBAC3B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;oBACtB,SAAS,EAAE,CAAC;gBACd,CAAC;gBACD,8EAA8E;gBAC9E,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;oBACxB,OAAO,CAAC,KAAK,CAAC,uCAAuC,SAAS,IAAI,WAAW,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;oBAC5G,aAAa,GAAG,IAAI,CAAC;gBACvB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,6DAA6D;YAC/D,CAAC;YACD,IAAI,aAAa;gBAAE,MAAM;QAC3B,CAAC;QAED,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;IAC3C,CAAC;IAED,oEAAoE;IAE5D,YAAY;QAClB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC;YAAE,OAAO,EAAE,CAAC;QACjD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,KAAqB;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,oEAAoE;QACpE,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;QACjG,IAAI,CAAC;YACH,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YAC1D,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC;gBAAC,cAAc,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,iCAAiC,EAAE,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;YACxH,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,IAAkB;QACvC,IAAI,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,sDAAsD;QACtD,IAAI,KAAK,CAAC,MAAM,GAAG,kBAAkB,EAAE,CAAC;YACtC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAC3C,CAAC;QACD,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAEO,cAAc,CAAC,OAAqB;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC;YACrB,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -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,31 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The Subscriptions dashboard's account × machine matrix had a dead-end. A cell whose login had expired showed only the grey text "⟳ Needs sign-in" with **no button to act on** — so you could see an account needed re-authentication but had no way to do anything about it from the dashboard. Every other cell-state was already actionable: an empty cell gets a "Set up" button, a failed cell gets a "Retry" button. The `needs-reauth` state was simply left out of the branch that renders a button and fell through to the "just draw text" path.
|
|
9
|
+
|
|
10
|
+
This fix moves `needs-reauth` into the actionable branch in `dashboard/subscriptions.js`. The cell now shows the status word "⟳ Needs sign-in" **and** a "Sign in" button directly below it. The button carries the same `(account, machine)` ids as the "Set up" button and runs the exact same in-dashboard flow (PIN → provider sign-in link → paste code). Because a needs-sign-in account already resolves to its email, the `start-cell` orchestrator drives a genuine re-authentication — the button is real, not cosmetic. No server route, authority, or data model changed; the PIN gate on starting a login is untouched.
|
|
11
|
+
|
|
12
|
+
## What to Tell Your User
|
|
13
|
+
|
|
14
|
+
If you saw an account in your Subscriptions grid marked "Needs sign-in" with no way to fix it, that's now a one-tap action. The cell shows "Needs sign-in" with a **Sign in** button right below — tap it, enter your PIN, open the sign-in link, and paste the code back, exactly like setting up a new account. Everything stays inside the dashboard; nothing changed about who's allowed to start a login.
|
|
15
|
+
|
|
16
|
+
## Summary of New Capabilities
|
|
17
|
+
|
|
18
|
+
- The account × machine matrix's "Needs sign-in" cell is now actionable: it renders the status word **plus a "Sign in" button** that runs the existing in-dashboard re-authentication flow (PIN → link → paste code).
|
|
19
|
+
- The button works for an account whose login expired on this machine OR on a peer machine — it rides the same PIN-gated, mesh-delivered `start-cell` path the "Set up" button already uses.
|
|
20
|
+
- No change to authorization: starting a login still requires the operator's dashboard PIN.
|
|
21
|
+
|
|
22
|
+
## Evidence
|
|
23
|
+
|
|
24
|
+
- New regression unit test in `tests/unit/subscriptions-render.test.ts`: asserts a `needs-reauth` cell renders the "Needs sign-in" word AND a `.sub-matrix-setup` "Sign in" button wired to the start-cell flow (`data-matrix-setup`, correct account/machine ids). 34/34 in that file pass.
|
|
25
|
+
- Related front-end tests green: `follow-me-controller-wiring.test.ts` (8) and `account-follow-me-locally-executable.test.ts` (9) — confirms the existing tap-handler/flow this button re-uses is unchanged.
|
|
26
|
+
- Traced root cause directly in `renderAccountMatrix`: `needs-reauth` was absent from the actionable-cell branch condition; the server `start-cell` route resolves an existing account's email and drives a real re-auth, so the new button is functional.
|
|
27
|
+
- Side-effects review: `upgrades/side-effects/matrix-needs-signin-button.md` (no block/allow surface; no new authority; machine-local render of an existing pool-scope flow). Tier 1.
|
|
28
|
+
|
|
29
|
+
## ELI16
|
|
30
|
+
|
|
31
|
+
The Subscriptions screen has a grid showing which account is signed in on which machine. Empty squares had a "Set up" button you could tap. But a square for an account whose login had run out just said "Needs sign-in" in grey — with no button. So you could see the problem but couldn't fix it from the screen. Turns out the code that decides "should this square have a button?" simply forgot to include the "needs sign-in" case, so it drew plain text instead. This fix adds the button: the square now says "Needs sign-in" with a "Sign in" button right under it, and tapping it runs the same sign-in steps as setting up a new account (enter your PIN, open the link, paste the code). It actually signs the account back in — it's not a fake button — and it works whether the account expired on this machine or another one.
|
|
@@ -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.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Side-Effects Review — Account matrix "Needs sign-in" → actionable Sign-in button
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `matrix-needs-signin-button`
|
|
4
|
+
**Date:** `2026-06-20`
|
|
5
|
+
**Author:** `Instar Agent (echo)`
|
|
6
|
+
**Second-pass reviewer:** `not required (no block/allow surface, no lifecycle/gate/sentinel)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The account × machine matrix in the Subscriptions dashboard had a cell-state, `needs-reauth` ("Needs sign-in"), that rendered as static text with no actionable control — a dead-end. This change (one branch condition + a button label in `dashboard/subscriptions.js`, plus one unit test in `tests/unit/subscriptions-render.test.ts`) moves `needs-reauth` into the actionable rendering branch so it draws the status word "⟳ Needs sign-in" AND a "Sign in" button directly below it. The button carries the same `data-matrix-setup` / `data-account-id` / `data-machine-id` attributes the empty-cell "Set up" button does, so it routes through the EXISTING, unchanged PIN-gated `start-cell` → sign-in-link → code-paste flow. No server route, authority, or data model is touched.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
This change touches NO decision point. It is presentation logic only: it decides which DOM (a button vs plain text) to render for an already-computed cell state. The authority that gates starting a login (the dashboard-PIN check on `POST /subscription-pool/matrix/start-cell`) is unchanged and continues to be the sole gate.
|
|
15
|
+
|
|
16
|
+
- `renderAccountMatrix` cell rendering (`dashboard/subscriptions.js`) — modify — adds `needs-reauth` to the set of cell-states that render an actionable button; pure view logic, no gating.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Over-block
|
|
21
|
+
|
|
22
|
+
No block/allow surface — over-block not applicable. The change ADDS an affordance; it rejects nothing.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 2. Under-block
|
|
27
|
+
|
|
28
|
+
No block/allow surface — under-block not applicable. The PIN gate on `start-cell` is unchanged, so this adds no new path that bypasses authorization: tapping "Sign in" still requires the operator's PIN to actually start a login, exactly as "Set up" does.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Level-of-abstraction fit
|
|
33
|
+
|
|
34
|
+
Correct layer. This is a view-rendering concern living in the dashboard front-end, exactly where the sibling "Set up"/"Retry" button logic already lives. It re-uses the existing `start-cell` orchestrator rather than re-implementing any email-resolution / mandate / login logic — it feeds the smart gate that already exists instead of running parallel to it.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 4. Signal vs authority compliance
|
|
39
|
+
|
|
40
|
+
Compliant. The change adds NO blocking authority and NO brittle decision logic. It renders a button that, when tapped, calls an existing PIN-gated authority (`start-cell`). The button itself holds no authority; the server endpoint remains the single authority and is untouched.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 5. Interactions
|
|
45
|
+
|
|
46
|
+
- The new button uses the SAME delegated tap handler (`wireMatrixSetup` → `onSetupTap` → `onConfirmTap` → `start-cell`) as the empty-cell "Set up" button, so it cannot double-fire or shadow another handler — it is the same code path keyed on `data-matrix-setup`.
|
|
47
|
+
- `start-cell` already handles an existing account: it resolves the account email from the accountId (`resolveFollowMeEnrollTarget`) and has self-target idempotency that reuses an in-flight pending login. A needs-reauth account resolves to its email, so the flow drives a real re-auth and does not mint a duplicate when one is already pending.
|
|
48
|
+
- No race with adjacent cleanup: the cell re-renders from durable state each poll; an in-progress login transitions the cell to the in-progress (◷) state with its Cancel button, exactly as a "Set up"-initiated login does.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 6. External surfaces
|
|
53
|
+
|
|
54
|
+
The only external surface is the dashboard UI: a `needs-reauth` cell now shows a "Sign in" button. No change to any API response, agent-to-agent surface, or other system. No new timing/conversation-state dependency — rendering is a pure function of the already-fetched pool/pending state.
|
|
55
|
+
|
|
56
|
+
### 6b. Operator-surface quality
|
|
57
|
+
|
|
58
|
+
This change EXISTS to improve operator-surface quality: it converts a non-actionable status into a one-tap action, matching the operator's directive that everything be actionable from the dashboard. The button label ("Sign in") matches the flow's existing vocabulary; the status word remains visible so the operator still understands WHY the action is offered.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
63
|
+
|
|
64
|
+
Machine-local rendering of a pool-scope read, BY DESIGN. The matrix already reads `scope=pool` (peers merged) and the `start-cell` flow already delivers the mandate over the mesh for a peer-target cell. A needs-reauth cell on a PEER machine (e.g. the account expired on the Laptop while the Mini fronts the dashboard) routes its "Sign in" through the same proven cross-machine `start-cell` → peer enroll/start path the "Set up" button uses. No new replication or per-machine state is introduced; the change rides the existing cross-machine plumbing.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 8. Rollback cost
|
|
69
|
+
|
|
70
|
+
Trivial. Revert the single commit (one branch condition + label + one test) — the cell returns to showing static "Needs sign-in" text. No data migration, no agent-state repair, no release coordination. Dashboard files ship static (no compiled artifact), so a revert is immediately effective on next deploy.
|