instar 1.3.813 → 1.3.815

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.
@@ -41,21 +41,22 @@ export const GLANCE_MAX_TOKEN_LEN = 40; // a longer token is a glued-word budget
41
41
  // (same discipline as the F3 purpose-line exempt list). The completeness test
42
42
  // asserts adopted ∪ grandfathered == every TAB_REGISTRY id, so a NEW tab in NEITHER
43
43
  // set fails the build; the monotonicity test asserts the grandfather size ≤ ceiling.
44
- export const GLANCE_ADOPTED_TABS = ['commitments'];
44
+ export const GLANCE_ADOPTED_TABS = ['commitments', 'blockers'];
45
45
 
46
46
  export const GLANCE_GRANDFATHERED = [
47
47
  'insights', 'sessions', 'files', 'dropzone', 'jobs', 'features', 'systems',
48
48
  'integrated-being', 'pr-pipeline', 'projects', 'initiatives', 'tokens',
49
49
  'resources', 'llm-activity', 'routing-map', 'spend', 'threadline', 'evidence',
50
50
  'process-health', 'subscriptions', 'preferences-learning', 'machines', 'mandates',
51
- 'blockers', 'secrets',
52
- ];
51
+ 'secrets',
52
+ ]; // 'blockers' left the list this PR (Phase 2) — it now builds through this component.
53
53
 
54
54
  // The committed ceiling on grandfathered-tab count. Only ever LOWER this (each
55
55
  // lowering marks a tab retrofitted onto the floor). Never raise it without an
56
56
  // operator-signed justification — raising it is how a NEW tab would silently ship
57
57
  // below the floor, the exact regression the ratchet exists to prevent.
58
- export const GLANCE_GRANDFATHERED_CEILING = 25;
58
+ // Lowered 25 24 (Phase 2): Blockers retrofitted onto the glance floor.
59
+ export const GLANCE_GRANDFATHERED_CEILING = 24;
59
60
 
60
61
  // ── F10 — insider-vocab detection ────────────────────────────────────────────
61
62
  // A readability floor, NOT a secret-redaction boundary (secret handling stays at
@@ -425,25 +426,40 @@ export function commitmentsOpenPopulation(commitments) {
425
426
 
426
427
  export function buildCommitmentsGlance(commitments, now = Date.now()) {
427
428
  const open = commitmentsOpenPopulation(commitments);
428
- const dueSoon = open.filter((c) => c.atRisk === true);
429
+ // OVERDUE TAKES PRECEDENCE over due-soon (issue #1435 §3): a promise whose HARD
430
+ // deadline is already in the past is OVERDUE, never merely "due soon". The old
431
+ // build classified due-soon purely from atRisk, so a stale beacon record a month
432
+ // past its hard deadline showed as "due soon" — the reported defect. Classify
433
+ // overdue FIRST, then take due-soon over the REMAINDER (atRisk but not overdue).
434
+ const overdue = open.filter((c) => c.hardDeadlineAt && Date.parse(c.hardDeadlineAt) < now);
435
+ const overdueSet = new Set(overdue);
436
+ const dueSoon = open.filter((c) => c.atRisk === true && !overdueSet.has(c));
429
437
  const waiting = open.filter((c) => c.blockedOn === 'user-input' || c.blockedOn === 'user-authorization');
430
438
  const quiet = open.filter((c) => c.beaconSuppressed === true);
431
- const overdue = open.filter((c) => c.hardDeadlineAt && Date.parse(c.hardDeadlineAt) < now);
432
439
 
433
440
  // Component-authored, jargon-free headline — honest to the one population.
441
+ // Count-aware verb agreement (#1435 §2): "1 needs" / "2 need", "1 is" / "2 are".
434
442
  let headline;
435
443
  if (open.length === 0) {
436
444
  headline = "You have no open promises right now.";
437
445
  } else {
438
- const soonClause = dueSoon.length > 0 ? `${dueSoon.length} need attention soon` : 'none need attention soon';
439
- const overdueClause = overdue.length > 0 ? `${overdue.length} overdue` : 'none overdue';
446
+ const soonClause = dueSoon.length === 0 ? 'none need attention soon'
447
+ : dueSoon.length === 1 ? '1 needs attention soon'
448
+ : `${dueSoon.length} need attention soon`;
449
+ const overdueClause = overdue.length === 0 ? 'none are overdue'
450
+ : overdue.length === 1 ? '1 is overdue'
451
+ : `${overdue.length} are overdue`;
440
452
  const noun = open.length === 1 ? 'open promise' : 'open promises';
441
453
  headline = `I'm carrying ${open.length} ${noun}; ${soonClause}, ${overdueClause}.`;
442
454
  }
443
455
 
456
+ // Every number the headline states now has a tile to drill into (#1435 §1): the
457
+ // "overdue" count gets its own OVERDUE tile — the most actionable state, so we add
458
+ // the tile rather than dropping the clause. Five tiles = the F10 max.
444
459
  const tiles = [
445
460
  { key: 'open', label: 'Open', value: String(open.length), tone: 'neutral', rows: open },
446
461
  { key: 'due-soon', label: 'Due soon', value: String(dueSoon.length), tone: dueSoon.length ? 'warn' : 'neutral', rows: dueSoon },
462
+ { key: 'overdue', label: 'Overdue', value: String(overdue.length), tone: overdue.length ? 'warn' : 'neutral', rows: overdue },
447
463
  { key: 'waiting', label: 'Waiting on you', value: String(waiting.length), tone: waiting.length ? 'warn' : 'neutral', rows: waiting },
448
464
  { key: 'quiet', label: 'Quiet', value: String(quiet.length), tone: 'muted', rows: quiet },
449
465
  ];
@@ -531,3 +547,140 @@ export function commitmentsGlanceSpec(doc, commitments, opts = {}) {
531
547
  }));
