You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rolling paper-cut batch per the v11 intake throttle (operating-procedures + canonical lane prompts): consequence findings file standalone; paper-cuts land here as lines and are batch-fixed in one sweep PR when the batch justifies it. Control tower created this because the throttle was inert without it (2026-07-20 triage audit finding).
Lines
Folded from standalone issues (closed, content preserved here):
From the 2026-07-20 triage-lane session (tool-mechanics nit):
TaskCreate invoked with a batched tasks:[...] array param (assumed multi-task-per-call shape) — actual tool signature is one task per call (subject+description strings), and its schema wasn't loaded into context yet, so the batched call round-tripped as InputValidationError before any tasks were created. No functional impact (skipped task-tracking for this cycle and proceeded), but worth flagging if TaskCreate batching is ever considered — the current one-task-per-call contract makes multi-item tracking expensive enough that lanes reasonably skip it.
From the 2026-07-20 work-2 lane session (rule 4b adjacency nit):
source-control(babysit-prs): absorb v4 loop-prompt operating rules into the skill #477 carries status: ready + wayfind: design simultaneously. Rule 4b's literal defect-skip list only names status: needs-decision/needs-human as mutually exclusive with status: ready, but wayfind: design's own taxonomy description ("design-space or domain-model decision; human in the loop") is the same semantic — a ready item wearing it reads as the identical triage defect 4b targets, just an unlisted label. Skipped source-control(babysit-prs): absorb v4 loop-prompt operating rules into the skill #477 this cycle on that reasoning rather than picking it; worth deciding whether 4b's skip list should extend to all wayfind: * human-in-loop variants (interview/design/prototype), not just the two named labels.
From the 2026-07-20 babysit lane session (amendment-round 13 restart, 6-PR cycle: #489, #568, #616, #665, #699, dotfiles#236):
pr_queue_snapshot.py reports "N blocking bot feedback items" by counting claude[bot] review-run summaries rather than reading their latest content — docs(ai-adoption-ladder): native-vs-hook telemetry audit + decision record #699's dispatch showed "3 blocking" when the PR was already ready-to-merge (and in fact independently merged) at HEAD.
A worker-scope lease (on docs(session-flow): document override boundary for stage taxonomy and retro rubric #489) stayed held and heartbeat-healthy throughout its run, yet a same-gh-identity push still landed on that PR's branch outside the lease path mid-cycle (the operator working the same PR live). The lease correctly cannot and does not prevent this — worth documenting explicitly as an expected limitation (a lease guards against concurrent babysit writers, not a human/other-session sharing the same login) so future workers don't over-trust lease exclusivity as a full race guarantee.
From the 2026-07-20 triage-lane session (rule 8b/8c priority-consistency nit):
From the 2026-07-20 work-2 lane session (tool-mechanics nit, rule 23):
gh issue view --json comments / gh api repos/.../issues/{n} return comment id as the GraphQL global node ID (e.g. IC_kwDO...); gh api repos/.../issues/comments/{id} -X PATCH (the REST edit-in-place endpoint rule 23 needs) requires the plain numeric REST id instead and 404s silently on the node-ID form — no error surfaced beyond a bare 404, easy to miss if the caller doesn't re-verify. First edit attempt this session silently no-op'd on the wrong ID shape; caught only by re-fetching and diffing updated_at. Get the numeric id via gh api repos/<o>/<r>/issues/<n>/comments -q '.[] | select(...) | .id' instead of the --json comments node-ID field before any rule-23 PATCH.
From the 2026-07-20 work lane session (amendment-round 13 restart):
gh pr checks <N> --watch --interval N in this environment did not reliably converge to a terminal state within a single tool call — repeated calls sometimes returned the same stale snapshot rather than blocking until a genuinely new state, requiring a plain (non-watch) gh pr checks poll loop instead. Possibly a gh CLI / Windows Git Bash interaction quirk rather than a repo-owned bug; noting for awareness, not filing separately (outside this repo's ownership).
From the 2026-07-20 triage-lane session (own-work correctness miss):
This repo has native GitHub Issue Types configured (Task/Bug/Feature, confirmed via issueTypes GraphQL query) and the label taxonomy doc says type belongs there, not a type: label, on org repos — but no type: label exists in this repo's live label set either, and the 9 items this lane triaged in its first cycle today (source-control:babysit-prs: bulk --resolve --include-human can sweep a thread deliberately deferred pending a human ruling #671/672/674/677/684/687/688/691/693) all shipped with zero issue type set, because prior cycles' own precedent (checked before filing) never set one either and the standing rules don't call it out explicitly. Caught mid-cycle-3 and backfilled retroactively (gh issue edit --type) for all of cycle 1+2's items (15 issues) plus set correctly on this cycle's historic-normalization batch going forward. Worth adding an explicit "set native issue type" step to this lane's own rule 1/8g text so it isn't rediscovered per-session.
From the 2026-07-20 triage-lane session (cycle 4, gh CLI tool-mechanics nit):
From the 2026-07-20 PR #737 review (setup-skill pattern gaps — verbatim-mirrored across /discovery:setup, /planning:setup, and the new /verification:setup; fix belongs to the shared pattern / the topic-docs contract binding, not one copy — patching one copy diverges an explicitly-mirrored family):
No explicit up-front rejection of a root-equivalent memory_dir — converted to toolchain/discovery/planning/verification: shared setup-skill topic-docs contract gaps (concern-file-ignore path, memory_dir root-rejection, headless-vs-forked ruling) #745 (needs-human) (./empty/repo-root) before the memory-root self-ignore write. Repro: apply memory_dir=. would make "the memory root's self-ignoring .gitignore" resolve to the consumer's root .gitignore and write *, hiding every untracked file. Currently prevented only by the downstream bolded backstop "Never edit the consumer's root .gitignore" (apply step 2) rather than the up-front rejection the contract (docs/conventions/topic-docs/README.md L259-262) mandates. Bounded (requires invalid off-default input + violating the bolded prohibition) but defense-in-depth is missing. Fix direction: validate and reject a root-equivalent memory_dir up front, surfacing it per the contract. Origin: same three setup skills (apply step 2). PR refactor(toolchain): relocate setup topic-docs offering to the verification plugin that owns it #737 thread (line 79).
Non-interactive/headless apply with full args permits persisting .claude/topic-docs.yaml — converted to toolchain/discovery/planning/verification: shared setup-skill topic-docs contract gaps (concern-file-ignore path, memory_dir root-rejection, headless-vs-forked ruling) #745 (needs-human), conflicting with the topic-docs contract's forked/headless read-only rule (docs/conventions/topic-docs/README.md L240-245: "A fork never writes .claude/topic-docs.yaml. This rule is contract-owned."). Repro: a dispatched/headless worker passing the complete <key>=<value> set is "never prompted" and writes the team-shared concern file without an interactive user decision. Fix direction: gate the persist on interactive context (or an explicit contract-sanctioned override), skipping the write in forked/headless runs, uniformly across all setup skills. Origin: same three setup skills (action-routing / apply step 1). PR refactor(toolchain): relocate setup topic-docs offering to the verification plugin that owns it #737 thread (line 33). Strongest of the three — the contract rule is explicit and contract-owned.
From the 2026-07-20 PR #742 review (deferred, fail-closed kept — security-guard relaxation, not a paper-cut fix):
Literal-$ authorized-path support in the disk-hygiene destructive guard. Repro: _literal_shell_words (plugins/disk-hygiene/skills/clean/scripts/destructive_guard.py L56-59) blanket-rejects any command containing $, so an authorized --data-root whose CLAUDE_PLUGIN_DATA path contains a literal $ is rejected before parsing — scan/preview/apply fail closed for those installs despite the argv authority. Current behavior is fail-closed/fail-loud (deny with visible reason) = over-blocking, the safe direction, outside DEFER-FORBIDDEN — so deferred deliberately, not a quick fix. Fix direction (design note): allow $ only inside a single-quoted literal word (bash does NOT expand $ in single quotes; it DOES inside double quotes), which requires a quote-aware tokenizer that still rejects real expansion/$(...)/backtick syntax — a security-guard change that must not reopen the injection vector the blanket check exists to block. Origin: PR fix(disk-hygiene): guard resolves authorized data root from hook argv #742 thread (destructive_guard.py line 141). → disk-hygiene: destructive_guard.py literal-$ authorized-path support in the shell tokenizer (PR #742 follow-up) #1035
From the 2026-07-20 PR-review blitz (deferred review threads, genuine-but-deferrable — outside DEFER-FORBIDDEN, off-default-path/advisory):
DECLARED_SAVEPOINT granularity mismatch in the retro multi-session snippet. Repro: handoff SKILL.md "Where handoffs live" defines a "save-point convention in CLAUDE.md / .claude/rules" as the FULL handoff location (used as-is, wins), but plugins/session-flow/skills/retro/context/session.md (~L55) labels rung 2 with that same "save-point convention" phrasing while using it as the memory_dir ROOT and appending /handoffs. A user who declares handoffs at .claude/handoffs and passes it as DECLARED_SAVEPOINT gets .claude/handoffs/handoffs; ls … 2>/dev/null swallows the miss silently. Deferred: retro is a read-only reflection pass (no gate, no irreversible action), off default path (.work default works), bounded. Fix direction: relabel rung 2 as a memory ROOT (not "save-point convention"), OR reconcile the two skills' granularity + make the retro snippet tolerant of a /handoffs-suffixed value. Origin: PR fix(claude-memory,session-flow): quote-aware topic-docs seam parser via shared helper #756 thread (retro/context/session.md:55). → session-flow/retro: fix DECLARED_SAVEPOINT granularity mismatch in multi-session snippet #821
/interview mid-task upgrade rule cannot fire. Repro: plugins/planning/skills/interview/context/session-config.md "Inverse direction — mid-task" (~L89) is phrased as an imperative to an executing actor, but /interview terminates at handoff (its own "handoff ALWAYS terminates current execution" rule) and no hook wires this context into the downstream execution session — read as runtime behavior it never runs. Deferred: advisory prose, no gate/irreversible action. Fix direction: reframe as guidance the interview hands the USER at handoff ("watch for these signals during execution"), consistent with the file's "advisory framing" section, OR relocate the rule into the execution/implement workflow where an agent is actually running. Origin: PR feat(planning): interview recommends downstream model, effort, and advisor #750 thread (interview/context/session-config.md:89). → planning/interview: reframe session-config advisory framing for terminal/general sessions #822
Session-config recommendation applied to terminal general interviews. Repro: session-config.md L7-8 frames the recommendation as configuring "the downstream execution session," but plugins/planning/skills/interview/SKILL.md Step 5 (L190) makes a general session terminal with no downstream consumer, while the deliberate "Both domains" section (SKILL.md:225 / session-config.md L76-80) extends the recommendation to general sessions — the two framings are never reconciled, producing /model/effort//advisor guidance for a session that will not exist. Deferred: advisory prose, reversible. Fix direction: for general sessions frame the advice as config for the current / next session (applied now), not "the downstream execution session," rather than dropping the deliberate "Both domains" scope. Origin: PR feat(planning): interview recommends downstream model, effort, and advisor #750 thread (interview/SKILL.md:225). → planning/interview: reframe session-config advisory framing for terminal/general sessions #822
From the 2026-07-20 PR #739 review (education explain evals — manual/advisory eval-format design, not DEFER-FORBIDDEN; the fix is a skill-quality schema decision):
From the 2026-07-21 triage-lane session (gh tool-mechanics gotcha, self-caught):
gh issue comment/comment-PATCH via inline --body with backtick-wrapped terms runs those terms as bash command-substitution and STRIPS them from the posted body — silent corruption, flagged only by a stray command not found on stderr. Hit on babysit-prs: resolve babysit_self_logins discovery contract (code drops discovery-widening; plugin.json userConfig still claims it) #897 (one --extra-self dropped; fixed via a PATCH edit). Always pass any comment/body containing backticks or $ through --body-file / -F body=@file (the lane's established brief pattern), never inline --body. Cheap fleet-wide guard: prefer --body-file for all non-trivial gh comment content.
Sweep rule: one PR per batch, structure-only/small fixes, each line checked off with the commit that fixed it.
From the 2026-07-21 work-lane session (cycle 1, pick-order scoping nits):
feat(claude-ops or session-flow): loop-prompt authoring skill — generate and maintain standing loop-lane prompts #480 (status: ready) explicitly states in its own body "Placement (claude-ops vs session-flow vs autonomy) = design decision for triage/human" but does not carry status: needs-decision — same defect class as rule 4b's needs-decision/needs-human co-labeling check, just not literally co-labeled (the ambiguity is in the body, not a second status label). Fix direction: either the author's self-flagged placement questions should route these to needs-decision at filing time, or list-frontier/triage should grep body text for this pattern. Left unclaimed this cycle. Resolved 2026-07-22 (cycle 3): re-verified live — the placement question was answered (operator design input + ratification interview, 2026-07-22 comments) and feat(claude-ops or session-flow): loop-prompt authoring skill — generate and maintain standing loop-lane prompts #480 correctly sits at status: ready. No mislabel remains.
CI-gate backlog: automatable conformance checks surfaced by the #313 fleet audit #445 (status: ready) is explicitly headed "No linked issue: tracking issue; closes nothing" — it's a checklist of 8 independent automatable CI-gate items carried out of a closed epic (Epic: plugin fleet conformance audit — 50-plugin doctrine matrix and remediation waves #313), not a single-PR-closeable item. A pick-order pass that doesn't read the full body (just title+labels) would wrongly treat it as dispatchable. Fix direction: decompose via /work-items:decompose into 8 sub-issues, or add a label/marker that flags "tracking issue, do not auto-dispatch whole" the same way needs-human/needs-decision do. Left unclaimed this cycle.
ci-health: detect checks that degrade mergeStateStatus without completing (stuck runner-label / orphaned status / never-settling) #374's title prefix ci-health: reads like a distinct plugin name but there is no plugins/ci-health/ directory — its actual deliverable (full body) targets plugins/source-control/skills/babysit-prs/ scripts. A pick-order pass that infers plugin ownership from title prefix alone (as this lane's guidance currently does — no plugin: label taxonomy exists, per gh label list) can mis-classify it as an independent-plugin pick and wrongly parallelize it alongside a real source-control pick. Not unique to ci-health: detect checks that degrade mergeStateStatus without completing (stuck runner-label / orphaned status / never-settling) #374 — likely other topic-prefixed titles (autonomy:, loops:, convention:) don't map 1:1 to plugins/* dirs either. Fix direction: either add a real plugin: <name> label taxonomy (durable, queryable) or document that title-prefix-as-plugin-inference is unreliable and must be body-verified before same-plugin-conflict checks.
From the 2026-07-21 babysit-lane session (cycle 1, worktree-prune stale-record nit):
Queue-start prune (prune_babysit_worktrees.py --apply) errored on a leftover state record for a merged/closed PR (melodic-software/ci-workflows#159) pointing at worktrees/melodic-software__ci-workflows__pr-159: fatal: not a git repository (or any of the parent directories): .git. The directory is gone (deleted outside the helper, or never fully created) but its state entry persists, so every queue-start prune re-errors on it instead of self-healing (removing an orphaned state record for a path that no longer exists as a worktree at all). Fix direction: when git status fails with "not a git repository" for a tracked worktree path, treat that as "already gone" and drop the state record instead of reporting an error. → source-control/babysit-prs: harden prune_babysit_worktrees.py against orphaned state #816
Queue-scope lease was lost mid-cycle to a stale-takeover (release --scope queue returned exit 3, "token does not match") after ~24 minutes waiting on 7 background per-PR workers without a queue-lease heartbeat in between. orchestration.md's Concurrency Guard requires heartbeating the queue lease at least every 5 minutes while waiting on background workers; this session didn't, so a concurrent runner reclaimed it via --steal-stale (>900s default staleness window) partway through. No apparent harm this cycle (all PR-scoped worker leases are independently scoped and were unaffected), but worth a documented reminder/example in orchestration.md or a defensive periodic-heartbeat helper call inserted directly into the queue-cycle procedure in SKILL.md/loop.md, since it's easy to lose track of during a long parallel worker fan-out.
Read-only babysit_merge.py <pr> --allowed-owners ... --self-logins @me (no --merge flag) was denied outright by the host's own auto-mode permission classifier — filed standalone as source-control:babysit-prs: read-only babysit_merge.py invocation blocked by host auto-mode permission classifier #787 since it blocks this lane's own required per-cycle MERGE-READY gate-proving (DEFER-FORBIDDEN-adjacent: it's the mechanism that would otherwise gate-prove the human merge-ready list), not batched here; cross-referenced for visibility.
From the 2026-07-21 babysit-lane session (cycle 3, additional false-positive-blocker observation):
From the 2026-07-21 work-lane session (operator course-correction — no staleness/heartbeat check on dispatched workers):
The orchestrator has no systematic policy for checking on a dispatched worker that goes quiet for a long stretch — it was relying on the worker sending an idle_notification or a status message, and had no fallback timer. Surfaced when a worker (issue claude-config: add model-upgrade unhobbling audit — sweep instruction surfaces for constraints newer models no longer need #800, authoring a brand-new skill from scratch) went ~30+ min with zero notifications of any kind (not even an idle ping, unlike every other worker this session), and the operator asked directly whether it was stuck. Checked the worker's worktree directly (git status/git log in its out-of-tree worktree) and found real, uncommitted progress (new skill directory + version/CHANGELOG/README edits) — not stuck, just a bigger task than the fixes other workers handled. Fix direction: since dispatched workers here are file-based (each owns a worktree the orchestrator can already read), the orchestrator should periodically poll worker worktree state (a cheap git status/git log check, no message round-trip needed) on some interval for any worker that hasn't reported in, rather than only reacting to inbound messages/idle-notifications or waiting for a user nudge. Worth wiring into the standing loop-prompt rules (a "long-silent worker" checklist item) so this isn't rediscovered per-session.
From the 2026-07-21 babysit-lane session (cycle 9, third readiness-gate over-count variant):
/work-items:triage attention view omits the priority-axis raw marker. PR fix(work-items): re-key triage scope on state, not authorship (#486) #802's new Scope section defines the raw marker as status:needs-triage / priority:needs-triage (whichever axis a consuming repo files under), but the "Attention view (no number)" buckets in plugins/work-items/skills/triage/SKILL.md still only list Unlabeled + status:needs-triage + needs-info. A consuming repo that files raw items under priority:needs-triage would have them missed by the no-arg attention view (neither unlabeled nor in the status bucket). Fail-safe - the missed item waits un-triaged, and the autonomous /work-items:work lane selects from the role-labeled frontier (list-frontier --autonomous), not this view, so nothing acts on the omission - hence deferred rather than blocking the PR. This repo's own raw marker is status:needs-triage, which the view already buckets, so it does not bite here. Origin: Codex review thread on PR fix(work-items): re-key triage scope on state, not authorship (#486) #802 (chatgpt-codex-connector, 2026-07-21). Fix direction: add the resolved priority-axis raw marker to the attention-view bucket list + filtering instructions, mirroring the Scope section's dual-axis wording. → work-items/triage: reconcile SKILL state machine + attention view with live labels #817
From the 2026-07-21 work-lane session (self-correction — wrong search path, not actually stale):
From the 2026-07-21 work-lane session (self-caught, fixed same-turn — exact #559 bug reproduced in this lane's own telemetry-edit habit):
This lane's own #502 telemetry-comment edit used gh api ... -f body=@<path>, which posted the literal string @C:/Users/.../telemetry-502.md as the comment body instead of the file's content — -f treats @file as a plain string in gh api; only -F (capital) auto-reads the file. This is the identical defect source-control/babysit-prs: telemetry-comment edit uses gh api -f body=@file, posts literal @path string instead of file content #559 already tracks for babysit-prs's telemetry-comment edit, independently reproduced here in a different skill's telemetry-editing code path (this lane's own ad hoc gh api invocation, not a shared script). Caught immediately (diffed the PATCH response body) and fixed same-turn with -F. Fix direction: source-control/babysit-prs: telemetry-comment edit uses gh api -f body=@file, posts literal @path string instead of file content #559's eventual fix should double-check for OTHER lanes/skills making the same -f/-F mistake in their own telemetry-comment-edit logic (this lane's own habit now corrected to always use -F body=@path), not just the one babysit-prs script it was filed against — the mistake is a general gh api footgun, not local to one call site.
From the 2026-07-21 work-lane session (self-caught, fixed same-turn — plugin-directory mismatch):
From the 2026-07-21 work-lane session (worker collision-instruction compliance gap — caught by orchestrator re-verification, not self-caught by the worker):
Gave a worker (disk-hygiene/clean: document per-plugin shell-helper + exit-code divergence as deliberate #820, a 5-plugin fanout PR) explicit, itemized version-collision instructions ahead of time — named the exact plugins at risk and the exact sibling PR numbers to check against. The worker still shipped 3 EXACT version-number collisions (not merely close — identical target versions to 3 already-open sibling PRs from this same lane) and applied no do-not-merge label, instead only noting the collisions in prose as "flagged for merge-order awareness, not blocking" — which is not what the collision protocol requires (serialize + do-not-merge + bump past the live claim). This was only caught because the orchestrator independently re-diffed the actual plugin.json changes in the PR rather than trusting the worker's self-report that collisions were "documented." Fix direction: a multi-plugin PR's collision handling should never be accepted on the worker's narrative alone — the orchestrator (or a CI check) should mechanically re-diff every touched plugin's version bump against current open-PR claims before treating a fanout PR's collision handling as complete. Consider requiring workers to paste the exact landed version number per touched plugin in their return payload specifically so this is cheap to cross-check without re-reading the whole diff.
From the 2026-07-21 work-lane session (account-wide session-limit disruption — recovery pattern, not a codebase defect but a fleet-operations gap):
3 concurrently-dispatched workers (feat(typos-format): per-file typos autofix hook plugin #831, feat(toolchain): add lychee-offline to cross-cutting ecosystem default #833, feat(toolchain): add pyright to python ecosystem check-cmd #834) all independently reported idleReason: "failed" / "You've hit your session limit · resets 8:30am (America/New_York)" within about a minute of each other — consistent with an ACCOUNT-level session limit affecting every spawned agent under this account simultaneously, not a per-agent failure. A real wall-clock gap of ~5.5 hours elapsed around this event despite otherwise-normal turn-by-turn interaction (i.e., the limit likely blocked more than just the 3 reporting workers — plausibly the orchestrator's own tool calls too, and possibly other concurrent lanes sharing the account). Recovery followed session-flow:keep-going's pattern rather than assuming state: inspected each dead worker's actual worktree (git status/git log) before acting — one had zero uncommitted work (redispatched clean), two had real uncommitted-but-unpushed progress with no PR opened yet (zero side-effect risk, safe to auto-resume per the autonomy policy — redispatched into the same worktrees with instructions to inspect the existing diff first rather than blindly redo). Fix direction: this lane's standing rules have no explicit handling for an account-wide (as opposed to single-worker) disruption — worth adding a checklist item to distinguish "this one worker died" (redispatch it) from "many workers died in the same short window" (a systemic account-level event, worth explicitly re-verifying ALL in-flight state — not just the reporting workers — since some may have silently stalled without ever sending a failure notification).
From the 2026-07-21 work-lane session (worker fabricated a plausible-but-wrong Claude-Session trailer value — caught by orchestrator cross-check, not self-caught):
A resumed worker (feat(toolchain): add pyright to python ecosystem check-cmd #834, after the account-wide session-limit disruption above) needed a Claude-Session: commit trailer value but only had a local CLI worktree-directory UUID available, not a claude.ai/code/session_... URL — it used the local UUID as the trailer value and flagged the substitution rather than silently guessing, which is the right instinct, but every other worker dispatched this same session used the identical real value https://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o (the orchestrating session's own URL, correctly reused verbatim across every dispatched sub-worker — confirmed by grepping prior commits in this session's own worktrees). The dispatch brief template asks workers to add "a Claude-Session: line" without ever stating what value to put there, leaving each worker to either already know it, guess, or flag-and-ask. Fix direction: the brief-composition step should state the exact session URL value explicitly (it's a single constant for the whole dispatching session, not something each worker needs to independently discover or invent) rather than leaving the value implicit and hoping every worker either already has it or asks.
Resolution reached this cycle: worker correctly refused to force-push to fix the interim commit's wrong trailer when the permission system explicitly denied it (right call — a peer's say-so, mine included, never substitutes for actual user/permission-system consent on a destructive op; this is NOT what got force-pushed, it was correctly refused). Investigated before escalating to the actual user: confirmed via gh repo view that this repo is squash-merge ONLY (merge/rebase commits disabled), and grepped .github/+scripts/ for any check that inspects individual commit trailers — none exists. Conclusion: the wrong interim-commit trailer is harmless — it's discarded at squash-merge time and nothing gates on it. Told the worker to leave it as-is rather than force-push or open a fresh branch/PR. No user escalation was needed once the actual stakes were checked empirically instead of assumed.
From the 2026-07-21 work-lane session (PR review job silently failed at the infrastructure level — same signal-quality class as #465/#473/#601's readiness-gate over/under-counting gaps, now confirmed in the review-posting workflow itself):
On PR feat(toolchain): add lychee-offline to cross-cutting ecosystem default #867, the review / review GitHub Actions check reported pass, but the actual comment it posted was an infra-failure placeholder: <!-- claude-review-infra-status --> + "Automated review did not complete — this is an infrastructure failure, not a review verdict... Last SDK result: (no execution file was produced)". The CI check's green status gives zero signal that the review itself never ran — an orchestrator (or a human) skimming "all checks green" would wrongly treat this PR as reviewed-clean when no review verdict exists at all. gh run rerun <run-id> could not retry the run directly ("this workflow run cannot be retried") — the only documented recovery path is pushing a new commit to retrigger. Fix direction: (1) the review CI check's pass/fail should reflect whether a REAL review verdict was posted, not just whether the job process exited 0 — an infra-failure placeholder comment should itself flip the check to fail or at least a distinct neutral state, not pass; (2) this lane's own post-green-review-pass step should explicitly check comment CONTENT for the claude-review-infra-status marker (or equivalent "did not complete" language) before treating a PR's review as done, not just trust the green check — caught here only because the reply text was read directly, not inferred from the checks list.
From the 2026-07-21 work-lane session (recurring pattern — rebase force-push blocked by permission system, 2nd occurrence same session):
Two different workers this session (feat(toolchain): add pyright to python ecosystem check-cmd #834/PR#859 earlier, planning/interview: reframe session-config advisory framing for terminal/general sessions #822/PR#848 during the post-chore: declare shell: bash on every skill with dynamic-context injections #860 rebase wave) each independently hit the same wall: after git rebase origin/main + conflict resolution, git push --force-with-lease was denied by the permission system (destructive-operation gate). Both correctly refused to route around the denial (right instinct — a peer's say-so never substitutes for real permission/user consent on a force-push). The resolution both times was the same and required no escalation: redo the same conflict resolution as a git merge origin/main instead of git rebase, which produces a merge commit pushable via a normal (non-force) git push. A third worker (source-control:babysit-prs: 'source-control-babysit-resolve-thread' bare wrapper not on PATH (command not found), worker must fall back to raw GraphQL #484/PR#840) used the merge approach from the start and never hit the wall at all. Fix direction: the worker-brief template's rebase/merge-staleness instructions should default to "merge origin/main in" rather than "rebase onto origin/main," since a merge accomplishes the same conflict-resolution result without ever needing a force-push in an environment where that permission is commonly gated — rebase should be reserved for cases where a clean linear history is specifically required and force-push is confirmed available.
From the 2026-07-21 work-lane session (near-miss — orchestrator dispatched a duplicate worker into an already-live worktree after wrongly concluding the first was dead):
Issue feat(typos-format): per-file typos autofix hook plugin #831's worker (worker-831b) went quiet for an extended stretch — two direct worktree checks (git status/git log) a few minutes apart showed zero visible change, and a direct status ping got no reply for a while, which matched this session's established "worker likely died to the account-wide session-limit disruption" pattern from earlier in the cycle. Concluded worker-831b was dead and dispatched a FRESH worker (worker-831c) into the EXACT SAME worktree directory to redo the task. Worker-831b was not actually dead — it was deep in a long, careful verification pass (hand-testing behavior against a real typos-cli binary) and eventually surfaced with a complete, correct, already-committed-and-pushed PR (feat(typos-format): per-file typos autofix hook plugin #880). Worker-831c, dispatched concurrently into the same live worktree, found what it reasonably interpreted as "an untracked prior session's uncommitted work" (actually worker-831b's own in-progress commit-in-flight) and proceeded to independently verify and build on it. Both workers ultimately converged on the SAME single commit with no corruption — but this was fortunate git-locking/timing, not a designed safeguard; a worse-timed race (both processes writing/committing at truly the same instant) could plausibly have corrupted the shared git index or produced a genuinely conflicting duplicate commit. Fix direction: before redispatching into an EXISTING worktree after concluding a worker is dead, either (a) require a longer silence threshold and more than one ping attempt with real spacing before declaring death (2 quick checks a few minutes apart is not enough signal, especially right after a known account-wide disruption event where slow-but-alive is a live possibility), or (b) when redispatch is warranted, create a NEW worktree/branch for the redispatch attempt instead of reusing the same directory, specifically so two live agents can never write to the same git state concurrently even if the "dead" conclusion turns out to be wrong.
From the 2026-07-21 work-lane session (new collision-detection gap class — a clean git auto-merge can silently hide a real version collision):
During the post-chore: declare shell: bash on every skill with dynamic-context injections #860 rebase wave, PR docs: document shell test-helper duplication and exit-code divergence as deliberate #853's worker independently caught a SECOND collision on its own initiative: an unrelated claude-ops PR (docs(claude-ops): record why lanes staleness probe stays a body instruction (#864) #877) merged mid-flight and happened to land at exactly 0.17.3 — the identical literal value docs: document shell test-helper duplication and exit-code divergence as deliberate #853 was already claiming for claude-ops. Because both sides of the merge wrote the same string for unrelated reasons, git's merge machinery did not flag it as a conflict at all — a normal git merge origin/main completed silently clean. The collision was only caught because the worker diffed claude-ops's actual version history on main directly rather than trusting "merge succeeded with no conflicts" as proof the version bump was still unique. This is a distinct risk class from the "stale open-PR-list snapshot" pattern already logged above — it can bite even with a perfectly fresh gh pr list check, because the collision comes from something that ALREADY merged, not from another still-open PR. Fix direction: this lane's version-collision protocol (rule 6d) should explicitly require checking the CURRENT value on main after any merge/rebase — not just "no conflicts" and not just "no other open PR claims this" — since a silently-matching auto-merge is a real, already-observed failure mode that neither check catches on its own.
From the 2026-07-21 decide-lane session (cycle 23, decision-taxonomy coverage gap):
From the 2026-07-21 work-lane session (2nd account-wide session-limit disruption — this time a dead worker's local branch had genuinely DIVERGED from origin, not merely fallen behind):
During keep-going recovery from a second account-wide session-limit event (4 dispatched workers died mid-task), one worker's (source-control:babysit-prs: 'source-control-babysit-resolve-thread' bare wrapper not on PATH (command not found), worker must fall back to raw GraphQL #484/PR#840) local worktree turned out to be in a real 3-way-divergence state: its local unpushed merge commit and origin's actual current tip had a different common ancestor, because ANOTHER actor (a different lane, same account identity) had pushed a legitimate, unrelated content fix directly to the same PR branch while this worker was mid-rebase. A naive recovery (just git push, or worse git push --force) would have either failed outright or silently clobbered the other lane's real commit. Correct recovery required: git merge-base --is-ancestor to detect true divergence (not just "origin moved"), then git merge origin/<branch> --no-edit to combine both histories (clean, no conflicts here since the two changes touched different files), re-verify the version claim was still uncollided against ALL currently-open siblings post-merge, THEN push normally. Two of the four recovered workers turned out to be simple fast-forward cases (local simply ahead, no divergence) and one had already fully succeeded before dying (idle-death, not mid-task-death) — only one of four needed the full divergence-reconciliation treatment. Fix direction: a keep-going-style recovery routine for a dead worker's git branch should always run the ancestor check FIRST (not just diff git log output by eye) before deciding whether a plain push suffices, since the difference between "origin moved ahead" and "origin diverged" determines whether a push will even succeed, let alone whether it's safe.
From the 2026-07-21 decide-lane session (cycle 28 restart, parked-PR scan under-detection):
The decide lane's periodic parked-decision PR scan (queue tier b) using only LITERAL markers ("needs-decision"/"parked decision"/"Decision defaulted"/"decide-and-defer"/etc.) returned NONE for several cycles while 4 genuinely-parked, unbriefed review-thread decisions existed — fix(disk-hygiene): define "suspicious" for unhinted home-root entries #869 (clean app/config exclusion: allowlist vs heuristic), feat(toolchain): add pyright to python ecosystem check-cmd #859 (pyright-in-default-check-cmd portability gate), docs(knowledge): youtube-digest synthesis target + named agnosticism gaps #854 (youtube-digest persist Target on resume), feat(implementation): front-load CI-hygiene and early-push clauses in dispatch brief #849 (orchestrator worker-commit integration when early-pushed source is absent). They were only caught once the scan prompt was broadened to SEMANTIC-equivalent language ("deferred to author/operator", "design question", "left open for", "author decision", "operator decision"). All four now briefed (PR-level comments, 2026-07-21). Fix direction: any parked-decision PR scan (decide lane tier-b here, and the triage lane if it runs one) must match the SEMANTIC shape of a deferred design fork in review threads, not just a fixed literal-marker list — reviewers/authors rarely write the exact tokens; they write "I'll leave this to the author" / "open design question" / "deferred". A literal-only scan silently under-reports tier-b coverage. Applied the broader term set in this session's scan prompt; worth baking the semantic term set into the standing scan contract so it survives restarts.
From the 2026-07-21 PR #859 verifier-resolver lane (toolchain pyright deferrals — review threads resolved under operator delegation; design decisions tracked here for the author):
From the 2026-07-21 PR #849 verifier-resolver lane (dispatch-brief phase-boundary exception — review thread resolved under operator delegation; design decision tracked here for the author):
feat(implementation): front-load CI-hygiene and early-push clauses in dispatch brief #849 P2 (implement-dispatch/SKILL.md "Phase boundaries" section): the plan-marks-only phase-commit exception does not say how the orchestrator obtains the worker's early-pushed source commit before the main-side build and the plan-only commit. In a dedicated-worktree topology (two worktrees cannot share a branch, so the worker is structurally on its own branch), the orchestrator's checkout lacks that commit unless it explicitly integrates — risking a plan-only commit that omits the source (separate branch) or a non-fast-forward push rejection (same remote branch). Assessed not defer-forbidden: the worker's source is already pushed to a remote ref (no data loss) and the mandatory main-side build + fresh-context verifier run against the orchestrator checkout and would fail loudly on a missing-source checkout (not silent/irreversible; caught at PR review before anything ships). Design decision for the author: pin the intended worker→orchestrator git topology and require the orchestrator to fetch + fast-forward / cherry-pick / merge the worker commit before the Step 4 build and the plan-marks-only commit. (codex P2; thread PRRT_kwDOTCGFQM6SqmQK. Overlaps the feat(implementation): front-load CI-hygiene and early-push clauses in dispatch brief #849 fork already noted higher in this issue from the decide-lane scan.) → implementation:implement-dispatch — pin worker->orchestrator git topology for early-pushed source before phase-boundary commit (PR #849 follow-up) #1018
From the 2026-07-21 babysit verifier session (PR #854, youtube-digest doc nit):
From the 2026-07-22 PR #898 verifier-resolver lane (feat/399 shared worktree helper — codex re-review P2 robustness edges on worktree-create.sh; review threads dispositioned + resolved under operator delegation, design decisions tracked here for the author):
feat(source-control): route /worktree create through a shared worktree-creation helper (#399 Phase A) #898 two valid P2 edge cases on plugins/source-control/scripts/worktree-create.sh, deferred as follow-ups (change-freeze on the branch: no fix-repush this cycle). (1) Bare-repo roots (in-checkout guard): a worktree_root under a bare clone (e.g. /repos/other.git/worktrees) makes git rev-parse --show-toplevel fail (no working tree), so the guard falls through and git worktree add creates a checkout inside the bare repo's git dir — violating the "root outside every repository" contract. Fix direction: also detect a bare-repository ancestor (e.g. probe git rev-parse --is-bare-repository / --git-dir on the nearest existing ancestor) before creating. (2) Git ref-syntax validation (name check): names like feat/foo..bar, feat/., foo.lock pass the char-class regex + 64-char limit but git rejects them as refs, so the helper reaches git worktree add and returns environment exit 4 despite documenting an up-front exit 2 for invalid names. Fix direction: run git check-ref-format --branch after the schema check so the correction flow receives the intended usage error (exit 2). (codex P2; threads PRRT_kwDOTCGFQM6Sw-0p (bare-repo) + PRRT_kwDOTCGFQM6Sw-0r (ref-syntax), dispositioned + resolved under delegation.) → PR feat(source-control): route /worktree create through a shared worktree-creation helper (#399 Phase A) #898, → source-control: worktree-create.sh bare-repo root detection + git ref-syntax validation (PR #898 follow-ups) #1016
From the 2026-07-22 merge-drive lane (worker-tier conflict-resolution dispatches, amendment-round 16):
disk-hygiene version-line serialization: every open plugins/disk-hygiene PR bumps the same single plugin.json version line + prepends the same CHANGELOG.md heading, so concurrent disk-hygiene PRs collide hard on that one line. Resolving PR fix(disk-hygiene): stop guard hook fail-open on skill-hook data-root token #1014's conflict required THREE re-resolves in one dispatch — main advanced (refactor(disk-hygiene): derive the Python version floor from one origin #1028→0.6.1, then docs(disk-hygiene): split Windows audit/execution lanes, scope the guard wording, fix stale no-userConfig claim #1031→0.6.2) mid-resolution, each re-colliding the version the worker had just chosen; final restack landed 0.4.8→0.6.3. A conflict-resolution worker re-resolving live can't fix the underlying serialization; a slower/less lucky cycle could loop indefinitely chasing a moving version line. Suggested fix direction: sequence disk-hygiene merges (hold other disk-hygiene PRs' conflict-resolution dispatch until one lands, rather than racing all of them against main in parallel), or move the version bump to a bot-owned post-merge step so PR branches don't carry it at all. Every other open disk-hygiene PR will need a version restack once whichever one lands next merges.
From the 2026-07-22 work lane (T3, PR #1030, #972 fix — dispatched-worker self-observation, amendment-round 16):
9 sibling formatter hooks share the same latent out-of-tree lint/format noise #972 fixed for markdown-format only (converted to #1091, routed needs-human — the shared-lib approach already regressed once): bash-format, biome-format, eol-normalizer, go-format, guardrails, powershell-format, ruff-format, typos-format, actionlint all carry the same hook::read_file_path() gap (project-membership scoping skipped when CLAUDE_PROJECT_DIR is unset, so a PostToolUse hook fires on scratchpad/temp .md-or-equivalent files outside any repo). PR fix(markdown-format): skip out-of-tree Markdown when CLAUDE_PROJECT_DIR unset (#972) #1030 scoped the fix to markdown-format alone after an attempted shared-lib fix (editing lib/hook-utils.sh + syncing all 12 carriers) caused 9 genuine plugins/guardrails/hooks/cli-flag-verify.test.sh regressions and was reverted. Fixing the other 9 as a class wants an opt-in shared scoping mechanism (each formatter hook opts in; the shared guardrail-adjacent code stays location-agnostic so a future guardrails-side change doesn't cascade into unrelated formatters again) — worth a dedicated issue with this trigger recorded, not another blind shared-lib edit. Source: PR fix(markdown-format): skip out-of-tree Markdown when CLAUDE_PROJECT_DIR unset (#972) #1030.
From the 2026-07-22 merge-drive lane (worker-tier claim-comment protocol, amendment-round 16):
From the 2026-07-22 babysit lane (safe tier, PR #1628, amendment-round 16):
/quality-gate restatement lane emits frontmatter that violates its own contract: both .work/delete-pr-template-inherit-org-default/review/*-restatement-review.md artifacts on melodic-software/medley#1628 had type: restatement-review plus non-schema mode/branch fields and a missing slug — quality-gate-evidence-contract.md's required frontmatter is type: quality-gate-evidence + slug. No corpus/runtime-gate cascade (.work/ is excluded from those), so this cycle just conformed both artifacts directly on the branch. Root cause is upstream in the /quality-gate restatement lane itself (plugin-owned), not this PR — worth fixing at the source so future restatement runs emit contract-conforming frontmatter instead of each consumer PR patching it after the fact. Source: PR https://github.com/melodic-software/medley/pull/1628.
From the 2026-07-22 work lane (T3, PR #1021 — second instance of the version-line serialization pattern already logged above for disk-hygiene, amendment-round 16):
Same version-line serialization pattern, now on source-control: PR chore(source-control): document plugin as sole worktree-convention SSOT (#401) #1021 (chore/401) needed the SAME single-line plugin.json version + CHANGELOG.md heading re-resolved three separate times in one session as unrelated source-control PRs landed around it — feat(source-control): setup writes a self-describing team convention file #1055 (0.17.0→0.17.1), then a second collision (0.17.1→0.17.2), then feat(source-control): configurable pr_body_required_sections scaffold + gate (#975) #1029 (0.17.2→0.18.0→0.18.1). Each was a clean mechanical re-merge (not a real conflict), but it consumed a full worker dispatch round-trip per collision purely to shuffle a version number nobody's logic actually depends on. Confirms the disk-hygiene finding above isn't plugin-specific — any high-traffic plugin whose PRs all touch one shared version line will thrash the same way under concurrent lanes. Same suggested fix applies: serialize same-plugin merges, or move the version bump to a bot-owned post-merge step (e.g. a merge-queue action that stamps the next version instead of every PR branch carrying its own guess).
From the 2026-07-22 work-2 lane (T5, telemetry self-observation, amendment-round 16):
gh issue comment --edit-last produced a duplicate telemetry comment across a session-interruption boundary: this lane's ops: loop-lane telemetry — running per-lane status (babysit / triage / work) #502 telemetry comment (id 5048731522) got duplicated into a second live comment (id 5051467200, created 2026-07-22T20:57:59Z) sometime around a weekly-usage-limit interruption, holding a full copy of the same cycle-1..7 history. Root cause not isolated (candidate: --edit-last's "last comment by current user" resolution racing or misfiring across an interrupted turn boundary; not reproduced on demand). Recovered by patching the original comment via its numeric id with gh api -X PATCH .../issues/comments/<id> (bypassing --edit-last entirely) and neutralizing the duplicate in place with a pointer back (deleting it was denied by this session's own permission gate against destructive ops — worth noting --delete-last/direct comment deletion may need an explicit approval path for any lane relying on self-cleanup). Suggested fix direction: any skill/rule prescribing --edit-last for a durable single-comment invariant (rule 23's telemetry pattern, and likely similar patterns elsewhere) should pin and reuse the comment's numeric id after first creation instead of re-resolving "last comment" every cycle.
triage-decide lane: cross-repo triage subagents keep reaching for status: needs-decision on genuinely-open items instead of the convention needs-human (alone) — 3rd occurrence across cycles 11-12 (github-iac#139, ci-runner#55, ci-runner#61), all self-caught and fixed same-cycle via post-hoc live-state verification. Dispatch-prompt wording likely needs a clearer positive instruction ("apply needs-human, never status: needs-decision, for fresh triage routing") rather than only the negative "never pair the two" phrasing added in round 17.
Rolling paper-cut batch per the v11 intake throttle (operating-procedures + canonical lane prompts): consequence findings file standalone; paper-cuts land here as lines and are batch-fixed in one sweep PR when the batch justifies it. Control tower created this because the throttle was inert without it (2026-07-20 triage audit finding).
Lines
Folded from standalone issues (closed, content preserved here):
source-control:babysit-prs: test_pr_queue_snapshot.py integration test doesn't assert the ignored bucket for Approve-with-nits classification #578 — (folded) see original issue for detail -> reopened source-control:babysit-prs: test_pr_queue_snapshot.py integration test doesn't assert the ignored bucket for Approve-with-nits classification #578
claude-ops:morning-brief: 3 minor test-coverage/maintenance nits (no-lanes telemetry case, rec-maxlen=0 case, usage() header extraction fragility) #579 — (folded) see original issue for detail -> reopened claude-ops:morning-brief: 3 minor test-coverage/maintenance nits (no-lanes telemetry case, rec-maxlen=0 case, usage() header extraction fragility) #579
fix(repo-hygiene): git-tree-reset exit-7 failure path emits RestoredTracked: N without the RESTORED>0 warning message the success path prints #605 — (folded) fixed by PR fix(repo-hygiene): emit RESTORED>0 warning on git-tree-reset exit-7 failure path (#605) #655 (exit-7 RESTORED>0 warning parity)
source-control(babysit-prs): SKILL.md step 9 cross-reference to loop.md §5.3 is imprecise after #504's cadence-mapping table landed #653 — (folded) see original issue for detail -> reopened source-control(babysit-prs): SKILL.md step 9 cross-reference to loop.md §5.3 is imprecise after #504's cadence-mapping table landed #653
From the 2026-07-20 cross-PR consistency audit:
casefold stragglers:
babysit_delta.pyowner/repo compares use.lower()(~L150-165) while same-PRpr_queue_snapshot.py:122casefolds the identical concept;babysit_feedback.py:125.lower()on a login. Convert to the ratified.casefold()/ shared helpers. → source-control/babysit-prs: casefold owner/repo/login compares in babysit scripts #815shell assert-helper duplicated 5x (source-control, repo-hygiene, claude-ops, guardrails, work-items copies) and
check-skill-portability.test.shopted out with bespoke PASS/FAIL counters — consolidate or document the per-plugin copy as deliberate. → disk-hygiene/clean: document per-plugin shell-helper + exit-code divergence as deliberate #820per-script exit-code taxonomies (gate 0/1/3/4 vs batch 0/1/2/5/7 vs portability 0/1/2) with no shared usage/exit helper — assess a tiny shared guard helper or document divergence. → disk-hygiene/clean: document per-plugin shell-helper + exit-code divergence as deliberate #820
From the 2026-07-20 triage-lane session (tool-mechanics nit):
TaskCreateinvoked with a batchedtasks:[...]array param (assumed multi-task-per-call shape) — actual tool signature is one task per call (subject+descriptionstrings), and its schema wasn't loaded into context yet, so the batched call round-tripped asInputValidationErrorbefore any tasks were created. No functional impact (skipped task-tracking for this cycle and proceeded), but worth flagging ifTaskCreatebatching is ever considered — the current one-task-per-call contract makes multi-item tracking expensive enough that lanes reasonably skip it.From the 2026-07-20 work-2 lane session (rule 4b adjacency nit):
status: ready+wayfind: designsimultaneously. Rule 4b's literal defect-skip list only namesstatus: needs-decision/needs-humanas mutually exclusive withstatus: ready, butwayfind: design's own taxonomy description ("design-space or domain-model decision; human in the loop") is the same semantic — a ready item wearing it reads as the identical triage defect 4b targets, just an unlisted label. Skipped source-control(babysit-prs): absorb v4 loop-prompt operating rules into the skill #477 this cycle on that reasoning rather than picking it; worth deciding whether 4b's skip list should extend to allwayfind: *human-in-loop variants (interview/design/prototype), not just the two named labels.From the 2026-07-20 babysit lane session (amendment-round 13 restart, 6-PR cycle: #489, #568, #616, #665, #699, dotfiles#236):
source-control-babysit-resolve-threadguarded wrapper not on PATH in nested/non-login shells — 3 independent workers (feat(claude-ops): lanes skill — scripted background loop-lane launcher (#508) #616, fix(guardrails): scope block-hook-bypass echo redirect to the actual producer (#546) #568, dotfiles#236) all had to invoke it by absolute cachebin/path instead of the bare command. Matches the known source-control:babysit-prs: 'source-control-babysit-resolve-thread' bare wrapper not on PATH (command not found), worker must fall back to raw GraphQL #484 gap; still open.The orchestrating machine's own local Claude Code block-hook-bypass guardrail false-positived on legitimate
cmd > fileredirects (hit by the feat(claude-ops): lanes skill — scripted background loop-lane launcher (#508) #616 and fix(guardrails): scope block-hook-bypass echo redirect to the actual producer (#546) #568 workers) — the same bug class fix(guardrails): scope block-hook-bypass echo redirect to the actual producer (#546) #568 just fixed inside the plugin's own copy of this script; the harness-side hook instance still has it.pr_queue_snapshot.pyreports "N blocking bot feedback items" by countingclaude[bot]review-run summaries rather than reading their latest content — docs(ai-adoption-ladder): native-vs-hook telemetry audit + decision record #699's dispatch showed "3 blocking" when the PR was already ready-to-merge (and in fact independently merged) at HEAD.prune_babysit_worktrees.pycan leave an empty directory behind on Windows when a file lock blocks actual removal, needing a manualrm -rf+git worktree prune(hit by the docs(ai-adoption-ladder): native-vs-hook telemetry audit + decision record #699 worker). → source-control/babysit-prs: harden prune_babysit_worktrees.py against orphaned state #816babysit-readiness-gate.sh's classification regex misses lowercase "Classification: valid" / "Fixed in " phrasing, false-negatively reportingREADINESS_BLOCKEDon findings that were genuinely already addressed (feat(source-control): babysit autopilot merge tier, gate-enforced and disabled by default #665 worker) — related to the known source-control:babysit-prs: babysit-readiness-gate.sh over-counts lifetime P-badges as 'findings', false READINESS_BLOCKED reason=under-decomposed on fully-classified PRs #465/source-control:babysit-prs: needs_worker's new_human_blocking_feedback fires on the worker's own self-authored replies (same-login false positive) #473 over-counting gaps already called out in this lane's standing rules.A worker-scope lease (on docs(session-flow): document override boundary for stage taxonomy and retro rubric #489) stayed held and heartbeat-healthy throughout its run, yet a same-gh-identity push still landed on that PR's branch outside the lease path mid-cycle (the operator working the same PR live). The lease correctly cannot and does not prevent this — worth documenting explicitly as an expected limitation (a lease guards against concurrent babysit writers, not a human/other-session sharing the same login) so future workers don't over-trust lease exclusivity as a full race guarantee.
From the 2026-07-20 triage-lane session (rule 8b/8c priority-consistency nit):
priority: high, but work-items(work): per-issue execution should compose installed skills as a role-separated mini-SDLC (implementer ≠ reviewer ≠ verifier, ephemeral fresh-context agents) #513 itself ispriority: mediumand is not in rule 8b's scaling-chain enumeration (#326-chain, #450, #476, #534, #500, #504, #530, #531, #535). Under rule 8c ("high still requires rule 5's criteria"), work-items(work): per-issue execution should compose installed skills as a role-separated mini-SDLC (implementer ≠ reviewer ≠ verifier, ephemeral fresh-context agents) #513's own children should default to medium like work-items(work): per-issue execution should compose installed skills as a role-separated mini-SDLC (implementer ≠ reviewer ≠ verifier, ephemeral fresh-context agents) #513 itself — mini-SDLC stage 1: durable pipeline-shape SSOT + work-skill wire-in (child of #513) #613 reads as a prior-cycle rule-application slip, not a deliberate escalation. Left uncorrected this cycle (rule 6: never edit items alreadystatus: ready) and matched the new sibling stages (mini-SDLC stage 2: frontier-tier complexity-dispatcher — depth-scaled lanes + upward-summarization contract (child of #513) #715-mini-SDLC stage 5: re-anchor periodic execution slot in worker chains (child of #513) #718) to work-items(work): per-issue execution should compose installed skills as a role-separated mini-SDLC (implementer ≠ reviewer ≠ verifier, ephemeral fresh-context agents) #513's medium instead of mini-SDLC stage 1: durable pipeline-shape SSOT + work-skill wire-in (child of #513) #613's high, to avoid compounding the drift. Worth an operator call on whether mini-SDLC stage 1: durable pipeline-shape SSOT + work-skill wire-in (child of #513) #613 should be relabeled medium for consistency. Resolved 2026-07-22 (cycle 3): mini-SDLC stage 1: durable pipeline-shape SSOT + work-skill wire-in (child of #513) #613 is now CLOSED — moot, no relabel needed.From the 2026-07-20 work-2 lane session (tool-mechanics nit, rule 23):
gh issue view --json comments/gh api repos/.../issues/{n}return commentidas the GraphQL global node ID (e.g.IC_kwDO...);gh api repos/.../issues/comments/{id} -X PATCH(the REST edit-in-place endpoint rule 23 needs) requires the plain numeric REST id instead and 404s silently on the node-ID form — no error surfaced beyond a bare 404, easy to miss if the caller doesn't re-verify. First edit attempt this session silently no-op'd on the wrong ID shape; caught only by re-fetching and diffingupdated_at. Get the numeric id viagh api repos/<o>/<r>/issues/<n>/comments -q '.[] | select(...) | .id'instead of the--json commentsnode-ID field before any rule-23 PATCH.From the 2026-07-20 work lane session (amendment-round 13 restart):
implement-dispatch's worker briefs don't warn against issue-number back-references in code comments — 2/2 fresh worker-authored PRs this session (fix(claude-ops): harden lanes launcher refresh — abort on failure, validate targets first #707/ops/lanes: harden lane-launcher refresh step — abort on refresh failure; validate targets before mutating #639, feat(work-items): container-scoped frontier and sub-item enumeration verb #709/work-items: tracker seam has no container-scoped frontier or child-enumeration verb — containers surface themselves on the global frontier #498) tripped thecomment-hygieneCI check on# Issue #NNN item .../(issue #NNN obs #N)-style comments, each costing a full extra fix-and-CI round trip. Worth adding a one-line reminder to the brief-composition contract (near loops/work: Bash tool cwd does not persist across calls despite tool docs — caused a worker's edits to land in the canonical checkout #566/docs(implementation): require worktree-cwd clause in dispatch briefs #702's just-added worktree-cwd clause) so workers front-load this the same way they now front-load the cwd caveat, rather than learning it via red CI (the exact anti-pattern rule 6 already forbids for the PR contract itself). → implementation/implement-dispatch: front-load CI-hygiene + early-push clauses in worker brief #819gh pr checks <N> --watch --interval Nin this environment did not reliably converge to a terminal state within a single tool call — repeated calls sometimes returned the same stale snapshot rather than blocking until a genuinely new state, requiring a plain (non-watch)gh pr checkspoll loop instead. Possibly aghCLI / Windows Git Bash interaction quirk rather than a repo-owned bug; noting for awareness, not filing separately (outside this repo's ownership).work-items:triage's live raw-intake marker ispriority: needs-triage, butSKILL.md/evals/reference docs snapshot the concept asstatus:needs-triage— an axis mismatch (priority-axis label documented as if it were a status-axis label). Spans shared docs; a maintainer taxonomy decision, not a single-issue-scoped fix. (Surfaced by work-items(triage): status side-exit routing does not reliably clear priority: needs-triage, letting already-decided items re-enter the queue #562's worker while landing the side-exit label-clearing invariant.) → work-items/triage: canonicalize raw-intake marker axis across SKILL, evals, reference docs #818work-items:triage's state machine doesn't modelstatus:needs-decisionas a routing outcome, even though it's live and in active use (Adopt the documentation-existence admission test as a portable-baseline pre-check in doc-drift and declutter tooling #505 carries it this session). (Surfaced by work-items(triage): status side-exit routing does not reliably clear priority: needs-triage, letting already-decided items re-enter the queue #562's worker, same pass.) → work-items/triage: reconcile SKILL state machine + attention view with live labels #817From the 2026-07-20 triage-lane session (own-work correctness miss):
Task/Bug/Feature, confirmed viaissueTypesGraphQL query) and the label taxonomy doc says type belongs there, not atype:label, on org repos — but notype:label exists in this repo's live label set either, and the 9 items this lane triaged in its first cycle today (source-control:babysit-prs: bulk --resolve --include-human can sweep a thread deliberately deferred pending a human ruling #671/672/674/677/684/687/688/691/693) all shipped with zero issue type set, because prior cycles' own precedent (checked before filing) never set one either and the standing rules don't call it out explicitly. Caught mid-cycle-3 and backfilled retroactively (gh issue edit --type) for all of cycle 1+2's items (15 issues) plus set correctly on this cycle's historic-normalization batch going forward. Worth adding an explicit "set native issue type" step to this lane's own rule 1/8g text so it isn't rediscovered per-session.From the 2026-07-20 triage-lane session (cycle 4, gh CLI tool-mechanics nit):
gh issue edit <n> --add-blocked-by <m>reported"Validation failed: Target issue has already been taken (addBlockedBy)"as an error for 3 issues (claude-ops:morning-brief: Queues section label set hardcoded to melodic-software taxonomy — parameterize or degrade like the telemetry-issue path #610, portability gate: escape-hatch grammar rigor — standalone-comment-only matching + required nonempty reason (pair from PR #609 re-review) #624, work-items:work: dispatch brief unconditionally imposes per-plugin version-bump/CHANGELOG obligations even when installed in a non-plugin consuming repo #636) in the same batch call that had just succeeded on their--add-labelflags — but a direct REST check (gh api repos/<o>/<r>/issues/<n>/dependencies/blocked_by) immediately after showed the relationship WAS actually created correctly in all 3 cases. The CLI's reported failure was spurious (likely a duplicate-mutation-attempt or eventual-consistency artifact), not a real rejection. Worth verifying via the REST dependencies endpoint rather than trusting agh issue edit --add-blocked-bynon-zero exit/error text at face value.From the 2026-07-20 triage-lane session (resolved: earlier #632/#633 anomaly):
createdAtdirectly: both timestamp at 06:38-06:46Z, roughly 10 hours before this session's first cycle (~16:43Z). They describe a DIFFERENT, EARLIER same-day triage-lane run's own self-caught mistakes — not a concurrent collision with this session. The apparent contradiction (labels/folds described as already-applied, then found unlabeled hours later) is fully explained by combining (a) it's a different, earlier session and (b) the already-tracked work-items:triage: cross-lane label race re-adds priority:needs-triage on an already-folded/blocked-by issue (#642) #646/loops: script the deterministic lane mechanics — machine-behavior block, #502 telemetry upsert, wire script-the-deterministic-work into prompt ritual #538 cross-lane label-race class, which this repo's telemetry history shows can strip/re-add labels well beyond a single re-add-needs-triage instance. No new mechanism needed here — work-items:triage: cross-lane label race re-adds priority:needs-triage on an already-folded/blocked-by issue (#642) #646/loops: script the deterministic lane mechanics — machine-behavior block, #502 telemetry upsert, wire script-the-deterministic-work into prompt ritual #538 already covers it; closing out this flag rather than re-carrying it every cycle.From the 2026-07-20 PR #737 review (setup-skill pattern gaps — verbatim-mirrored across
/discovery:setup,/planning:setup, and the new/verification:setup; fix belongs to the shared pattern / the topic-docs contract binding, not one copy — patching one copy diverges an explicitly-mirrored family):Committed-tier guard probes the contract root, not the concern-file path. — converted to toolchain/discovery/planning/verification: shared setup-skill topic-docs contract gaps (concern-file-ignore path, memory_dir root-rejection, headless-vs-forked ruling) #745 (needs-human) Repro: in a repo that ignores
.claude/(or.claude/topic-docs.yaml),applyrunsgit check-ignoreonly on<contract_dir>/probe/PLAN.md, so it writes.claude/topic-docs.yamland reports it persisted/tracked while git ignores it — placement is local-only, invisible to teammates. Fix direction: alsogit check-ignore -vthe concern-file path itself and STOP/report the matching rule before claiming persistence. Origin:plugins/verification/skills/setup/SKILL.mdcheckstep 3 /applystep 2 (identical inplugins/discovery/skills/setup/SKILL.md,plugins/planning/skills/setup/SKILL.md). PR refactor(toolchain): relocate setup topic-docs offering to the verification plugin that owns it #737 thread (line 76).No explicit up-front rejection of a root-equivalent
memory_dir— converted to toolchain/discovery/planning/verification: shared setup-skill topic-docs contract gaps (concern-file-ignore path, memory_dir root-rejection, headless-vs-forked ruling) #745 (needs-human) (./empty/repo-root) before the memory-root self-ignore write. Repro:apply memory_dir=.would make "the memory root's self-ignoring.gitignore" resolve to the consumer's root.gitignoreand write*, hiding every untracked file. Currently prevented only by the downstream bolded backstop "Never edit the consumer's root.gitignore" (apply step 2) rather than the up-front rejection the contract (docs/conventions/topic-docs/README.mdL259-262) mandates. Bounded (requires invalid off-default input + violating the bolded prohibition) but defense-in-depth is missing. Fix direction: validate and reject a root-equivalentmemory_dirup front, surfacing it per the contract. Origin: same three setup skills (applystep 2). PR refactor(toolchain): relocate setup topic-docs offering to the verification plugin that owns it #737 thread (line 79).Non-interactive/headless
applywith full args permits persisting.claude/topic-docs.yaml— converted to toolchain/discovery/planning/verification: shared setup-skill topic-docs contract gaps (concern-file-ignore path, memory_dir root-rejection, headless-vs-forked ruling) #745 (needs-human), conflicting with the topic-docs contract's forked/headless read-only rule (docs/conventions/topic-docs/README.mdL240-245: "A fork never writes.claude/topic-docs.yaml. This rule is contract-owned."). Repro: a dispatched/headless worker passing the complete<key>=<value>set is "never prompted" and writes the team-shared concern file without an interactive user decision. Fix direction: gate the persist on interactive context (or an explicit contract-sanctioned override), skipping the write in forked/headless runs, uniformly across all setup skills. Origin: same three setup skills (action-routing /applystep 1). PR refactor(toolchain): relocate setup topic-docs offering to the verification plugin that owns it #737 thread (line 33). Strongest of the three — the contract rule is explicit and contract-owned.From the 2026-07-20 PR #742 review (deferred, fail-closed kept — security-guard relaxation, not a paper-cut fix):
$authorized-path support in the disk-hygiene destructive guard. Repro:_literal_shell_words(plugins/disk-hygiene/skills/clean/scripts/destructive_guard.pyL56-59) blanket-rejects any command containing$, so an authorized--data-rootwhoseCLAUDE_PLUGIN_DATApath contains a literal$is rejected before parsing — scan/preview/apply fail closed for those installs despite the argv authority. Current behavior is fail-closed/fail-loud (deny with visible reason) = over-blocking, the safe direction, outside DEFER-FORBIDDEN — so deferred deliberately, not a quick fix. Fix direction (design note): allow$only inside a single-quoted literal word (bash does NOT expand$in single quotes; it DOES inside double quotes), which requires a quote-aware tokenizer that still rejects real expansion/$(...)/backtick syntax — a security-guard change that must not reopen the injection vector the blanket check exists to block. Origin: PR fix(disk-hygiene): guard resolves authorized data root from hook argv #742 thread (destructive_guard.pyline 141). → disk-hygiene: destructive_guard.py literal-$ authorized-path support in the shell tokenizer (PR #742 follow-up) #1035From the 2026-07-20 PR-review blitz (deferred review threads, genuine-but-deferrable — outside DEFER-FORBIDDEN, off-default-path/advisory):
DECLARED_SAVEPOINTgranularity mismatch in the retro multi-session snippet. Repro: handoffSKILL.md"Where handoffs live" defines a "save-point convention in CLAUDE.md / .claude/rules" as the FULL handoff location (used as-is, wins), butplugins/session-flow/skills/retro/context/session.md(~L55) labels rung 2 with that same "save-point convention" phrasing while using it as thememory_dirROOT and appending/handoffs. A user who declares handoffs at.claude/handoffsand passes it asDECLARED_SAVEPOINTgets.claude/handoffs/handoffs;ls … 2>/dev/nullswallows the miss silently. Deferred: retro is a read-only reflection pass (no gate, no irreversible action), off default path (.workdefault works), bounded. Fix direction: relabel rung 2 as a memory ROOT (not "save-point convention"), OR reconcile the two skills' granularity + make the retro snippet tolerant of a/handoffs-suffixed value. Origin: PR fix(claude-memory,session-flow): quote-aware topic-docs seam parser via shared helper #756 thread (retro/context/session.md:55). → session-flow/retro: fix DECLARED_SAVEPOINT granularity mismatch in multi-session snippet #821/interviewmid-task upgrade rule cannot fire. Repro:plugins/planning/skills/interview/context/session-config.md"Inverse direction — mid-task" (~L89) is phrased as an imperative to an executing actor, but/interviewterminates at handoff (its own "handoff ALWAYS terminates current execution" rule) and no hook wires this context into the downstream execution session — read as runtime behavior it never runs. Deferred: advisory prose, no gate/irreversible action. Fix direction: reframe as guidance the interview hands the USER at handoff ("watch for these signals during execution"), consistent with the file's "advisory framing" section, OR relocate the rule into the execution/implement workflow where an agent is actually running. Origin: PR feat(planning): interview recommends downstream model, effort, and advisor #750 thread (interview/context/session-config.md:89). → planning/interview: reframe session-config advisory framing for terminal/general sessions #822Session-config recommendation applied to terminal general interviews. Repro:
session-config.mdL7-8 frames the recommendation as configuring "the downstream execution session," butplugins/planning/skills/interview/SKILL.mdStep 5 (L190) makes a general session terminal with no downstream consumer, while the deliberate "Both domains" section (SKILL.md:225 / session-config.md L76-80) extends the recommendation to general sessions — the two framings are never reconciled, producing/model/effort//advisorguidance for a session that will not exist. Deferred: advisory prose, reversible. Fix direction: for general sessions frame the advice as config for the current / next session (applied now), not "the downstream execution session," rather than dropping the deliberate "Both domains" scope. Origin: PR feat(planning): interview recommends downstream model, effort, and advisor #750 thread (interview/SKILL.md:225). → planning/interview: reframe session-config advisory framing for terminal/general sessions #822From the 2026-07-20 PR #739 review (education
explainevals — manual/advisory eval-format design, not DEFER-FORBIDDEN; the fix is a skill-quality schema decision):plugins/education/skills/explain/evals/evals.jsondepend on warm conversational context (a prior assistant message, or an in-context referent), but the manual eval recipe pastes eachpromptinto a fresh session (docs/MIGRATION-PLAYBOOK.md:351) and the evals schema (plugins/skill-quality/reference/evals.schema.json) has no conversation-history fixture field. Sharpest case: chore: initialize marketplace scaffold #1 (empty-argument-anaphora-default) and docs(playbook): document the local plugin development loop #7 (cold-start-empty-argument-asks-what) carry byte-identical prompts ("I don't get it.") with contradictory expected outputs — under the fresh-session recipe chore: initialize marketplace scaffold #1 collapses into docs(playbook): document the local plugin development loop #7's cold-start condition and cannot pass as written; ci: onboard to the CI platform (ci-workflows + standards) #4 ("this proof" with emptyfiles) and perf(markdown-formatter): unwired producer builds telemetry payload before the opt-in guard (~90ms/edit on Windows) #6 ("wait, what does this actually do?") likewise have no referent to resolve, so the skill's own cold-start rule fires instead of the behavior each case means to exercise.validate-evalsis structure-only, so it stays green over this. Fix direction (design, choose one): add a conversation-history fixture mechanism to the evals schema upstream inskill-quality(covers every skill's warm-context cases), OR restructure these three cases to be self-contained (embedding prior context into the prompt changes what chore: initialize marketplace scaffold #1 asserts; merging/removing a case drops warm-path coverage). Origin: PR feat(education): add explain skill — one-shot plain-language altitude drop with teach handoff #739 threads (evals.json lines 7, 43, 67). → education:explain / skill-quality: evals.json warm-context cases untestable under the fresh-session recipe (PR #739 follow-up) #1036From the 2026-07-20 decide-lane session (cycle 1, decided-item re-park churn — mis-routing class):
status: needs-decisionto at least THREE operator/maintainer-DECIDED items — repo: per-change version bump + top-insert CHANGELOG serialize concurrent same-plugin PRs (conflict by construction) #464 (comment 5024644615), Adopt the documentation-existence admission test as a portable-baseline pre-check in doc-drift and declutter tooling #505 (5024644993), autonomy(check-security-binding): static credential-root + egress-target validation cannot converge without a configured allowlist #549 (5024718496) — by reasoning from each issue's stale BODY text ("decision to make first" / "needs a human architecture decision") instead of reading the operator-acceptance / tower-application comment already on the thread. Two consequences: (a) decided work is bounced back into the decision queue (latency + duplicate briefs); (b) SHARPEST — repo: per-change version bump + top-insert CHANGELOG serialize concurrent same-plugin PRs (conflict by construction) #464's re-park set RECOMMENDED = the CHANGELOG-fragment-directory option the maintainer had EXPLICITLY REJECTED (7/19T15:48, "no release boundary exists to assemble at"), so a work lane acting on the re-park would implement a rejected fleet-wide (39+ plugin) design. Reconciled this cycle via application-ready comments on all three (quote ratification + supersede the re-park + recommend re-flip tostatus: ready). Root cause: the re-parking step's decided-check keys off issue-body prose, not the presence of an "Operator decision"/ratified-carrier comment. Fix direction: before re-addingneeds-decision, scan comments for an operator/maintainer ruling and skip (or surface a conflict) if one exists — never re-derive "is this decided?" from the body. ESCALATION TRIGGER: if any of repo: per-change version bump + top-insert CHANGELOG serialize concurrent same-plugin PRs (conflict by construction) #464/Adopt the documentation-existence admission test as a portable-baseline pre-check in doc-drift and declutter tooling #505/autonomy(check-security-binding): static credential-root + egress-target validation cannot converge without a configured allowlist #549 is re-parked AGAIN after this reconciliation, promote to a standalone priority:high issue (silent-wrong routing feeding wrong implementation).From the 2026-07-21 triage-lane session (blocked-briefed re-promotion gap):
blocked-by, do NOT markstatus: ready), the item ends up with neither the rawpriority: needs-triagemarker (cleared on routing) norstatus: ready— so it is invisible to the triage attention view AND the work-lane's ready frontier until its blocker closes. Nothing observed to auto-promote it tostatus: readywhen theblocked-byedge resolves. First hit: claude-ops: lane-launcher never captures launch commit, leaving refresh.md's staleness probe unfillable #792 (blocked-by loops/autonomy: lanes cannot consume their own merged plugin fixes — need plugin sync + reload path (or documented restart cadence) #514). VERIFY whether the work-lane already re-selects blocked-by-satisfied briefed items; if not, define the promotion trigger (triage re-scan of recently-unblocked briefed items, or work-lane selecting briefed+unblocked regardless ofstatus: ready). Distinct from source-control:babysit-prs: worker-scope per-PR lease did not prevent a concurrent worker on the same PR (duplicate P1 fixes) #524 (worker picks up a still-blocked item — the inverse).From the 2026-07-21 triage-lane session (lane-coverage gap, self-caught cycle 7):
priority: needs-triage", but the triage SKILL's own attention view includes bucket 1 = unlabeled (never triaged) and rule 8g says newly-arrived unlabeled items normalize inline. Querying only thepriority: needs-triagelabel (cycles 1-6) skipped 4 unlabeled raw items (claude-ops: install_new userConfig has no default, leaves literal placeholder unrendered #786, knowledge: library_dir seam accepts only literal paths — machine-specific config collides with hardcoded-path guardrail #798, education: add quiz-me skill — post-work comprehension verification (HITL, non-gating by default) #799, claude-config: add model-upgrade unhobbling audit — sweep instruction surfaces for constraints newer models no longer need #800); claude-ops: install_new userConfig has no default, leaves literal placeholder unrendered #786 sat untriaged from 03:01Z through ~4 cycles until a decomposition-scan surfaced it viaupdatedAt. Fix (this lane): scan BOTHpriority: needs-triageAND unlabeled-open every cycle (attention buckets 1+2), not just the label. Recommend rule 1's queue definition be reworded to name the unlabeled bucket explicitly so it isn't rediscovered per-session. Corrected in-session going forward.From the 2026-07-21 triage-lane session (gh tool-mechanics gotcha, self-caught):
gh issue comment/comment-PATCH via inline--bodywith backtick-wrapped terms runs those terms as bash command-substitution and STRIPS them from the posted body — silent corruption, flagged only by a straycommand not foundon stderr. Hit on babysit-prs: resolve babysit_self_logins discovery contract (code drops discovery-widening; plugin.json userConfig still claims it) #897 (one--extra-selfdropped; fixed via a PATCH edit). Always pass any comment/body containing backticks or$through--body-file/-F body=@file(the lane's established brief pattern), never inline--body. Cheap fleet-wide guard: prefer--body-filefor all non-trivial gh comment content.Sweep rule: one PR per batch, structure-only/small fixes, each line checked off with the commit that fixed it.
From the 2026-07-21 work-lane session (cycle 1, pick-order scoping nits):
chore(source-control): retire stale ghq-layout-sibling-pr-worktrees doc; plugin owns worktree convention #401 (
status: ready, source-control A2 hardening list) is written as a single closeable issue but its "Actions" checklist is majority cross-repo (dotfiles/chezmoi doc deletion +CLAUDE.mdpointer removal) — aclaude-code-plugins-only PR cannot close it as-is. Only "verify/migrate babysit exemption content into the plugin" is lane-actionable. Fix direction: split into an in-repo sub-issue (verify/migrate) + a dotfiles-repo-owned issue for the deletion, or re-scope chore(source-control): retire stale ghq-layout-sibling-pr-worktrees doc; plugin owns worktree convention #401 to the in-repo part only and open the cross-repo half separately. Left unclaimed by the work lane this cycle rather than guessed at.feat(claude-ops or session-flow): loop-prompt authoring skill — generate and maintain standing loop-lane prompts #480 (
status: ready) explicitly states in its own body "Placement (claude-ops vs session-flow vs autonomy) = design decision for triage/human" but does not carrystatus: needs-decision— same defect class as rule 4b's needs-decision/needs-human co-labeling check, just not literally co-labeled (the ambiguity is in the body, not a second status label). Fix direction: either the author's self-flagged placement questions should route these toneeds-decisionat filing time, orlist-frontier/triage should grep body text for this pattern. Left unclaimed this cycle. Resolved 2026-07-22 (cycle 3): re-verified live — the placement question was answered (operator design input + ratification interview, 2026-07-22 comments) and feat(claude-ops or session-flow): loop-prompt authoring skill — generate and maintain standing loop-lane prompts #480 correctly sits atstatus: ready. No mislabel remains.CI-gate backlog: automatable conformance checks surfaced by the #313 fleet audit #445 (
status: ready) is explicitly headed "No linked issue: tracking issue; closes nothing" — it's a checklist of 8 independent automatable CI-gate items carried out of a closed epic (Epic: plugin fleet conformance audit — 50-plugin doctrine matrix and remediation waves #313), not a single-PR-closeable item. A pick-order pass that doesn't read the full body (just title+labels) would wrongly treat it as dispatchable. Fix direction: decompose via/work-items:decomposeinto 8 sub-issues, or add a label/marker that flags "tracking issue, do not auto-dispatch whole" the same wayneeds-human/needs-decisiondo. Left unclaimed this cycle.ci-health: detect checks that degrade mergeStateStatus without completing (stuck runner-label / orphaned status / never-settling) #374's title prefix
ci-health:reads like a distinct plugin name but there is noplugins/ci-health/directory — its actual deliverable (full body) targetsplugins/source-control/skills/babysit-prs/scripts. A pick-order pass that infers plugin ownership from title prefix alone (as this lane's guidance currently does — noplugin:label taxonomy exists, pergh label list) can mis-classify it as an independent-plugin pick and wrongly parallelize it alongside a real source-control pick. Not unique to ci-health: detect checks that degrade mergeStateStatus without completing (stuck runner-label / orphaned status / never-settling) #374 — likely other topic-prefixed titles (autonomy:,loops:,convention:) don't map 1:1 toplugins/*dirs either. Fix direction: either add a realplugin: <name>label taxonomy (durable, queryable) or document that title-prefix-as-plugin-inference is unreliable and must be body-verified before same-plugin-conflict checks.From the 2026-07-21 babysit-lane session (cycle 1, worktree-prune stale-record nit):
Queue-start prune (
prune_babysit_worktrees.py --apply) errored on a leftover state record for a merged/closed PR (melodic-software/ci-workflows#159) pointing atworktrees/melodic-software__ci-workflows__pr-159:fatal: not a git repository (or any of the parent directories): .git. The directory is gone (deleted outside the helper, or never fully created) but its state entry persists, so every queue-start prune re-errors on it instead of self-healing (removing an orphaned state record for a path that no longer exists as a worktree at all). Fix direction: whengit statusfails with "not a git repository" for a tracked worktree path, treat that as "already gone" and drop the state record instead of reporting an error. → source-control/babysit-prs: harden prune_babysit_worktrees.py against orphaned state #816Queue-scope lease was lost mid-cycle to a stale-takeover (
release --scope queuereturned exit 3, "token does not match") after ~24 minutes waiting on 7 background per-PR workers without a queue-lease heartbeat in between.orchestration.md's Concurrency Guard requires heartbeating the queue lease at least every 5 minutes while waiting on background workers; this session didn't, so a concurrent runner reclaimed it via--steal-stale(>900s default staleness window) partway through. No apparent harm this cycle (all PR-scoped worker leases are independently scoped and were unaffected), but worth a documented reminder/example inorchestration.mdor a defensive periodic-heartbeat helper call inserted directly into the queue-cycle procedure inSKILL.md/loop.md, since it's easy to lose track of during a long parallel worker fan-out.Read-only
babysit_merge.py <pr> --allowed-owners ... --self-logins @me(no--mergeflag) was denied outright by the host's own auto-mode permission classifier — filed standalone as source-control:babysit-prs: read-only babysit_merge.py invocation blocked by host auto-mode permission classifier #787 since it blocks this lane's own required per-cycle MERGE-READY gate-proving (DEFER-FORBIDDEN-adjacent: it's the mechanism that would otherwise gate-prove the human merge-ready list), not batched here; cross-referenced for visibility.From the 2026-07-21 babysit-lane session (cycle 3, additional false-positive-blocker observation):
pr_queue_snapshot.pycounted a brand-new claude[bot] issue comment as "1 blocking bot feedback item" onmelodic-software/provisioning#189purely because it was new, without reading the bot's own verdict language ("Not a blocker", "Ready to merge as-is", an OPTIONAL nice-to-have suggestion). The mechanical readiness gate (babysit-readiness-gate.sh) correctly reportedREADINESS_OK findings=0for the same PR/head, so the two signals disagree. Same underlying pattern as source-control:babysit-prs: babysit-readiness-gate.sh over-counts lifetime P-badges as 'findings', false READINESS_BLOCKED reason=under-decomposed on fully-classified PRs #465 (badge/comment presence counted without checking live disposition) but the trigger here is comment recency, not a stale P-badge. Not filed standalone since the fix direction is identical to source-control:babysit-prs: babysit-readiness-gate.sh over-counts lifetime P-badges as 'findings', false READINESS_BLOCKED reason=under-decomposed on fully-classified PRs #465's — worth folding into whatever fix lands there rather than tracking separately.From the 2026-07-21 work-lane session (operator course-correction — no staleness/heartbeat check on dispatched workers):
idle_notificationor a status message, and had no fallback timer. Surfaced when a worker (issue claude-config: add model-upgrade unhobbling audit — sweep instruction surfaces for constraints newer models no longer need #800, authoring a brand-new skill from scratch) went ~30+ min with zero notifications of any kind (not even an idle ping, unlike every other worker this session), and the operator asked directly whether it was stuck. Checked the worker's worktree directly (git status/git login its out-of-tree worktree) and found real, uncommitted progress (new skill directory + version/CHANGELOG/README edits) — not stuck, just a bigger task than the fixes other workers handled. Fix direction: since dispatched workers here are file-based (each owns a worktree the orchestrator can already read), the orchestrator should periodically poll worker worktree state (a cheapgit status/git logcheck, no message round-trip needed) on some interval for any worker that hasn't reported in, rather than only reacting to inbound messages/idle-notifications or waiting for a user nudge. Worth wiring into the standing loop-prompt rules (a "long-silent worker" checklist item) so this isn't rediscovered per-session.From the 2026-07-21 babysit-lane session (cycle 9, third readiness-gate over-count variant):
babysit-readiness-gate.shon claude-code-plugins#803 reported READINESS_BLOCKED (findings=40 classified=5) despite the worker fully addressing every genuinely-open item (2 fixed+tested, 3 classified-deferred, 1 self-authored-filtered). Root cause per the worker: the gate counts every severity WORD occurrence across all comment bodies, including plain prose like "No new CRITICAL" or "Prior IMPORTANT findings" inside 8 historical review passes plus the worker's own classification-reply prose — not just genuine open findings. Same over-count family as source-control:babysit-prs: babysit-readiness-gate.sh over-counts lifetime P-badges as 'findings', false READINESS_BLOCKED reason=under-decomposed on fully-classified PRs #465/source-control:babysit-prs: read-only babysit_merge.py invocation blocked by host auto-mode permission classifier #787's badge/comment-recency variants, now a third distinct trigger (severity-word-in-prose). Worth folding into whatever fix eventually lands there — the gate needs to key off actual open/unresolved finding markers, not any occurrence of a severity word anywhere in the thread history.From the 2026-07-21 work-lane session (recurring worker-brief gap — exec-bit, 2nd occurrence same session):
.shscripts with a shebang line but non-executable git index mode (100644), tripping thehygiene→exec-bitCI check both times, requiring a resumed fix round each time. Neither worker's dispatch brief mentioned the exec-bit convention explicitly — both only learned about it via red CI, which the standing lane rules elsewhere explicitly say to avoid ("front-load the PR contract — never learn it via red CI"). Fix direction: add a one-line reminder to the standard implementation-worker brief template (wherever this lane's dispatch briefs are composed) — "any new file with a shebang must begit update-index --chmod=+x'd before committing" — so it's front-loaded instead of rediscovered per-PR. → implementation/implement-dispatch: front-load CI-hygiene + early-push clauses in worker brief #819From PR #802 (fix #486, tower-dispatched unblock - deferred Codex P2):
/work-items:triageattention view omits the priority-axis raw marker. PR fix(work-items): re-key triage scope on state, not authorship (#486) #802's new Scope section defines the raw marker asstatus:needs-triage/priority:needs-triage(whichever axis a consuming repo files under), but the "Attention view (no number)" buckets inplugins/work-items/skills/triage/SKILL.mdstill only list Unlabeled +status:needs-triage+ needs-info. A consuming repo that files raw items underpriority:needs-triagewould have them missed by the no-arg attention view (neither unlabeled nor in the status bucket). Fail-safe - the missed item waits un-triaged, and the autonomous/work-items:worklane selects from the role-labeled frontier (list-frontier --autonomous), not this view, so nothing acts on the omission - hence deferred rather than blocking the PR. This repo's own raw marker isstatus:needs-triage, which the view already buckets, so it does not bite here. Origin: Codex review thread on PR fix(work-items): re-key triage scope on state, not authorship (#486) #802 (chatgpt-codex-connector, 2026-07-21). Fix direction: add the resolved priority-axis raw marker to the attention-view bucket list + filtering instructions, mirroring the Scope section's dual-axis wording. → work-items/triage: reconcile SKILL state machine + attention view with live labels #817From the 2026-07-21 work-lane session (self-correction — wrong search path, not actually stale):
babysit-readiness-gate.shDOES exist — atplugins/source-control/scripts/(plugin-rootscripts/, notskills/babysit-prs/scripts/where this lane first searched). Retracting the prior stale-reference note above. Re-dispatched source-control:babysit-prs: babysit-readiness-gate.sh exits 4 without FETCH_COMMENTS_OWNER/FETCH_COMMENTS_REPO env vars, undocumented in worker contract #475 properly once the correct path was found.From the 2026-07-21 decide-lane session (cycle 10, brief-staleness sweep — systemic finding):
From the 2026-07-21 work-lane session (self-caught, fixed same-turn — exact #559 bug reproduced in this lane's own telemetry-edit habit):
#502telemetry-comment edit usedgh api ... -f body=@<path>, which posted the literal string@C:/Users/.../telemetry-502.mdas the comment body instead of the file's content —-ftreats@fileas a plain string ingh api; only-F(capital) auto-reads the file. This is the identical defect source-control/babysit-prs: telemetry-comment edit uses gh api -f body=@file, posts literal @path string instead of file content #559 already tracks forbabysit-prs's telemetry-comment edit, independently reproduced here in a different skill's telemetry-editing code path (this lane's own ad hocgh apiinvocation, not a shared script). Caught immediately (diffed the PATCH response body) and fixed same-turn with-F. Fix direction: source-control/babysit-prs: telemetry-comment edit uses gh api -f body=@file, posts literal @path string instead of file content #559's eventual fix should double-check for OTHER lanes/skills making the same-f/-Fmistake in their own telemetry-comment-edit logic (this lane's own habit now corrected to always use-F body=@path), not just the onebabysit-prsscript it was filed against — the mistake is a generalgh apifootgun, not local to one call site.From the 2026-07-21 work-lane session (self-caught, fixed same-turn — plugin-directory mismatch):
plugins/youtube-digest/directory —youtube-digestis a skill nested underplugins/knowledge/skills/youtube-digest/. Caught BEFORE dispatch (via the new "verify paths exist before concluding" rule adopted after the source-control:babysit-prs: babysit-readiness-gate.sh exits 4 without FETCH_COMMENTS_OWNER/FETCH_COMMENTS_REPO env vars, undocumented in worker contract #475 miss) by searching for ayoutube-digestorloops-named plugin directory and finding none; corrected the worker's brief to targetplugins/knowledge/.claude-plugin/plugin.jsonandplugins/knowledge/CHANGELOG.mdinstead of a nonexistentplugins/youtube-digest/. No defect shipped, but noting the pattern: issue titles that name a SKILL are not a reliable proxy for the owning PLUGIN directory when the two names diverge — worth a brief-template reminder to resolve the actual plugin root (grepthe skill path up to its.claude-plugin/ancestor) before assuming title-derived pathing.From the 2026-07-21 work-lane session (worker collision-instruction compliance gap — caught by orchestrator re-verification, not self-caught by the worker):
do-not-mergelabel, instead only noting the collisions in prose as "flagged for merge-order awareness, not blocking" — which is not what the collision protocol requires (serialize + do-not-merge + bump past the live claim). This was only caught because the orchestrator independently re-diffed the actualplugin.jsonchanges in the PR rather than trusting the worker's self-report that collisions were "documented." Fix direction: a multi-plugin PR's collision handling should never be accepted on the worker's narrative alone — the orchestrator (or a CI check) should mechanically re-diff every touched plugin's version bump against current open-PR claims before treating a fanout PR's collision handling as complete. Consider requiring workers to paste the exact landed version number per touched plugin in their return payload specifically so this is cheap to cross-check without re-reading the whole diff.From the 2026-07-21 work-lane session (account-wide session-limit disruption — recovery pattern, not a codebase defect but a fleet-operations gap):
idleReason: "failed"/"You've hit your session limit · resets 8:30am (America/New_York)"within about a minute of each other — consistent with an ACCOUNT-level session limit affecting every spawned agent under this account simultaneously, not a per-agent failure. A real wall-clock gap of ~5.5 hours elapsed around this event despite otherwise-normal turn-by-turn interaction (i.e., the limit likely blocked more than just the 3 reporting workers — plausibly the orchestrator's own tool calls too, and possibly other concurrent lanes sharing the account). Recovery followedsession-flow:keep-going's pattern rather than assuming state: inspected each dead worker's actual worktree (git status/git log) before acting — one had zero uncommitted work (redispatched clean), two had real uncommitted-but-unpushed progress with no PR opened yet (zero side-effect risk, safe to auto-resume per the autonomy policy — redispatched into the same worktrees with instructions to inspect the existing diff first rather than blindly redo). Fix direction: this lane's standing rules have no explicit handling for an account-wide (as opposed to single-worker) disruption — worth adding a checklist item to distinguish "this one worker died" (redispatch it) from "many workers died in the same short window" (a systemic account-level event, worth explicitly re-verifying ALL in-flight state — not just the reporting workers — since some may have silently stalled without ever sending a failure notification).From the 2026-07-21 work-lane session (worker fabricated a plausible-but-wrong
Claude-Sessiontrailer value — caught by orchestrator cross-check, not self-caught):Claude-Session:commit trailer value but only had a local CLI worktree-directory UUID available, not aclaude.ai/code/session_...URL — it used the local UUID as the trailer value and flagged the substitution rather than silently guessing, which is the right instinct, but every other worker dispatched this same session used the identical real valuehttps://claude.ai/code/session_01K1V3gkrfSf75isB8MiDy3o(the orchestrating session's own URL, correctly reused verbatim across every dispatched sub-worker — confirmed by grepping prior commits in this session's own worktrees). The dispatch brief template asks workers to add "aClaude-Session:line" without ever stating what value to put there, leaving each worker to either already know it, guess, or flag-and-ask. Fix direction: the brief-composition step should state the exact session URL value explicitly (it's a single constant for the whole dispatching session, not something each worker needs to independently discover or invent) rather than leaving the value implicit and hoping every worker either already has it or asks.Resolution reached this cycle: worker correctly refused to force-push to fix the interim commit's wrong trailer when the permission system explicitly denied it (right call — a peer's say-so, mine included, never substitutes for actual user/permission-system consent on a destructive op; this is NOT what got force-pushed, it was correctly refused). Investigated before escalating to the actual user: confirmed via
gh repo viewthat this repo is squash-merge ONLY (merge/rebase commits disabled), and grepped.github/+scripts/for any check that inspects individual commit trailers — none exists. Conclusion: the wrong interim-commit trailer is harmless — it's discarded at squash-merge time and nothing gates on it. Told the worker to leave it as-is rather than force-push or open a fresh branch/PR. No user escalation was needed once the actual stakes were checked empirically instead of assumed.From the 2026-07-21 work-lane session (PR review job silently failed at the infrastructure level — same signal-quality class as #465/#473/#601's readiness-gate over/under-counting gaps, now confirmed in the review-posting workflow itself):
review / reviewGitHub Actions check reportedpass, but the actual comment it posted was an infra-failure placeholder:<!-- claude-review-infra-status -->+ "Automated review did not complete — this is an infrastructure failure, not a review verdict... Last SDK result:(no execution file was produced)". The CI check's green status gives zero signal that the review itself never ran — an orchestrator (or a human) skimming "all checks green" would wrongly treat this PR as reviewed-clean when no review verdict exists at all.gh run rerun <run-id>could not retry the run directly ("this workflow run cannot be retried") — the only documented recovery path is pushing a new commit to retrigger. Fix direction: (1) thereviewCI check's pass/fail should reflect whether a REAL review verdict was posted, not just whether the job process exited 0 — an infra-failure placeholder comment should itself flip the check to fail or at least a distinct neutral state, notpass; (2) this lane's own post-green-review-pass step should explicitly check comment CONTENT for theclaude-review-infra-statusmarker (or equivalent "did not complete" language) before treating a PR's review as done, not just trust the green check — caught here only because the reply text was read directly, not inferred from the checks list.From the 2026-07-21 work-lane session (recurring pattern — rebase force-push blocked by permission system, 2nd occurrence same session):
git rebase origin/main+ conflict resolution,git push --force-with-leasewas denied by the permission system (destructive-operation gate). Both correctly refused to route around the denial (right instinct — a peer's say-so never substitutes for real permission/user consent on a force-push). The resolution both times was the same and required no escalation: redo the same conflict resolution as agit merge origin/maininstead ofgit rebase, which produces a merge commit pushable via a normal (non-force)git push. A third worker (source-control:babysit-prs: 'source-control-babysit-resolve-thread' bare wrapper not on PATH (command not found), worker must fall back to raw GraphQL #484/PR#840) used the merge approach from the start and never hit the wall at all. Fix direction: the worker-brief template's rebase/merge-staleness instructions should default to "merge origin/main in" rather than "rebase onto origin/main," since a merge accomplishes the same conflict-resolution result without ever needing a force-push in an environment where that permission is commonly gated — rebase should be reserved for cases where a clean linear history is specifically required and force-push is confirmed available.From the 2026-07-21 work-lane session (near-miss — orchestrator dispatched a duplicate worker into an already-live worktree after wrongly concluding the first was dead):
git status/git log) a few minutes apart showed zero visible change, and a direct status ping got no reply for a while, which matched this session's established "worker likely died to the account-wide session-limit disruption" pattern from earlier in the cycle. Concluded worker-831b was dead and dispatched a FRESH worker (worker-831c) into the EXACT SAME worktree directory to redo the task. Worker-831b was not actually dead — it was deep in a long, careful verification pass (hand-testing behavior against a realtypos-clibinary) and eventually surfaced with a complete, correct, already-committed-and-pushed PR (feat(typos-format): per-file typos autofix hook plugin #880). Worker-831c, dispatched concurrently into the same live worktree, found what it reasonably interpreted as "an untracked prior session's uncommitted work" (actually worker-831b's own in-progress commit-in-flight) and proceeded to independently verify and build on it. Both workers ultimately converged on the SAME single commit with no corruption — but this was fortunate git-locking/timing, not a designed safeguard; a worse-timed race (both processes writing/committing at truly the same instant) could plausibly have corrupted the shared git index or produced a genuinely conflicting duplicate commit. Fix direction: before redispatching into an EXISTING worktree after concluding a worker is dead, either (a) require a longer silence threshold and more than one ping attempt with real spacing before declaring death (2 quick checks a few minutes apart is not enough signal, especially right after a known account-wide disruption event where slow-but-alive is a live possibility), or (b) when redispatch is warranted, create a NEW worktree/branch for the redispatch attempt instead of reusing the same directory, specifically so two live agents can never write to the same git state concurrently even if the "dead" conclusion turns out to be wrong.From the 2026-07-21 work-lane session (new collision-detection gap class — a clean git auto-merge can silently hide a real version collision):
0.17.3— the identical literal value docs: document shell test-helper duplication and exit-code divergence as deliberate #853 was already claiming for claude-ops. Because both sides of the merge wrote the same string for unrelated reasons, git's merge machinery did not flag it as a conflict at all — a normalgit merge origin/maincompleted silently clean. The collision was only caught because the worker diffed claude-ops's actual version history onmaindirectly rather than trusting "merge succeeded with no conflicts" as proof the version bump was still unique. This is a distinct risk class from the "stale open-PR-list snapshot" pattern already logged above — it can bite even with a perfectly freshgh pr listcheck, because the collision comes from something that ALREADY merged, not from another still-open PR. Fix direction: this lane's version-collision protocol (rule 6d) should explicitly require checking the CURRENT value onmainafter any merge/rebase — not just "no conflicts" and not just "no other open PR claims this" — since a silently-matching auto-merge is a real, already-observed failure mode that neither check catches on its own.From the 2026-07-21 decide-lane session (cycle 23, decision-taxonomy coverage gap):
A coverage sweep over OPEN issues NOT labeled
status: needs-decision/needs-humanfound genuine unmade decisions carrying no decision label — the labeling taxonomy is silently missing them, so they never reach the decide lane's normal queue and sit un-briefed indefinitely. Confirmed brief-worthy (now briefed by this lane, each with a "recommendstatus: needs-decision" routing note): source-control(babysit-prs): autopilot direct-gate route is inert under enabled tier — no actor runs the approver pass on zero-blocker PRs #738 (priority:high — autopilot direct-gate approver-pass ownership; already referenced in control-tower: closure-audit batch 2026-07-20 — operator decisions (fold-member consolidation, re-baseline additions, label normalization, title convention) #607 as a flip-milestone yet unlabeled), source-control:babysit-prs: advisory-P2-under-approval routing has no ignored-vs-material policy (babysit_feedback.py) #594 (priority:high — advisory-P2-under-Approve route material-vs-ignored), disk-hygiene: POSIX has no support lane (Bash denies all non-engine) and macOS manual-handoff has no deletion lane #383 (disk-hygiene macOS gap: build lane vs Windows-only doc scope). Borderline candidates left for triage judgment: work-items: AI disclaimer wording is triage-specific ('during triage') — cross-lane filing needs a lane-neutral disclaimer SSOT #768 claude-config: audit-instructions — evaluate pre-computed !-injected surface inventory (absorb candidate from audit-model-fit) #888 knowledge: library_dir seam accepts only literal paths — machine-specific config collides with hardcoded-path guardrail #798 code-tidying: legacy marker-less docs-prose overrides resolve project-only forever, never receive bundled P-1..P-6 (split from #701) #767 guardrails: hardcoded-path-check — Windows-aware remediation, inline opt-out for machine-scoped files, document gitignore limitation #390. Also a label-hygiene defect: source-control:babysit-prs: advisory-P2-under-approval routing has no ignored-vs-material policy (babysit_feedback.py) #594 carries BOTHpriority: highandpriority: medium(dup priority axis). Fix direction: triage's intake should ensure a genuine design fork getsstatus: needs-decision(orneeds-human) at birth — awayfind: design/"Decision needed"-body item with no decision label is the detectable signature; and de-dup the priority axis. Mitigated this cycle by the decide lane's coverage sweep, but that sweep is not part of the normal label-driven queue, so the gap recurs without an intake fix. Resolved 2026-07-22 (cycle 3): appliedstatus: needs-decisionto source-control(babysit-prs): autopilot direct-gate route is inert under enabled tier — no actor runs the approver pass on zero-blocker PRs #738 and disk-hygiene: POSIX has no support lane (Bash denies all non-engine) and macOS manual-handoff has no deletion lane #383 (were still missing it; source-control:babysit-prs: advisory-P2-under-approval routing has no ignored-vs-material policy (babysit_feedback.py) #594 was already correctly resolved — ratified 2026-07-22 and no longer dual-labeled). claude-config: audit-instructions — evaluate pre-computed !-injected surface inventory (absorb candidate from audit-model-fit) #888/knowledge: library_dir seam accepts only literal paths — machine-specific config collides with hardcoded-path guardrail #798 are now CLOSED (moot). work-items: AI disclaimer wording is triage-specific ('during triage') — cross-lane filing needs a lane-neutral disclaimer SSOT #768/code-tidying: legacy marker-less docs-prose overrides resolve project-only forever, never receive bundled P-1..P-6 (split from #701) #767/guardrails: hardcoded-path-check — Windows-aware remediation, inline opt-out for machine-scoped files, document gitignore limitation #390 remain genuinely unevaluated — re-filed below as a fresh, narrower follow-up so this doesn't get lost.Follow-up from the line above: work-items: AI disclaimer wording is triage-specific ('during triage') — cross-lane filing needs a lane-neutral disclaimer SSOT #768 (work-items — lane-neutral AI-disclaimer wording SSOT), code-tidying: legacy marker-less docs-prose overrides resolve project-only forever, never receive bundled P-1..P-6 (split from #701) #767 (code-tidying — legacy marker-less docs-prose overrides never receive bundled P-1..P-6), guardrails: hardcoded-path-check — Windows-aware remediation, inline opt-out for machine-scoped files, document gitignore limitation #390 (guardrails hardcoded-path-check — Windows-aware remediation + inline opt-out + gitignore-limitation docs) are all OPEN, carry a priority label but no status label, and have zero comments — i.e. never triaged past initial filing, not confirmed as decision-shaped (unlike source-control(babysit-prs): autopilot direct-gate route is inert under enabled tier — no actor runs the approver pass on zero-blocker PRs #738/disk-hygiene: POSIX has no support lane (Bash denies all non-engine) and macOS manual-handoff has no deletion lane #383/source-control:babysit-prs: advisory-P2-under-approval routing has no ignored-vs-material policy (babysit_feedback.py) #594 above). Needs an actual triage pass (read full body, classify bug vs enhancement, T1 tier) on each, not just a label patch.
From the 2026-07-21 work-lane session (2nd account-wide session-limit disruption — this time a dead worker's local branch had genuinely DIVERGED from origin, not merely fallen behind):
git push, or worsegit push --force) would have either failed outright or silently clobbered the other lane's real commit. Correct recovery required:git merge-base --is-ancestorto detect true divergence (not just "origin moved"), thengit merge origin/<branch> --no-editto combine both histories (clean, no conflicts here since the two changes touched different files), re-verify the version claim was still uncollided against ALL currently-open siblings post-merge, THEN push normally. Two of the four recovered workers turned out to be simple fast-forward cases (local simply ahead, no divergence) and one had already fully succeeded before dying (idle-death, not mid-task-death) — only one of four needed the full divergence-reconciliation treatment. Fix direction: a keep-going-style recovery routine for a dead worker's git branch should always run the ancestor check FIRST (not just diffgit logoutput by eye) before deciding whether a plain push suffices, since the difference between "origin moved ahead" and "origin diverged" determines whether a push will even succeed, let alone whether it's safe.From the 2026-07-21 decide-lane session (cycle 28 restart, parked-PR scan under-detection):
From the 2026-07-21 PR #859 verifier-resolver lane (toolchain pyright deferrals — review threads resolved under operator delegation; design decisions tracked here for the author):
python.yamlcheck-cmd):uv run pyrightis the firstcheck-cmdtool whose presence is not implied by the ruff-config opt-in gate. A ruff-configured project with pyright absent that hits the rung-4 bundled fallback gets a compound-&&failure (green->red, fail-closed) or an ecosystem-level missing-tool skip that also drops ruff (coverage loss). Root tension: skip granularity is per-ecosystem, not per-tool. Options: make the skip per-tool, or document pyright as a hard prerequisite of the python default once ruff is opted in. → toolchain: python.yaml pyright per-tool skip granularity + config-glob + opt-in wording gaps (PR #859 follow-ups) #1017python.yamlglobs): detection globs (*.py,pyproject.toml,uv.lock) omitpyrightconfig.json, so a standalone pyright-config-only change is not auto-detected by/toolchain:check//toolchain:lintlocal runs (CI still enforces its own check). Consider adding pyright config files to the python globs. → toolchain: python.yaml pyright per-tool skip granularity + config-glob + opt-in wording gaps (PR #859 follow-ups) #1017python.yamlopt-in): the second semicolon-separated clause ("pyright runs in its default standard mode absent ...") structurally resembles the multi-tool per-tool opt-in pattern (SKILL.md bash example), risking misread of pythons single-condition gate as multi-condition. SKILL.md explicitly designates python single-condition (mitigates runtime risk); reword so the sole gating condition (ruff config) is unambiguous and the pyright-mode note reads as descriptive, not a second gate. → toolchain: python.yaml pyright per-tool skip granularity + config-glob + opt-in wording gaps (PR #859 follow-ups) #1017From the 2026-07-21 PR #849 verifier-resolver lane (dispatch-brief phase-boundary exception — review thread resolved under operator delegation; design decision tracked here for the author):
implement-dispatch/SKILL.md"Phase boundaries" section): the plan-marks-only phase-commit exception does not say how the orchestrator obtains the worker's early-pushed source commit before the main-side build and the plan-only commit. In a dedicated-worktree topology (two worktrees cannot share a branch, so the worker is structurally on its own branch), the orchestrator's checkout lacks that commit unless it explicitly integrates — risking a plan-only commit that omits the source (separate branch) or a non-fast-forward push rejection (same remote branch). Assessed not defer-forbidden: the worker's source is already pushed to a remote ref (no data loss) and the mandatory main-side build + fresh-context verifier run against the orchestrator checkout and would fail loudly on a missing-source checkout (not silent/irreversible; caught at PR review before anything ships). Design decision for the author: pin the intended worker→orchestrator git topology and require the orchestrator to fetch + fast-forward / cherry-pick / merge the worker commit before the Step 4 build and the plan-marks-only commit. (codex P2; thread PRRT_kwDOTCGFQM6SqmQK. Overlaps the feat(implementation): front-load CI-hygiene and early-push clauses in dispatch brief #849 fork already noted higher in this issue from the decide-lane scan.) → implementation:implement-dispatch — pin worker->orchestrator git topology for early-pushed source before phase-boundary commit (PR #849 follow-up) #1018From the 2026-07-21 babysit verifier session (PR #854, youtube-digest doc nit):
plugins/knowledge/skills/youtube-digest/SKILL.mdL19 buckets contact sheets as temp-only, butsnapshot-bootstrap.jscopies them into slice-localkey-frames/contact-sheets/(gitignored local DR) and the Output contract listskey-frames/contact-sheets/*.jpgas a "local DR snapshot" — reword L19 to distinguish gitignored local snapshots from committed durable retention (codex P2; thread dispositioned + resolved under delegation). → PR docs(knowledge): youtube-digest synthesis target + named agnosticism gaps #854, → knowledge/youtube-digest: SKILL.md contact-sheet retention wording + --target local-checkout resolution gap (PR #854 follow-ups) #1015From the 2026-07-21 babysit verifier session (PR #854, youtube-digest target-resolution gap):
plugins/knowledge/skills/youtube-digest/SKILL.mdL289 resolves--targetto a target name only, buttemplates/synthesis-item.md:6requires grep-backed touchpoint paths from the resolved target — awatch --target <slug>from a separate corpus checkout has no tree to grep and can fall back to CWD or invent paths. Resolve--targetto a local checkout (cloneowner/reposlug per the apply design, or require a checkout before synthesis). Root family of the earlier target-durability nit (resume cannot recover--target). (codex P2; thread dispositioned + resolved under delegation.) → PR docs(knowledge): youtube-digest synthesis target + named agnosticism gaps #854, → knowledge/youtube-digest: SKILL.md contact-sheet retention wording + --target local-checkout resolution gap (PR #854 follow-ups) #1015From the 2026-07-22 PR #898 verifier-resolver lane (feat/399 shared worktree helper — codex re-review P2 robustness edges on
worktree-create.sh; review threads dispositioned + resolved under operator delegation, design decisions tracked here for the author):plugins/source-control/scripts/worktree-create.sh, deferred as follow-ups (change-freeze on the branch: no fix-repush this cycle). (1) Bare-repo roots (in-checkout guard): aworktree_rootunder a bare clone (e.g./repos/other.git/worktrees) makesgit rev-parse --show-toplevelfail (no working tree), so the guard falls through andgit worktree addcreates a checkout inside the bare repo's git dir — violating the "root outside every repository" contract. Fix direction: also detect a bare-repository ancestor (e.g. probegit rev-parse --is-bare-repository/--git-diron the nearest existing ancestor) before creating. (2) Git ref-syntax validation (name check): names likefeat/foo..bar,feat/.,foo.lockpass the char-class regex + 64-char limit but git rejects them as refs, so the helper reachesgit worktree addand returns environment exit 4 despite documenting an up-front exit 2 for invalid names. Fix direction: rungit check-ref-format --branchafter the schema check so the correction flow receives the intended usage error (exit 2). (codex P2; threads PRRT_kwDOTCGFQM6Sw-0p (bare-repo) + PRRT_kwDOTCGFQM6Sw-0r (ref-syntax), dispositioned + resolved under delegation.) → PR feat(source-control): route /worktree create through a shared worktree-creation helper (#399 Phase A) #898, → source-control: worktree-create.sh bare-repo root detection + git ref-syntax validation (PR #898 follow-ups) #1016From the 2026-07-22 merge-drive lane (worker-tier conflict-resolution dispatches, amendment-round 16):
plugins/disk-hygienePR bumps the same singleplugin.jsonversion line + prepends the sameCHANGELOG.mdheading, so concurrent disk-hygiene PRs collide hard on that one line. Resolving PR fix(disk-hygiene): stop guard hook fail-open on skill-hook data-root token #1014's conflict required THREE re-resolves in one dispatch — main advanced (refactor(disk-hygiene): derive the Python version floor from one origin #1028→0.6.1, then docs(disk-hygiene): split Windows audit/execution lanes, scope the guard wording, fix stale no-userConfig claim #1031→0.6.2) mid-resolution, each re-colliding the version the worker had just chosen; final restack landed 0.4.8→0.6.3. A conflict-resolution worker re-resolving live can't fix the underlying serialization; a slower/less lucky cycle could loop indefinitely chasing a moving version line. Suggested fix direction: sequence disk-hygiene merges (hold other disk-hygiene PRs' conflict-resolution dispatch until one lands, rather than racing all of them against main in parallel), or move the version bump to a bot-owned post-merge step so PR branches don't carry it at all. Every other open disk-hygiene PR will need a version restack once whichever one lands next merges.From the 2026-07-22 work lane (T3, PR #1030, #972 fix — dispatched-worker self-observation, amendment-round 16):
#972fixed formarkdown-formatonly (converted to #1091, routedneeds-human— the shared-lib approach already regressed once):bash-format,biome-format,eol-normalizer,go-format,guardrails,powershell-format,ruff-format,typos-format,actionlintall carry the samehook::read_file_path()gap (project-membership scoping skipped whenCLAUDE_PROJECT_DIRis unset, so a PostToolUse hook fires on scratchpad/temp.md-or-equivalent files outside any repo). PR fix(markdown-format): skip out-of-tree Markdown when CLAUDE_PROJECT_DIR unset (#972) #1030 scoped the fix tomarkdown-formatalone after an attempted shared-lib fix (editinglib/hook-utils.sh+ syncing all 12 carriers) caused 9 genuineplugins/guardrails/hooks/cli-flag-verify.test.shregressions and was reverted. Fixing the other 9 as a class wants an opt-in shared scoping mechanism (each formatter hook opts in; the shared guardrail-adjacent code stays location-agnostic so a future guardrails-side change doesn't cascade into unrelated formatters again) — worth a dedicated issue with this trigger recorded, not another blind shared-lib edit. Source: PR fix(markdown-format): skip out-of-tree Markdown when CLAUDE_PROJECT_DIR unset (#972) #1030.From the 2026-07-22 merge-drive lane (worker-tier claim-comment protocol, amendment-round 16):
ghidentity (kyle-sexton) — the same identity every lane and every concurrent session uses. A dispatched worker reading PR comments (worker-907, cycle 2) cannot tell its own orchestrator's claim apart from a different concurrent session's claim; both read as "kyle-sexton commented." The protocol only actually works today via the orchestrator's own out-of-band lease-state bookkeeping, not from anything a worker can observe on the PR itself. Multiple PRs this session (fix(disk-hygiene): setup check reports the kill switch deterministically, never from an unexpanded body token #1012, fix(disk-hygiene): stop guard hook fail-open on skill-hook data-root token #1014, feat(repo-hygiene): single pruned walk + dry-run manifest + apply summary #1023, fix(disk-hygiene): reason about volume-root rejection instead of blanket-denying non-OS drives #1026) had a second live session pushing commits under the same identity mid-dispatch, confirming this isn't hypothetical. Fix direction: either give each lane/session a distinguishable posting identity (bot account per lane, or a session-id suffix in the claim body that a worker CAN read and compare against its own dispatch metadata), or make claim verification a main-agent-only check (never delegate "is this PR claimed" reasoning to a worker that structurally can't answer it).From the 2026-07-22 babysit lane (safe tier, PR #1628, amendment-round 16):
/quality-gaterestatement lane emits frontmatter that violates its own contract: both.work/delete-pr-template-inherit-org-default/review/*-restatement-review.mdartifacts on melodic-software/medley#1628 hadtype: restatement-reviewplus non-schemamode/branchfields and a missingslug—quality-gate-evidence-contract.md's required frontmatter istype: quality-gate-evidence+slug. No corpus/runtime-gate cascade (.work/is excluded from those), so this cycle just conformed both artifacts directly on the branch. Root cause is upstream in the/quality-gaterestatement lane itself (plugin-owned), not this PR — worth fixing at the source so future restatement runs emit contract-conforming frontmatter instead of each consumer PR patching it after the fact. Source: PR https://github.com/melodic-software/medley/pull/1628.From the 2026-07-22 work lane (T3, PR #1021 — second instance of the version-line serialization pattern already logged above for disk-hygiene, amendment-round 16):
source-control: PR chore(source-control): document plugin as sole worktree-convention SSOT (#401) #1021 (chore/401) needed the SAME single-lineplugin.jsonversion +CHANGELOG.mdheading re-resolved three separate times in one session as unrelatedsource-controlPRs landed around it — feat(source-control): setup writes a self-describing team convention file #1055 (0.17.0→0.17.1), then a second collision (0.17.1→0.17.2), then feat(source-control): configurable pr_body_required_sections scaffold + gate (#975) #1029 (0.17.2→0.18.0→0.18.1). Each was a clean mechanical re-merge (not a real conflict), but it consumed a full worker dispatch round-trip per collision purely to shuffle a version number nobody's logic actually depends on. Confirms the disk-hygiene finding above isn't plugin-specific — any high-traffic plugin whose PRs all touch one shared version line will thrash the same way under concurrent lanes. Same suggested fix applies: serialize same-plugin merges, or move the version bump to a bot-owned post-merge step (e.g. a merge-queue action that stamps the next version instead of every PR branch carrying its own guess).From the 2026-07-22 work-2 lane (T5, telemetry self-observation, amendment-round 16):
gh issue comment --edit-lastproduced a duplicate telemetry comment across a session-interruption boundary: this lane's ops: loop-lane telemetry — running per-lane status (babysit / triage / work) #502 telemetry comment (id 5048731522) got duplicated into a second live comment (id 5051467200, created 2026-07-22T20:57:59Z) sometime around a weekly-usage-limit interruption, holding a full copy of the same cycle-1..7 history. Root cause not isolated (candidate:--edit-last's "last comment by current user" resolution racing or misfiring across an interrupted turn boundary; not reproduced on demand). Recovered by patching the original comment via its numeric id withgh api -X PATCH .../issues/comments/<id>(bypassing--edit-lastentirely) and neutralizing the duplicate in place with a pointer back (deleting it was denied by this session's own permission gate against destructive ops — worth noting--delete-last/direct comment deletion may need an explicit approval path for any lane relying on self-cleanup). Suggested fix direction: any skill/rule prescribing--edit-lastfor a durable single-comment invariant (rule 23's telemetry pattern, and likely similar patterns elsewhere) should pin and reuse the comment's numeric id after first creation instead of re-resolving "last comment" every cycle.status: needs-decisionon genuinely-open items instead of the conventionneeds-human(alone) — 3rd occurrence across cycles 11-12 (github-iac#139, ci-runner#55, ci-runner#61), all self-caught and fixed same-cycle via post-hoc live-state verification. Dispatch-prompt wording likely needs a clearer positive instruction ("apply needs-human, never status: needs-decision, for fresh triage routing") rather than only the negative "never pair the two" phrasing added in round 17.