Repository navigation
fix(task-bridge): archive context-drop results when voice client is offline - #1189
Conversation
…ffline Context-drop tasks written by Sutando.app have no bridge consumer — Discord/Telegram/voice bridges all skip them (no source field match). When the voice client is offline the result-scan loop's `continue` leaves them in results/ indefinitely. Fix: read the task file and check for `source: context-drop`. If present, archive the result immediately (same path as task-chat-* results). No DM or voice narration — context-drops are local-only, delivery is silent. Companion fix: Sutando.app main.swift writeTask() must include `source: context-drop` in the task file template for this to take effect. Closes sonichi#969 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
task-bridge.ts now archives results whose task file has `source: context-drop` when the voice client is offline (companion to task-bridge PR closing sonichi#969). Without this field the task-bridge fix has no way to identify context-drop tasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VasiliyRad
left a comment
There was a problem hiding this comment.
Fix is correct. The voice-offline result-scan block now reads the task file and checks for source: context-drop, then archives both files with the same pattern used elsewhere. The continue correctly skips the re-queue path. The companion main.swift fix closes the gap for the hotkey path (the startContextDropWatcher code path already wrote this field). Two files, 24 additions, no unrelated changes. Clean.
liususan091219
left a comment
There was a problem hiding this comment.
Read the diff and walked the surrounding context in src/task-bridge.ts:700-727. Patch lives between the existing task-chat-* archive block and the outer "stay queued" continue; — placement is correct, no race with the chat-archive path (different regex filter even though taskId.startsWith('task-') is shared).
Blocking
None. Logic is sound, scope is small (24 lines, no deletions), no behavior change for other paths. Voice-offline → source: context-drop → archive within 10s is what the patch delivers, matching #969.
Non-blocking
-
PR body slightly out of sync with the diff. The body says "The companion fix (Sutando.app
writeTask()addingsource: context-drop) is in the distribution repo" — but this PR actually includes thesrc/Sutando/main.swift:1777companion change too. Worth tightening the body so a future reader doesn't think only the bridge half landed here. -
Outer guard
if (taskId.startsWith('task-'))is always true in this code path (every task id starts withtask-); the real filter is the^source:\s*context-dropregex inside. Functionally fine, but the outer guard reads like dead code. Could drop it for clarity — or, if kept as a "task-id sanity check", a comment saying so would help. -
No tests added. The recent project trend (per the structural-test PRs landing alongside bridge changes) has been to ship one. A small "result-watcher sees
source: context-droptask with no voice client → archives within 10s" test intests/would lock in the contract. -
catch {}swallows read errors silently. Defensible — falls through to the queued-stay path on read failure — but if a permissions/EBUSY problem ever shows up on a real host, the silent path makes it invisible. Aconsole.warnin the catch (matching the style of[TaskBridge] Failed to forward ...on line 709) would aid diagnosis.
— Maddy (MBP node)
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Diff reviewed. The Swift companion (adds source: context-drop field) and the TS archive block (regex check + archive-after-10s) are both correct. Empty catch {} on the task-body read is appropriate — file-read failure should silently fall through to existing behavior. The taskId.startsWith('task-') guard is redundant but harmless. CI green, companion tests in #1192.
…sonichi#969) Companion test PR for sonichi#1189 (fix: archive context-drop results when voice client is offline). Tests will fail on main until sonichi#1189 is merged. 13 tests across 3 suites: - main.swift writeTask() emits `source: context-drop` before `task:` - task-bridge.ts result watcher has the detection regex in the offline branch, calls _sendTaskStatus/_deliveredResults/_pendingTasks, and archives both result + task file (2× archiveFile calls) - Pure regex unit tests pin the /^source:\s*context-drop/m contract: matches well-formed context-drop tasks, rejects voice/discord tasks, and rejects inline occurrences inside the task body prose Source-inspection approach (no import of task-bridge.js) avoids the node:sqlite availability constraint that affects task-bridge-format.test.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VasiliyRad
left a comment
There was a problem hiding this comment.
Clean, scoped fix. The new block sits correctly inside the voice-offline path after the chat-archive handler; /^source:\s*context-drop/m regex guard prevents double-archive of task-chat-* (those don't have the field). Outer continue at line 726 already short-circuits the iteration, so the inner continue is redundant-but-harmless. Swift side is the load-bearing half — additive guard is safe to land without it. Test plan: typecheck + manual is fine for a 23-line additive change.
LGTM 👍
bassilkhilo-ag2
left a comment
There was a problem hiding this comment.
Good two-part fix for #969. The approach (adding source: context-drop in the Swift task writer, then keying off that field in task-bridge.ts) is clean — the task file itself signals the delivery contract rather than requiring the bridge to maintain a separate allowlist of sources.
Small nit: if (taskId.startsWith('task-')) is always true by construction (all task IDs start with 'task-'), but it's harmless — just dead code.
The 10s delayed archive + _deliveredResults.add(file) + _pendingTasks.delete(taskId) correctly mirrors the other offline-client archive branches. LGTM.
jgluck96
left a comment
There was a problem hiding this comment.
LGTM. The two-part fix is tightly coupled correctly:
- main.swift adds
source: context-dropto writeTask() output — the missing field that caused task-bridge to skip these entirely - task-bridge.ts reads it in the voice-offline path: archive + mark delivered, skip the 'other bridges will handle it' fallthrough
Regex /^source:\s*context-drop/m handles any whitespace between colon and value. The 10s archive-delay pattern matches the rest of the file. In-flight state cleanup (_deliveredResults, _pendingTasks) is correct. Forward-looking only — old tasks without the field still need the 24h stale sweep, which is acceptable.
sonichi
left a comment
There was a problem hiding this comment.
LGTM. The two-file fix is the right approach — Swift side writes the source: context-drop field, TS side detects it and archives without waiting for a bridge delivery. The 10s archive delay, _deliveredResults.add + _pendingTasks.delete + continue matches the voice-task archive pattern exactly. The try/catch around the taskBody read is appropriately defensive.
sonichi
left a comment
There was a problem hiding this comment.
LGTM. The Swift companion (source: context-drop field) + task-bridge regex guard work together correctly. One note: the existsSync(ctxTaskFile) fast-path is correct but if the task file is already gone, the result stays in results/ unarchived — the stale-results sweep covers it eventually, so this is fine for the current scope. Closing my duplicate #1298.
sonichi
left a comment
There was a problem hiding this comment.
LGTM. Clean, minimal fix for the context-drop pile-up (issue #969). The 10s delay before archiving is a sensible grace period. NOT superseded by Wave 4 — this is the only place that handles source:context-drop archiving in the voice-offline path.
One note: the merge guide listed '+ 8 tests for _taskSource() added' but the PR only has 2 files (no test file). The description appears to be a documentation error in our notes — the fix itself is complete as-is.
Problem
Context-drop tasks written by Sutando.app (via keyboard shortcut) have no bridge consumer — the task file currently has no
source:field, so Discord/Telegram/voice bridges all skip the result. When the voice client is offline, the result-scan loop hits thecontinueguard and leavesresults/task-*.txtfiles accumulating indefinitely (the archive-stale-results.py startup sweep is the only thing that eventually clears them, after 24h).Reported in: #969
Fix
In the voice-offline path of the result-scan loop, after the voice-task forward and the
task-chat-*archive blocks, check if the corresponding task file hassource: context-drop. If so, archive the result immediately — same pattern astask-chat-*.No DM, no voice narration — context-drops are local-only; silent archival is the right delivery path.
Companion fix
The companion fix (Sutando.app
writeTask()addingsource: context-dropto the task file template) is in the distribution repo. Without it this guard is a no-op — the fix is additive and safe to land independently.Test plan
npm run typecheck→ cleanCloses #969
🤖 Generated with Claude Code