532
548
  return { headline: base.headline, tiles, population: base.population };
533
549
  }
550
+
551
+ // ── Blockers reference builder (the Phase-2 rebuild) ──────────────────────────
552
+ // Turns the /blockers ledger entries into a glance spec. A blocker is a DECAYING
553
+ // HYPOTHESIS, not a settled wall (docs/specs/dashboard-ux-standard.md): each entry
554
+ // moves through a pipeline (candidate → authority-checked → access-requested →
555
+ // dry-run → live-run) and terminates as either RESOLVED (it turned out not to be a
556
+ // wall) or a TRUE-BLOCKER (the best current understanding, with a recheck date —
557
+ // never "stop trying"). Every tile maps to a state predicate over ONE population
558
+ // (the non-archived ledger entries GET /blockers returns), so the counts are honest
559
+ // and each headline number has exactly one tile to drill into. The full record
560
+ // (id, state, timestamps, terminal detail) lives at Layer 3, one click below the
561
+ // plain-language row — the ~7,000-word raw table is gone from the front page but
562
+ // nothing is lost, only moved down a layer.
563
+
564
+ const BLOCKER_NON_TERMINAL = new Set([
565
+ 'candidate', 'authority-checked', 'access-requested', 'dry-run', 'live-run',
566
+ ]);
567
+
568
+ // Plain-word state names for the Layer-3 record (the raw state token stays honest to
569
+ // the ledger but reads as everyday language, never insider jargon at the glance).
570
+ const BLOCKER_STATE_WORD = {
571
+ 'candidate': 'Just spotted',
572
+ 'authority-checked': 'Checked who can clear it',
573
+ 'access-requested': 'Asked you for access',
574
+ 'dry-run': 'Trying it safely first',
575
+ 'live-run': 'Attempting it for real',
576
+ 'resolved': 'Resolved — not a wall after all',
577
+ 'true-blocker': 'Truly stuck for now (recheck scheduled)',
578
+ };
579
+
580
+ /** The single population: the non-archived ledger entries GET /blockers returns. */
581
+ export function blockersPopulation(entries) {
582
+ return (Array.isArray(entries) ? entries : []).filter((e) => e && typeof e.state === 'string');
583
+ }
584
+
585
+ export function buildBlockersGlance(entries) {
586
+ const all = blockersPopulation(entries);
587
+ const working = all.filter((e) => BLOCKER_NON_TERMINAL.has(e.state));
588
+ const stuck = all.filter((e) => e.state === 'true-blocker');
589
+ const resolved = all.filter((e) => e.state === 'resolved');
590
+
591
+ // Component-authored, jargon-free headline — honest to the one population, with
592
+ // count-aware verb agreement.
593
+ let headline;
594
+ if (all.length === 0) {
595
+ headline = 'No blockers are being tracked right now.';
596
+ } else {
597
+ const stuckClause = stuck.length === 0 ? 'Nothing is truly stuck right now'
598
+ : stuck.length === 1 ? '1 thing is truly stuck right now'
599
+ : `${stuck.length} things are truly stuck right now`;
600
+ const workClause = working.length === 0 ? 'none are being worked'
601
+ : working.length === 1 ? '1 is being worked'
602
+ : `${working.length} are being worked`;
603
+ headline = `${stuckClause}; ${workClause}.`;
604
+ }
605
+
606
+ const tiles = [
607
+ { key: 'stuck', label: 'Truly stuck', value: String(stuck.length), tone: stuck.length ? 'warn' : 'neutral', rows: stuck },
608
+ { key: 'working', label: 'Being worked', value: String(working.length), tone: 'neutral', rows: working },
609
+ { key: 'resolved', label: 'Resolved', value: String(resolved.length), tone: 'muted', rows: resolved },
610
+ ];
611
+
612
+ return { headline, tiles, population: all };
613
+ }
614
+
615
+ /** One plain-word Layer-2 row for a blocker — the plain-language framing that opened
616
+ * it (its detectedText). IDs/timestamps/state machinery are Layer 3, not here. */
617
+ export function blockerRowText(e) {
618
+ return sanitizeForDisplay(e.detectedText || e.origin || 'A blocker', 'summary');
619
+ }
620
+
621
+ /**
622
+ * Layer-3 full record for a blocker — every existing column plus terminal detail,
623
+ * one click below the plain Layer-2 row. All values via textContent (XSS-safe):
624
+ * detectedText / origin / terminal free text are UNTRUSTED and are displayed, never
625
+ * interpreted. This is where the raw state token, id, and timestamps legitimately
626
+ * live (they used to be dumped on the front page).
627
+ */
628
+ export function blockerRecordNode(doc, e, opts = {}) {
629
+ const fmtTs = opts.fmtTs || defaultFmtTs;
630
+ const wrap = el(doc, 'div', 'glance-record-fields');
631
+ const rows = [
632
+ ['What looked stuck', e.detectedText || '—'],
633
+ ['state', BLOCKER_STATE_WORD[e.state] || e.state || '—'],
634
+ ['id', e.id || '—'],
635
+ ['opened by', e.origin || '—'],
636
+ ['first seen', fmtTs(e.createdAt)],
637
+ ['last update', fmtTs(e.updatedAt)],
638
+ ];
639
+ const t = e.terminal;
640
+ if (t && t.kind === 'resolved') {
641
+ rows.push(['outcome', 'Resolved — it turned out not to be a wall']);
642
+ if (t.playbookPath) rows.push(['playbook', t.playbookPath]);
643
+ } else if (t && t.kind === 'true-blocker') {
644
+ rows.push(['outcome', `Best current understanding (${t.reasonKind || 'reason unknown'}) — not "give up"`]);
645
+ if (t.recheckAfter) rows.push(['recheck after', fmtTs(t.recheckAfter)]);
646
+ }
647
+ for (const [k, v] of rows) {
648
+ const row = el(doc, 'div', 'glance-record-row');
649
+ row.appendChild(el(doc, 'span', 'glance-record-key', String(k)));
650
+ row.appendChild(el(doc, 'span', 'glance-record-val', String(v)));
651
+ wrap.appendChild(row);
652
+ }
653
+ return wrap;
654
+ }
655
+
656
+ /**
657
+ * Build the FULL Blockers glance spec with drill wiring — importable by index.html
658
+ * AND the three test tiers. Each tile's onActivate renders the filtered ledger
659
+ * entries as plain Layer-2 rows; each row opens the Layer-3 record. Population +
660
+ * counts come from buildBlockersGlance (one denominator, honest counts).
661
+ */
662
+ export function blockersGlanceSpec(doc, entries, opts = {}) {
663
+ const base = buildBlockersGlance(entries);
664
+ const tiles = base.tiles.map((t) => ({
665
+ key: t.key,
666
+ label: t.label,
667
+ value: t.value,
668
+ tone: t.tone,
669
+ onActivate: ({ doc: d, drilldown, openRecord }) => {
670
+ const rows = t.rows || [];
671
+ if (rows.length === 0) return; // component renders the honest F6 empty-state
672
+ const list = el(d, 'div', 'glance-list');
673
+ for (const e of rows) {
674
+ const row = d.createElement('button');
675
+ row.type = 'button';
676
+ row.className = 'glance-list-row';
677
+ row.setAttribute('aria-label', 'Open the full record');
678
+ row.appendChild(el(d, 'span', 'glance-list-summary', blockerRowText(e)));
679
+ row.addEventListener('click', () => openRecord(blockerRecordNode(d, e, { fmtTs: opts.fmtTs })));
680
+ list.appendChild(row);
681
+ }
682
+ drilldown.appendChild(list);
683
+ },
684
+ }));
685
+ return { headline: base.headline, tiles, population: base.population };
686
+ }
@@ -3455,25 +3455,27 @@
3455
3455
  </div>
