Repository navigation
Dead-letters section and Requeue button (vikunja#557) - #9
Merged
Merged
Conversation
added 2 commits
August 29, 2026 07:28
~/.claude/task-queue/dead-letters/ is written by task-dispatcher when a task exhausts its routing retries, and nothing could show it — the MCP's get_task answered `not found` and this plugin globbed the queue root only. Seventeen tasks accumulated there between 2026-05-29 and 2026-07-25, every one a security audit request, all seventeen carrying the identical failed_reason, and the only notice any got was one Matrix message at the moment it was dropped. Pairs with task-queue-mcp v0.10.0. Does not fix the bug that produced the seventeen — that is vikunja#63/#169. - GET /dead-letters, read-only, reading the YAML directly like every other read. - panels/dead-letters.ts — collapsed, not a tab: the healthy count is zero, so a tab would be permanently empty furniture. The heading renders the count whatever it is, including `none`, and turns red when it is not. The count loads on every refresh rather than on expand; a number that appears only after the operator opens the section is a number nobody sees. - dead-letters.ts — shaping and reason-grouping as pure, tested functions. Grouped by failed_reason: 17 records with one identical reason are ONE bug that fired 17 times, and 17 sibling rows read as 17 unrelated problems. - Requeue button → the new `requeue` control action → POST /tasks/:id/requeue. Confirmed before firing, and the confirmation says the part that matters: requeueing does not fix why the task was dropped. - A source-level drift gate pinning the ControlAction union to server.ts's mutation route regex. AGENTS.md called these "three copies of one contract" and nothing checked it; adding an action to the union alone compiles, and the failure mode is a button that 404s against the plugin's own backend. Verified to fail in both directions. Verified against the live queue: GET /dead-letters returns all 17, one reason group, all targeting security. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> agent-id: developer
Audit 2026-08-29 (agent-workflow-interop-2026-08-phase1): no findings in this repo. Worth recording what the auditor verified structurally rather than by test — that toDeadLetter() builds its response from an explicit field allowlist and never references `payload`, making GET /dead-letters strictly narrower than the existing GET /tasks, and that renderRow() escapes every interpolated value while routing summary and reason through textContent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> agent-id: developer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Build
agent-workflow-interop-2026-08Phase 1. Pairs with task-queue-mcp#18 (v0.10.0), which owns the queue-side half and the operator-onlyPOST /tasks/{id}/requeueroute this calls.Why
~/.claude/task-queue/dead-letters/is written bytask-dispatcherwhen a task exhausts its routing retries. Nothing could show it: the MCP'sget_taskanswerednot found, and this plugin globbed the queue root only.Seventeen tasks sat there between 2026-05-29 and 2026-07-25 — every one a security audit request, all seventeen carrying the identical
failed_reason— with no interface anywhere in the fleet able to display the number.This does not fix the bug that produced them (vikunja#63/#169).
What
GET /dead-letters— read-only, readingdead-letters/*.ymldirectly like every other read here. No new manifest permission, no new env var.panels/dead-letters.ts— the section.dead-letters.ts— record shaping and reason-grouping as pure, unit-tested functions.requeuecontrol action → the MCP's operator-only route.Three decisions
none, and turns red the moment it is not.failed_reason. Seventeen records with one identical reason are one bug that fired seventeen times. Seventeen sibling rows read as seventeen unrelated problems — roughly how they were treated for three months.Requeue is confirmed before firing, and the confirmation says the part that matters: it does not fix why the task was dropped, so if the cause is live it comes back.
A drift gate the invariant was missing
AGENTS.md says the
ControlActionunion,server.ts's route regex, and the MCP's custom routes are "three copies of one contract" — and nothing checked it. Adding an action to the union alone compiles; the failure mode is a button that 404s against the plugin's own backend. The two copies in this repo are now pinned to each other by a source-level test. Verified to fail in both directions (droprequeuefrom the regex → red; drop it from the union → red).Handled edge cases
id—ago()maps an invalid date to "just now", which would claim a three-month-old drop happened seconds agocreatedis aDateDatedead-letters/fs.watchis not recursive on Linux; deliberate, and documented — the dispatcher's unlink from the queue root does fireVerification
npm run build(tsc gate) clean; 85 tests pass. Randist/server.jsagainst the live queue:Not yet deployed — needs
./deploy.sh && pm2 restart cloudcliafter merge, and the paired task-queue-mcp container rebuild for the Requeue button's route to exist.🤖 Generated with Claude Code