From cef7a4655ba71d976bc29e3d91193b845bff7224 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Mon, 26 Oct 2026 23:53:32 -0700 Subject: [PATCH 1/2] Retire the hourly found-work nudge from the kernel sweep (TASK-381) Lily ruled 2026-10-27 (decision 6ae0493258eabb3645e350c3): narrow the found-work wake to assigned or addressed events. The sweep woke every implementer seat for unclaimed rows, and most of those wakes ended NO_REPLY. Unclaimed rows now reach a seat through the row router; assigned rows keep the assigned-task wake (assignedTaskWakeService). - sweep() no longer calls wakeForFoundWork; it reports zero found-work wakes. - wakeForFoundWork and notifyFoundWork stay in place, unreached from the sweep, so their direct tests still pin the machinery. Deleting them is a follow-up. - Tests: the sweep-level found-work assertions now call wakeForFoundWork directly, and a new test pins that sweep() sends no nudge. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kite Agent-Model: claude/claude-haiku-5-5/default --- .../services/kernelWorkSweepService.test.js | 25 +++++++++++++------ backend/services/kernelWorkSweepService.ts | 12 ++++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/backend/__tests__/unit/services/kernelWorkSweepService.test.js b/backend/__tests__/unit/services/kernelWorkSweepService.test.js index 5c1a9d371c..e9e928a28d 100644 --- a/backend/__tests__/unit/services/kernelWorkSweepService.test.js +++ b/backend/__tests__/unit/services/kernelWorkSweepService.test.js @@ -329,7 +329,7 @@ describe('sweep', () => { { _id: POD_A, tasks: [{ taskId: 'TASK-007', title: 'stalled work' }], count: 1 }, ]); - const result = await KernelWorkSweepService.sweep(NOW); + const result = await KernelWorkSweepService.wakeForFoundWork(NOW); expect(mockNotifyFoundWork).toHaveBeenCalledTimes(1); const [podId, items, count] = mockNotifyFoundWork.mock.calls[0]; @@ -342,7 +342,7 @@ describe('sweep', () => { it('matches unoffered revisions regardless of age so the hourly batch can retry', async () => { Task.aggregate.mockResolvedValue([]); - await KernelWorkSweepService.sweep(NOW); + await KernelWorkSweepService.wakeForFoundWork(NOW); const [pipeline] = Task.aggregate.mock.calls[0]; const match = pipeline[0].$match; @@ -370,7 +370,7 @@ describe('sweep', () => { })); Task.aggregate.mockResolvedValue([{ _id: POD_A, tasks: many, count: 9 }]); - await KernelWorkSweepService.sweep(NOW); + await KernelWorkSweepService.wakeForFoundWork(NOW); const [, items, count] = mockNotifyFoundWork.mock.calls[0]; expect(items).toHaveLength(9); @@ -429,14 +429,25 @@ test('watcher receipts retry even when work discovery is disabled', async () => }); -test('a watcher retry failure does not block rescue or work discovery', async () => { +test('a watcher retry failure does not block rescue', async () => { const receipts = require('../../../services/taskEventService').retryTaskWatcherDigests; receipts.mockRejectedValueOnce(new Error('lookup failed')); const rescue = jest.spyOn(KernelWorkSweepService, 'rescueLapsed'); - const discovery = jest.spyOn(KernelWorkSweepService, 'wakeForFoundWork'); try { await KernelWorkSweepService.sweep(NOW); expect(rescue).toHaveBeenCalledTimes(1); - expect(discovery).toHaveBeenCalledTimes(1); - } finally { rescue.mockRestore(); discovery.mockRestore(); } + } finally { rescue.mockRestore(); } +}); + +test('TASK-381: the sweep sends no found-work nudge, even with unclaimed rows due', async () => { + Task.aggregate.mockResolvedValue([ + { _id: POD_A, tasks: [{ taskId: 'TASK-015', title: 'decouple' }], count: 1 }, + ]); + const discovery = jest.spyOn(KernelWorkSweepService, 'wakeForFoundWork'); + try { + const result = await KernelWorkSweepService.sweep(NOW); + expect(discovery).not.toHaveBeenCalled(); + expect(mockNotifyFoundWork).not.toHaveBeenCalled(); + expect(result.woken).toBe(0); + } finally { discovery.mockRestore(); } }); diff --git a/backend/services/kernelWorkSweepService.ts b/backend/services/kernelWorkSweepService.ts index 98bbeb278d..b77508da2a 100644 --- a/backend/services/kernelWorkSweepService.ts +++ b/backend/services/kernelWorkSweepService.ts @@ -365,13 +365,17 @@ class KernelWorkSweepService { scannedPods: 0, rescued: 0, deferred: 0, woken: 0, skippedNoWork: 0, }; } + // TASK-381 (ruling 2026-10-27): the hourly found-work nudge is retired. It + // woke every implementer seat for unclaimed rows, and most of those wakes + // ended NO_REPLY. Unclaimed rows reach a seat through the row router (one + // PATCH + one @mention per row); assigned rows through the assigned-task + // wake. So the sweep no longer calls wakeForFoundWork. const { rescued, deferred } = await KernelWorkSweepService.rescueLapsed(now); - const { woken, skippedNoWork, scannedPods } = await KernelWorkSweepService.wakeForFoundWork(now); - if (rescued.length || deferred.length || woken) { - console.log(`[kernel-sweep] rescued=${rescued.length} deferred=${deferred.length} woken=${woken} pods=${scannedPods}`); + if (rescued.length || deferred.length) { + console.log(`[kernel-sweep] rescued=${rescued.length} deferred=${deferred.length}`); } return { - scannedPods, rescued: rescued.length, deferred: deferred.length, woken, skippedNoWork, + scannedPods: 0, rescued: rescued.length, deferred: deferred.length, woken: 0, skippedNoWork: 0, }; } } From a60a9f6f65a04143152475a43a7bed321dc2ea03 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Tue, 27 Oct 2026 00:05:57 -0700 Subject: [PATCH 2/2] Amend ADR-018 D8.7: the kernel sweep no longer sends the found-work nudge (TASK-381) Records Lily's 2026-10-27 ruling (decision 6ae0493258eabb3645e350c3) in the ADR that owns the discovery wake, per the review on #2839. Notes that wakeForFoundWork and its config read are inert until the delete-or-reconnect choice is made. Co-Authored-By: Claude Haiku 5.5 Co-authored-by: kite Agent-Model: claude/claude-haiku-5-5/default --- docs/adr/ADR-018-agent-attention-claims.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/adr/ADR-018-agent-attention-claims.md b/docs/adr/ADR-018-agent-attention-claims.md index 8ebd338129..28786208d8 100644 --- a/docs/adr/ADR-018-agent-attention-claims.md +++ b/docs/adr/ADR-018-agent-attention-claims.md @@ -473,6 +473,12 @@ The D8.2 discovery exception woke reviewers who had no implementation capacity: Discovery now requires an explicit `config.workDiscovery: { enabled: true, role: 'implementer' }` on the installation. It skips a seat with assigned pending work or an active claim in that pod, whether the claim stores a seat key or its bot User id, and caps delivery at one nudge per seat and pod per hour. Missing role configuration fails closed. An unoffered revision remains eligible beyond the sweep's ten-minute tick so the next hourly batch can carry it. A capped nudge does not mark an unassigned row as offered. Browser board updates and addressed owner wakes are unaffected. +### D8.7 — AMENDMENT (2026-10-27): the kernel sweep no longer sends the found-work nudge (TASK-381) + +Lily ruled on TASK-381 (decision `6ae0493258eabb3645e350c3`): narrow the found-work wake to assigned or addressed events. `KernelWorkSweepService.sweep()` no longer calls `wakeForFoundWork`, so the hourly D8.3 nudge is not sent by the sweep. Unclaimed rows reach a seat through the row router (one assignment and one @mention per row). Assigned rows keep the assigned-task wake (D8.4), and addressed owner wakes are unaffected. + +What this leaves in place, so the next reader does not assume it is gone: `wakeForFoundWork` and `notifyFoundWork` still exist and are still exercised by direct tests. Nothing in production reaches them from the sweep. The `config.workDiscovery` read in D8.3 is therefore inert until those functions are either deleted or reconnected, and that choice is pending. Until it is made, read D8.3 as describing behaviour the sweep no longer performs. + ### D8.4 — AMENDMENT (2026-10-24): assigned work survives a silent turn **Status: ACCEPTED direction (TASK-469), including the ruling that deliberate