3456
3456
  </div>
3457
3457
 
3458
- <!-- Blockers tab — Blocker Ledger read surface (Phase 1).
3458
+ <!-- Blockers tab — Blocker Ledger read surface, rebuilt on the glance template
3459
+ (Dashboard UX Standard F10/F11, topic 29836 Phase 2).
3459
3460
  A blocker is a DECAYING HYPOTHESIS, not a settled wall: each entry moves through
3460
3461
  candidate → authority-checked → access-requested → dry-run → live-run → resolved /
3461
3462
  true-blocker. A true-blocker is "best current understanding — recheck after <date>",
3462
3463
  never "stop trying". Read-only here; data from GET /blockers. detectedText and all
3463
- free-text are UNTRUSTED and HTML-escaped before render. 503 = feature off. -->
3464
+ free-text are UNTRUSTED the shared glance component renders every value through
3465
+ sanitizeForDisplay + textContent (never innerHTML). 503 = feature off. -->
3464
3466
  <div id="blockersPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
3465
3467
  <div style="display:flex;justify-content:space-between;align-items:center">
3466
3468
  <h2 style="margin:0">Blockers</h2>
3467
3469
  <button onclick="loadBlockers()" style="padding:6px 12px">Refresh</button>
3468
3470
  </div>
3469
3471
  <div class="tab-purpose">
