Repository navigation
task-work silently writes no TAB_ID when the tab lookup misses: report and log the miss at launch (#242) - #243
Conversation
…t and log the miss at launch, link it from task-done (#242) A missed tab-id capture used to append nothing and print nothing, so its only symptom was task-done's "no tab id captured" hours later, in another command. `aw_record_tab_id` in `lib/zellij-tab.sh` now replaces the silent block in all seven task-work copies (drift-guarded `info-tab-id` region), both task-reviewer copies and task-recreate-worker. On a miss it says why on stderr — not-in-zellij, no-jq, list-tabs-empty, race, or no-match with the tab names zellij reported — and appends a `tab-id:` line to radio's log. A hit prints nothing; a miss never aborts the launch. task-done's skip line gains a second line naming which source was empty, including the grep that finds the launch-time `tab-id:` line. It still never falls back to the unscoped close-tab (#107 / #108). Trigger not reproduced: the nine TAB_ID-less sidecars on this machine all predate #118, which added the capture; 50-char and collision-suffixed names match byte-for-byte in zellij 0.44.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n if, not A && B || C, for the log append (SC2015) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spec complianceIssue #242 specified two parts: Part 1 — loud, logged, non-fatal capture. ✅ Fully delivered. Part 2 — find the trigger. ✅ Honestly assessed. The PR provides a solid analysis: all nine sidecars without
Constraints respected. ✅ No fallback to unscoped CI. ✅ Green, 1 run for head commit Code-review findingsNit 1 —
|
…ent and test no-zellij-bin, test the reviewer and recreate-worker callers (#242 review) - `no-zellij-bin` joins the reason list in the runbook row of all nine docs that carry it, with a test that drops zellij from `PATH`. - `task-reviewer` (claude and kiro-gh) and `task-recreate-worker` each get a test that a miss is reported and logged under their own caller name; the recreate-worker one also pins that the stale TAB_ID is stripped and not replaced. - A comment in `aw_record_tab_id` says why the miss path re-queries list-tabs up to three times, so nobody folds the calls together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dy (#236) Rebase onto origin/main after #243 (#242) merged first. The two PRs overlap on nine files -- CHANGELOG.md, README.md and all 7 */bin/task-done -- and this one DELETES those seven, so a resolution that took either side whole would have lost a P0's work or this one's. Carried forward rather than resolved by deletion: 1. #243's _TAB_ID_MISS block and the second skip line, which name WHICH source came up empty and print the `grep 'tab-id:'` that finds the launch-time log line. Seven copies of that became one when task-done was inverted, so it belongs in the canonical body. 2. Both README edits: this PR's module-shape section and #243's runbook row. #243's nine runbook docs -- 7 templates, README, and this repo's own .claude/gh-workflow.md -- are otherwise untouched; verified all nine. 3. Both CHANGELOG entries: this one under Changed, #243's under Fixed. 4. A fourth item not on the carry-forward list: #243's three task-done cases in tests/tab_id_capture.bats ran through $CLAUDE_GH_TASK_DONE, a helper var this PR retires. Retargeted to `env AW_IMPL=claude-gh "$TASK_DONE"`, the same treatment the other suites got. THEIR ASSERTIONS ARE UNCHANGED AND THEY PASS AGAINST THIS SHAPE, which is the evidence the port is faithful rather than plausible. Counts move again, and the previous figures were wrong against the wrong baseline: origin/main is now 1397 because #243 added 17 tests of its own, not the 1380 this branch had been quoting. Measured by checking origin/main out into a throwaway worktree and counting it rather than inferring: 1397 baseline - 32 retired + 14 added = 1379 bats --count tests/*.bats = 1379 ./run_tests.sh exit 0 -- 1379 ok, 0 not ok The CHANGELOG now names the REF as well as the tool, since "1380" was correct against the wrong baseline -- a third variant of the count-credibility problem raised in review, after the grep-vs-bats one. check-drift 25 groups. shellcheck clean on the full CI glob. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tical copies (#236) (#244) * task-done: one canonical body + tracker modules, deleting 7 near-identical copies (#236) task-done was a three-variant file wearing seven copies. claude-gh, claude-notion, kiro-gh and kiro-notion were byte-identical; claude-local and kiro-local were byte-identical to each other; claude-jira differed by seven lines. 1525 lines expressing about 249 distinct ones, held in step by ten of the 35 groups in tools/check-drift.sh. The part that genuinely differed was the part with no sentinel on it: the `gh pr view` / `gh pr create` block sat between two drift-guarded regions and was guarded by neither, so jira's Jira-key uppercasing could have broken in one copy unnoticed. The local board-regen region was nested inside confirm-and-cleanup, and extract_region is a plain awk window, so the outer extract swallowed the inner sentinels and passed only because both local copies happened to match. There is no agent axis here at all, and that shaped the design: removing a worktree, sweeping radio state and closing a tab never depended on which agent was in the tab. So a loadout is {tracker x agent} and the modules are keyed on the axes rather than the combo -- lib/trackers/{gh,jira,notion,local}.sh and lib/agents/{claude,kiro}.sh, four files and two, not seven of each. kiro-jira (#92) reuses jira.sh x kiro.sh with zero new module files for this tool. Three hooks carry it and four of the seven loadouts override none: aw_tracker_pr_section (jira), aw_tracker_usage_steps and aw_tracker_post_cleanup (local). lib/trackers/_default.sh holds what the four byte-identical copies actually had, so gh.sh and notion.sh override nothing rather than restating an identical PR section -- otherwise seven copies would merely have become four. aw_tracker_module / aw_agent_module live in lib/detect-impl.sh beside aw_all_impls, and aw_all_trackers / aw_all_agents derive the axis names from that list rather than restating them. No behaviour changes. One candidate was designed out rather than accepted: aw_regenerate_board defaults its `self` to ${BASH_SOURCE[1]}, which from a tracker module resolves to a file with no task-board beside it, so the sibling fallback would silently find nothing. aw_tracker_post_cleanup now takes the impl and names that loadout's own task-done, keeping $PATH-first-then-sibling resolution byte-identical. The two local board tests caught it on the first run. Tests ran 1380 -> 1360: 32 duplicated cases retired, 12 added. The port was done in two steps on purpose -- retarget all 67 task_done cases at the canonical script and confirm green first, then retire -- so behaviour preservation is an observation rather than a hope. tests/loadout_modules.bats proves every module LOADS (derived from aw_all_impls, failing on a missing file, an orphan file, or a module missing a hook) and tests/task_done.bats proves the right one RAN. Both were demonstrated to fail, not assumed to. Upgrading: no task-init re-run needed. All seven installers already symlink bin/task-done and never their own copy, so no installer-written artifact changes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * task-done: address review on #236 — call-site double error, stale comment, count parity (#244) Three items from the clean-with-nits review on PR #244. 1. tests/task_done_dispatcher.bats:56 said "kiro-notion's task-done prints branch/base lines", true pre-#236 and not after. The comment now says what the test pins: detection reached the notion module and the SHARED body produced those lines, there being exactly one task-done since #236. 2. The test count disagreed between the two durable records -- PR body 1380 -> 1360, CHANGELOG 1381 -> 1361. Nets agreed at -20, absolute baselines did not, which undercuts the credibility the retirement table exists for. Cause found rather than a side picked: `bats --count` and `grep -c '^@test'` differ by one because tests/radio_home_isolation.bats:105 has an @test inside a heredoc that writes a generated probe.bats fixture, so grep counts a test bats never runs. The measured count is authoritative; the CHANGELOG now states which tool produced it and shows the arithmetic. 3. The composition call site was source "$(aw_tracker_module "$AW_ROOT" "$TRACKER")" || exit 1 which reads as resolve-then-source and is not: on a missing module the helper writes its diagnosis and exits 1, but the substitution has already yielded the empty string, so `source ""` runs and bash appends `: No such file or directory` naming a line in task-done before `|| exit 1` is reached -- inviting a reader to debug the wrong file. Now two lines. The part worth recording is why the existing test missed it. `aw_tracker_module names the missing file rather than letting source fail` passed either way, because it exercised the helper directly and never went through the call site: a name promising more than it checked, so a green suite would have told the next reader something untrue. Same shape as the misnamed table row this branch caught in its own test rename. Both helper tests are renamed to say they test the helper, and two new cases run the real bin/task-done against a checkout with a module removed and refute the shell noise -- one for gh, one sweeping all four trackers. Both were verified to FAIL against the old call site before landing, which the first draft did not: it asserted `source: : not found`, the message the review described, rather than the one bash actually emits. That draft passed against the very call site it was written to reject. Counts: 1380 baseline - 32 retired + 14 added = 1362, and bats --count returns 1362. Suite exit 0, 1362 ok, 0 not ok. check-drift 25 groups. shellcheck clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * task-done: carry #243's skip-line fix and tests into the canonical body (#236) Rebase onto origin/main after #243 (#242) merged first. The two PRs overlap on nine files -- CHANGELOG.md, README.md and all 7 */bin/task-done -- and this one DELETES those seven, so a resolution that took either side whole would have lost a P0's work or this one's. Carried forward rather than resolved by deletion: 1. #243's _TAB_ID_MISS block and the second skip line, which name WHICH source came up empty and print the `grep 'tab-id:'` that finds the launch-time log line. Seven copies of that became one when task-done was inverted, so it belongs in the canonical body. 2. Both README edits: this PR's module-shape section and #243's runbook row. #243's nine runbook docs -- 7 templates, README, and this repo's own .claude/gh-workflow.md -- are otherwise untouched; verified all nine. 3. Both CHANGELOG entries: this one under Changed, #243's under Fixed. 4. A fourth item not on the carry-forward list: #243's three task-done cases in tests/tab_id_capture.bats ran through $CLAUDE_GH_TASK_DONE, a helper var this PR retires. Retargeted to `env AW_IMPL=claude-gh "$TASK_DONE"`, the same treatment the other suites got. THEIR ASSERTIONS ARE UNCHANGED AND THEY PASS AGAINST THIS SHAPE, which is the evidence the port is faithful rather than plausible. Counts move again, and the previous figures were wrong against the wrong baseline: origin/main is now 1397 because #243 added 17 tests of its own, not the 1380 this branch had been quoting. Measured by checking origin/main out into a throwaway worktree and counting it rather than inferring: 1397 baseline - 32 retired + 14 added = 1379 bats --count tests/*.bats = 1379 ./run_tests.sh exit 0 -- 1379 ok, 0 not ok The CHANGELOG now names the REF as well as the tool, since "1380" was correct against the wrong baseline -- a third variant of the count-credibility problem raised in review, after the grep-vs-bats one. check-drift 25 groups. shellcheck clean on the full CI glob. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #242
What changed
Part 1: the miss is loud, logged, and never fatal.
aw_record_tab_idinlib/zellij-tab.shreplaces the silent capture block in:task-workcopies (the drift-guardedinfo-tab-idregion)task-reviewercopies andtask-recreate-worker, which had the same three linesWhen the lookup misses, it prints on stderr why, names the slug it searched for, and appends a line to
~/.task-force/radio/log(tab-id: <caller> capture missed slug=… reason=… info=… detail=…). The reasons it tells apart:no-zellij-bin: zellij is not onPATHnot-in-zellij:$ZELLIJis unsetno-jq: jq is not onPATHlist-tabs-empty: zellij listed nothingrace: the tab is listed by the time the diagnosis re-queriesno-match: carries the slug's length and every tab name zellij reported, JSON-quoted, so a byte-level mismatch shows in the line itselfA successful capture prints nothing, so output is unchanged (regression test included). A miss still lets the worker launch.
The two ends are linked.
task-done'sSkipping zellij close-tab (no tab id captured …)line gains a second line naming which source was empty:$ZELLIJunsetTAB_ID=, with the exactgrep 'tab-id:.*slug=<slug> ' …/radio/logthat finds the launch-time lineThe reason is worked out when the id is read, because the sidecar is deleted before the close step reports it.
task-donestill never falls back to the unscopedclose-tab(#107 / #108).Part 2: the trigger was not reproduced
I could not reproduce the trigger. The issue's evidence turns out to have a simpler explanation:
TAB_ID(gdi-chatbot) have mtimes of 2026-05-12 to 2026-05-14. The capture was added by Fix #117: preserve TAB_ID across re-register; persist TAB_ID in $INFO_FILE #118 on 2026-05-24, so they predate the feature. Every sidecar on this machine written since has itsTAB_ID.zellij attach --create-background, not the live one). The 50-characterbug-model-renders-table-but-the-chat-already-outpu, its 56-character collision form…-hu1s5, andadd-readme-7qeguall came back byte-equal fromlist-tabs --json, matched right afternew-tab.So the intermittent reports come from a condition those artifacts do not record. The next one will name itself in one line. That also covers misses on
task-done's side, which are not capture failures at all: a branch switched away fromtask/<slug>(no sidecar found), ortask-donerun outside zellij.Sequencing: #237
This change lives in
task-work'sinfo-tab-idregion, which #237 (the tracker × agent split from #122 Phase 2) deletes and relocates. #237 must carry this forward into its new modules, not reinvent it. The behaviour lives inlib/zellij-tab.sh(aw_record_tab_id), so in practice the relocated code just needs to call it.Docs
.claude/gh-workflow.md.lib/zellij-tab.shactually logs.task-initre-run: the scripts reach machines through symlinks. A re-run only adds the new runbook row to an installed workflow doc.Verification
./run_tests.sh: 1393/1393 (baseline 1380 + 13 new). Most are intests/tab_id_capture.bats; it covers each reason code, a miss with zero exit and a log line, a silent hit, the kiro-gh loadout, and the threetask-donereasons. One more is intests/radio_runbook.bats.tools/check-drift.sh: 35 groups clean.shellcheck -x: clean on every changed shell file.🤖 Generated with Claude Code