3470
- Things that looked like they stopped progress, tracked as <b>decaying hypotheses</b> rather than settled walls.
3471
- Each one moves through verification states; a "true blocker" is the best current understanding with a recheck date —
3472
- never a permanent "give up".
3473
- </div>
3474
- <div id="blockersBody" style="border:1px solid var(--border);border-radius:8px;padding:16px;font-size:13px">
3475
- <div style="color:var(--text-dim)">Loading...</div>
3472
+ Things that looked like they stopped progress, tracked as <b>decaying hypotheses</b> rather than settled walls
3473
+ the headline says where things stand; tap a tile to see which ones, tap one for the full record.
3474
+ A "truly stuck" blocker is the best current understanding with a recheck date, never a permanent "give up".
3476
3475
  </div>
3476
+ <!-- Glance floors F10/F11 (topic 29836): the shared component renders the
3477
+ headline + tiles + drill-down here. -->
3478
+ <div id="blockersGlance" class="glance-root"></div>
3477
3479
  </div>
3478
3480
 
3479
3481
  <!-- LLM Activity tab — Observable Intelligence (docs/specs/observable-intelligence.md).
@@ -6305,79 +6307,43 @@
6305
6307
  }
6306
6308
  }
6307
6309
 
6308
- // ── Blockers Tab (Blocker Ledger Phase 1 read surface) ──────────
6309
- // A blocker is a decaying hypothesis, not a settled wall. Read-only.
6310
- // detectedText + all free-text are UNTRUSTED escapeHtml before render.
6311
- function blockerStateBadge(state) {
6312
- const colors = {
6313
- 'candidate': 'var(--text-dim)',
6314
- 'authority-checked': '#6ea8fe',
6315
- 'access-requested': '#6ea8fe',
6316
- 'dry-run': '#d6a700',
6317
- 'live-run': '#d6a700',
6318
- 'resolved': 'var(--accent)',
6319
- 'true-blocker': 'var(--red)',
6320
- };
6321
- const bg = colors[state] || 'var(--text-dim)';
6322
- return '<span style="display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;' +
6323
- 'font-weight:600;color:#fff;white-space:nowrap;background:' + bg + '">' +
6324
- escapeHtml(String(state || 'unknown')) + '</span>';
6325
- }
6326
- function blockerTerminalLine(entry) {
6327
- const t = entry && entry.terminal;
6328
- if (!t) return '';
6329
- if (t.kind === 'resolved') {
6330
- const path = t.playbookPath ? ' · playbook: ' + escapeHtml(String(t.playbookPath)) : '';
6331
- return '<div style="font-size:12px;color:var(--accent);margin-top:4px">Resolved' + path + '</div>';
6332
- }
6333
- if (t.kind === 'true-blocker') {
6334
- // NEVER frame a true-blocker as settled / "stop trying" — it's a decaying hypothesis.
6335
- const reason = t.reasonKind ? escapeHtml(String(t.reasonKind)) : 'unknown reason';
6336
- const recheck = t.recheckAfter ? fmtRelTime(t.recheckAfter) : 'unscheduled';
6337
- return '<div style="font-size:12px;color:var(--red);margin-top:4px">Current hypothesis (' + reason +
6338
- ') — recheck after ' + escapeHtml(recheck) + '</div>';
6339
- }
6340
- return '';
6341
- }
6310
+ // ── Blockers Tab — glance floors F10/F11 (topic 29836, Phase 2) ──
6311
+ // A blocker is a decaying hypothesis, not a settled wall. Rebuilt on the shared
6312
+ // glance component: a plain-English headline + tiles (Layer 1); each tile drills
6313
+ // into the filtered ledger entries as plain sentences (Layer 2); each row opens
6314
+ // the full record with state/id/timestamps/terminal detail (Layer 3). detectedText
6315
+ // + all free text are UNTRUSTED → the component renders every value through
6316
+ // sanitizeForDisplay + textContent (never innerHTML), so this is XSS-safe by
6317
+ // construction (an improvement over the old escapeHtml-into-innerHTML table).
6342
6318
  async function loadBlockers() {
6343
- const bodyEl = document.getElementById('blockersBody');
6319
+ const glanceRoot = document.getElementById('blockersGlance');
6320
+ if (!glanceRoot) return;
6321
+
6322
+ const glance = await loadGlanceModule();
6323
+ if (!glance) {
6324
+ glanceRoot.textContent = 'Loading the glance view failed — refresh to retry.';
6325
+ return;
6326
+ }
6327
+
6328
+ let resp = null;
6344
6329
  try {
6345
- const resp = await apiFetch('/blockers');
6346
- const entries = (resp && resp.entries) || [];
6347
- if (entries.length === 0) {
6348
- bodyEl.innerHTML = '<div style="color:var(--text-dim)">No blockers recorded' +
6349
- ((resp && resp.total != null) ? ' (total ' + escapeHtml(String(resp.total)) + ')' : '') + '.</div>';
6350
- return;
6351
- }
6352
- bodyEl.innerHTML =
6353
- '<table style="width:100%;border-collapse:collapse;font-size:13px">' +
6354
- '<thead><tr style="text-align:left;color:var(--text-dim)">' +
6355
- '<th style="padding:6px 8px">State</th>' +
6356
- '<th style="padding:6px 8px">ID</th>' +
6357
- '<th style="padding:6px 8px">Detected</th>' +
6358
- '<th style="padding:6px 8px">Origin</th>' +
6359
- '<th style="padding:6px 8px;text-align:right">Updated</th>' +
6360
- '</tr></thead><tbody>' +
6361
- entries.map(e =>
6362
- '<tr style="border-top:1px solid var(--border);vertical-align:top">' +
6363
- '<td style="padding:6px 8px">' + blockerStateBadge(e.state) + '</td>' +
6364
- '<td style="padding:6px 8px;font-family:monospace;color:var(--text-dim)">' + escapeHtml(String(e.id || '—')) + '</td>' +
6365
- '<td style="padding:6px 8px">' + escapeHtml(String(e.detectedText || '')) + blockerTerminalLine(e) + '</td>' +
6366
- '<td style="padding:6px 8px">' + escapeHtml(String(e.origin || '—')) + '</td>' +
6367
- '<td style="padding:6px 8px;text-align:right;white-space:nowrap">' + escapeHtml(fmtRelTime(e.updatedAt || e.createdAt)) + '</td>' +
6368
- '</tr>'
6369
- ).join('') +
6370
- '</tbody></table>';
6330
+ resp = await apiFetch('/blockers');
6371
6331
  } catch (err) {
6372
6332
  const m = err && err.message ? String(err.message) : String(err);
6333
+ glanceRoot.textContent = '';
6334
+ const note = document.createElement('div');
6335
+ note.className = 'glance-empty';
6373
6336
  // 503 → the Blocker Ledger feature is off (monitoring.blockerLedger.enabled false, the default).
6374
- if (/503|unavailable|disabled|not initialized/i.test(m)) {
6375
- bodyEl.innerHTML = '<div style="color:var(--text-dim)">Blocker Ledger isn\'t turned on yet ' +
6376
- '(enable <code>monitoring.blockerLedger.enabled</code>).</div>';
6377
- } else {
6378
- bodyEl.innerHTML = '<div style="color:var(--red)">Error: ' + escapeHtml(m) + '</div>';
6379
- }
6337
+ note.textContent = /503|unavailable|disabled|not initialized/i.test(m)
6338
+ ? 'Blocker tracking isnt turned on for this agent yet.'
6339
+ : 'Could not load blockers right now — refresh to retry.';
6340
+ glanceRoot.appendChild(note);
6341
+ return;
6380
6342
  }
6343
+
6344
+ const entries = (resp && Array.isArray(resp.entries)) ? resp.entries : [];
6345
+ const spec = glance.blockersGlanceSpec(document, entries, {});
6346
+ glance.renderGlance(document, glanceRoot, spec);
6381
6347
  }
6382
6348
 
6383
6349
  // ── Threadline → Telegram bridge settings ──────────────────
@@ -522,7 +522,16 @@ export function buildMatrixModel(poolScope, pendingScope, transient = {}) {
522
522
  for (const m of machineList) {
523
523
  const key = `${acct.accountId}::${m.machineId}`;
524
524
  const t = transient[key] || null;
525
- const pendingLogin = inProgress.get(key) || null;
525
+ // OPTIMISTIC CANCEL (issue #1428): a confirmed cancel (2xx) drops a `cancelled`
526
+ // transient so the cell resets AT CLICK TIME instead of showing the stale
527
+ // in-flight flow for one poll cycle (~40s). It SUPPRESSES the cached
528
+ // pending-login (which the next poll hasn't dropped yet), letting the cell fall
529
+ // through to its true underlying state ("Sign in" / "Set up"). The transient is
530
+ // cleared on the very next poll (purgeTransients), so if the cancel actually
531
+ // FAILED server-side the fresh pending-login re-shows the flow — the poll stays
532
+ // the authority.
533
+ const cancelled = t && t.state === 'cancelled';
534
+ const pendingLogin = cancelled ? null : (inProgress.get(key) || null);
526
535
  let state;
527
536
  if (m.offline) state = 'offline'; // whole column offline (FD6)
528
537
  else if (t && t.state === 'held') state = 'held';
@@ -849,6 +858,11 @@ export function createController(opts) {
849
858
  if (!entry || typeof entry.at !== 'number') continue;
850
859
  if (entry.state === 'just-verified' && t - entry.at > JUST_VERIFIED_TTL_MS) delete state.matrixTransient[key];
851
860
  if ((entry.state === 'expired' || entry.state === 'broken') && t - entry.at > EXPIRED_TTL_MS) delete state.matrixTransient[key];
861
+ // The optimistic `cancelled` bridge (issue #1428) lives for exactly one poll:
862
+ // purgeTransients runs inside render() with the FRESH server bodies in hand, so
863
+ // clearing it here hands authority back to the poll — a still-pending login
864
+ // (cancel actually failed) re-derives 'in-progress' on this same render.
865
+ if (entry.state === 'cancelled') delete state.matrixTransient[key];
852
866
  }
853
867
  state.recentOutcomes = state.recentOutcomes
854
868
  .filter((o) => o && typeof o.at === 'number' && now() - o.at <= OUTCOME_TTL_MS)
@@ -1328,13 +1342,19 @@ export function createController(opts) {
1328
1342
  try {
1329
1343
  const r = await postJson(URLS.cancel, { machineId, id: accountId });
1330
1344
  if (r.ok && r.json && (r.json.cancelled || r.json.alreadyTerminal)) {
1331
- // TERMINAL (cancelled): the episode is over release the hold so the next
1332
- // rebuild replaces the flow with a fresh "Set up" from server state.
1345
+ // TERMINAL (cancelled): the episode is over. OPTIMISTIC RESET (issue #1428):
1346
+ // drop a `cancelled` transient + release the hold, then rebuild the cell NOW
1347
+ // from cache so the operator sees the in-flight flow disappear immediately —
1348
+ // not after the next ~40s poll. The transient suppresses the stale cached
1349
+ // pending-login until the next real poll reconciles (and stays authority if
1350
+ // the cancel actually failed). Keep a status line as the fallback for the
1351
+ // rare case where another open interaction defers the full rebuild.
1333
1352
  const key = `${accountId}::${machineId}`;
1334
- delete state.matrixTransient[key];
1335
1353
  delete state.matrixEpisodes[key];
1354
+ state.matrixTransient[key] = { state: 'cancelled', at: now() };
1336
1355
  cell.removeAttribute('data-interaction-open');
1337
1356
  setCellStatus(cell, 'Cancelled — you can set this up again.');
1357
+ rerenderMatrixFromCache();
1338
1358
  } else {
1339
1359
  const msg = (r.json && (r.json.error || r.json.reason)) ? (r.json.error || r.json.reason) : `failed (${r.status})`;
1340
1360
  setCellStatus(cell, `Couldn’t cancel: ${msg}`);
@@ -1 +1 @@
1
- {"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
@@ -12848,6 +12848,10 @@ process.stdin.on('end', async () => {
12848
12848
  // Recorded so deployed agents cleanly upgrade to the pre-POST-mint
12849
12849
  // template instead of getting a `.new` candidate.
12850
12850
  '63ca933e2d7c59d92c92d2799afa71b9c75e45caf3ab7c1cb06aa8eb95ba2900',
12851
+ // Pre-worktree-home-resolution version. Shipped through v1.3.813.
12852
+ // Existing agents must receive the constrained agent-home resolver and
12853
+ // loud unknown-id queue refusal rather than an inert `.new` candidate.
12854
+ '89849c10aa30cc83a07d6e7721aa3ebbfd07ab897250c0d0f3e234f079dba153',
12851
12855
  ]);
12852
12856
  /**
12853
12857
  * SHA-based migrator for telegram-reply.sh — replaces marker-string