Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions .claude/agents/quality-mgr.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,18 @@ every reply to the assigner named in the assignment, never to a fixed name.
wake-up, not a serialization rule: after handling it, list the queue again
and pick up everything else that is open.
- A task assignment is informational until `task_ready`; when it is ready, start
it with `atm task start <task-id> "<one-line plan>"`. The start event does not
close the task.
it with `atm task start <task-id> "<one-line plan>"`, then claim its matching
QA bead with `bd update <task-id> --claim`. The start
event does not close either item.
- Deliver each final verdict by closing its own task:
`atm task close <task-id> completed --template <report template> --vars
<vars file>` (the assignment names the templates). Close tasks in whatever
<vars file>` followed by `bd close <task-id>` (the
assignment names the templates). Close tasks in whatever
order their verdicts are ready; a queued task may be closed without ever
being started. A plain `atm send <lead>` leaves the task open and keeps
later assignments queued. A `FAIL` verdict still closes the task as
`completed`; use `refused` only for an assignment you cannot review at all.
later assignments queued. A `FAIL` verdict still closes the task and bead as
`completed`; use `refused` only for an assignment you cannot review at all,
leaving the bead open with `bd update <task-id> --notes "<reason>"`.

## Inputs

Expand Down Expand Up @@ -142,7 +145,7 @@ TODO-specific rule:

## Workflow

1. Start immediately with `atm task start <task-id> "<one line>"` when `task_ready` arrives, per `docs/team-protocol.md`.
1. Start immediately with `atm task start <task-id> "<one line>"` and `bd update <task-id> --claim` when `task_ready` arrives, per `docs/team-protocol.md`.
2. Validate that the task is XML rendered from the QA template. Reject any
non-XML assignment from the lead immediately.
3. Read the task payload and determine the reviewer set.
Expand Down Expand Up @@ -199,6 +202,10 @@ TODO-specific rule:
11. Report a final PASS, FAIL, or IN-FLIGHT gate to the lead, including
deliverable completion as `X/Y (Z%)`.

When reporting QA findings, preserve their stable finding ids for
`/triaging-findings`; do not create or close Beads for those findings. The lead
creates and wires the resulting fix beads.

## Default Reviewer Set

For implementation QA-1 in this Rust repo:
Expand Down Expand Up @@ -288,7 +295,7 @@ Reviewer ownership note:
All ATM messages must follow the required sequence:
1. task start
2. in-flight status when reviewer launch or collection takes time
3. final QA verdict
3. final QA verdict and `bd close <task-id>`

For PR updates:
- install the templates with
Expand Down
64 changes: 57 additions & 7 deletions .claude/skills/codex-orchestration/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,63 @@ Before starting a sprint:
9. `.claude/agents/rust-best-practices-agent.md` and
`.claude/skills/codex-orchestration/rust-best-practices-agent-assignment.json.j2`
exist for first-pass boundary optimization review.
10. Every agent pane exports `BEADS_ACTOR` equal to its `ATM_IDENTITY` (the
pane name, not an alias), and bead assignee values use those same names.

## Beads

This is the one lifecycle contract for development, fix, and QA work.

1. **Identity and dispatch.** Before dispatch, the lead creates one bead for
each task, sets its assignee to the recipient's ATM identity, and uses that
bead id everywhere: `bd update <bead-id> --assignee=<atm-identity>`;
`atm task assign --task-id <bead-id>`; and template-vars
`task_id`. Release work is a child of its release epic (`bd create --parent
<epic>`).
2. **Assignee-owned tandem lifecycle.** First self-check `[ "$BEADS_ACTOR" =
"$ATM_IDENTITY" ]`. If it fails, stop and report to the lead rather than
claiming under the shared git user. Then start with `atm task start <id>
"<plan>"` and `bd update <id> --claim`; after successful validation, close
with `atm task close <id> completed --stdin` and `bd close <id>`. A refusal
runs `atm task close <id> refused "<reason>"` and leaves the bead open with
a note (`bd update <id> --notes "<reason>"`). A push or progress report
closes neither system.
3. **Dependency-driven flow.** Before the first dispatch, the lead creates an
epic chain with `bd dep add <next> <prereq>`; each QA bead depends on its
dev bead, and merge/release beads depend on the latest QA bead. After a QA
paired close, the lead reads the verdict before running `bd ready`: on
PASS, dispatch what opens; on FAIL, first create fix child beads and QA-2,
make QA-2 depend on every fix bead, and make merge depend on QA-2 (`bd dep
add <merge> <qa-2>`). Then `bd ready` must show the fixes, not merge. A
merge bead is dispatchable only when its latest QA bead closed PASS. An
assignee views its own work with `bd ready --assignee "$ATM_IDENTITY"`; the
lead uses unfiltered `bd ready` for dispatch.
4. **QA findings and rejected work.** After `/triaging-findings`, each promoted
finding is a child bead of the epic and its id is the fix task id. For a
failed QA round, every fix bead blocks its follow-up QA bead, which in turn
blocks merge; it never tries to block the already-closed QA bead. `quality-mgr`
reports stable finding ids but does not create beads. If a lead rejects
completed work, the lead reopens its bead or creates a child bead; the lead
never closes a bead on acceptance.

## Sprint Flow

1. the lead assigns development to a developer using `dev-template.xml.j2`.
1. the lead creates and wires the dev bead, then assigns development to its
assignee using `dev-template.xml.j2` with the bead id as `task_id`.
Every dev assignment must include the sprint-plan document path as
`sprint_doc`, and that sprint document is the authoritative source for the
task. Assignment prose may summarize, but it must not replace or weaken the
sprint doc.
2. the developer starts, implements, commits, pushes, and reports branch plus SHA.
2. the developer claims the bead in tandem with task start, then implements,
commits, pushes, reports branch plus SHA, and closes both task and bead
after validation.
3. Before QA-1, the developer performs a self-directed Rust best-practices sweep on
the integration branch using the same `review_targets` planned for QA-1 and
fixes all RBP findings found there. This is a developer cleanup step, not a
QA surprise.
4. the lead opens or updates the PR.
5. the lead assigns QA to `quality-mgr` using `qa-template.xml.j2`.
5. after the dev bead closes, the lead runs `bd ready`, then assigns the
newly-ready QA bead to `quality-mgr` using `qa-template.xml.j2`.
Every QA assignment must include `sprint_doc`, and `quality-mgr` must treat
that sprint document as the authoritative QA scope source.
6. `quality-mgr` launches the full reviewer set on QA-1 (the sprint's first
Expand Down Expand Up @@ -136,13 +178,20 @@ Before starting a sprint:
triage-and-fix path. `rust-best-practices-agent`, `rust-best-practices-agent`,
and `rust-service-hardening-agent` remain part of docs-only plan review
and phase-ending review regardless of sprint round.
8. If QA passes and CI is green, merge may proceed.
9. After every QA round that reports any finding, at any severity, the lead
8. After a QA close, the lead reads the verdict before `bd ready`: PASS and
green CI permit the now-ready merge work; FAIL must not expose merge.
9. On any QA FAIL, the lead runs `/triaging-findings`, then creates a fix bead
for every promoted finding and a QA-2 bead that depends on every fix. The
merge bead depends on QA-2, so `bd ready` shows only fix work. Repeat this
rule for each failed follow-up QA round; merge becomes eligible only after
the latest QA bead closes PASS.
10. After every QA round that reports any finding, at any severity, the lead
runs `/triaging-findings` (where the repository carries that skill) the
same way: every finding is recorded, correlated
across worktrees, and promoted to the current top layer of the stack. No
finding is skipped, deferred, or left without a fix dispatch.
10. After triage completes, the lead routes concrete fixes to a developer of
11. After triage completes, the lead creates and wires finding child beads,
then routes concrete fixes to a developer of
the tier the fix needs, using `fix-assignment.xml.j2`: easy fixes go to the
fast tier for speed, not back to the sprint's developer by default. Fix assignments must also include
`sprint_doc`, and the sprint document remains authoritative if the task
Expand Down Expand Up @@ -292,4 +341,5 @@ Use the Rust assignment templates from:
The sequence for every ATM task assignment β€” start, work, task close; the
receiver never acks a close β€” is defined once in
[`docs/team-protocol.md`](../../../docs/team-protocol.md) (Required Flow).
This skill adds nothing to it and restates none of it.
The Beads lifecycle is defined in this skill's **Beads** section; templates
carry its assignee commands.
4 changes: 2 additions & 2 deletions .claude/skills/codex-orchestration/dev-template.xml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ metadata:
</references>

<workflow>
<step id="a">Start the task immediately with `atm task start {{ task_id }} "<one line: what you will do first>"`, then begin executing it in the same work session. Make reasonable assumptions and do not ask clarifying questions unless a real blocker prevents execution.</step>
<step id="a">Start the task immediately with `atm task start {{ task_id }} "<one line: what you will do first>"`, then claim the matching bead with `bd update {{ task_id }} --claim` and begin executing in the same work session. Make reasonable assumptions and do not ask clarifying questions unless a real blocker prevents execution.</step>
<step id="c">Read `{{ sprint_doc }}` before coding. Treat it as the authoritative source for scope, deliverables, deletion targets, validation, and acceptance criteria. If this assignment summary and the sprint doc differ, the sprint doc wins and the mismatch must be reported.</step>
<step id="d">Before coding, update the worktree from the sprint target branch and include prior fixes already merged to that target.</step>
<step id="d1">Honor `<dependency-relations>`: must-follow merge-forward trigger is parent dev push, not QA; merge parent β†’ child before every round. PR-completion trigger is parent PR merge first. Stop if a parallel-safe relation intersects.</step>
<step id="e">As soon as the development changes are complete and the branch is pushable, commit and push immediately. Send branch name and commit hash right away to the assigner (the sender of this message) with a plain `atm send {{ lead }} --stdin` β€” a progress report, not a close; never close the task on a push. This lets PR work and QA preparation begin in parallel. {% if cc and cc != lead %}Copy a one-line summary to `{{ cc }}` with a plain `atm send {{ cc }} --stdin`.{% endif %}</step>
<step id="f">After the push report, run the required validation and tests. Do not wait for PR creation before starting validation.</step>
<step id="g">After validation, fix findings and re-run checks until clean. Then close the task with the completion report as the body: `atm task close {{ task_id }} completed --stdin <<'EOF' … EOF` β€” the deliverable inventory and the exact gate output lines; for deletion or cleanup sprints, the before/after targeted symbol or code-path inventory (net LOC is secondary evidence). Only this close frees your queue: the next assignment stays queued and never starts until `{{ task_id }}` is closed, and a plain `atm send` report does not close it. Use `atm task close {{ task_id }} refused "<reason>"` only when the whole assignment cannot be done. {% if cc and cc != lead %}Copy a one-line summary to `{{ cc }}` with a plain `atm send {{ cc }} --stdin`.{% endif %}</step>
<step id="g">After validation, fix findings and re-run checks until clean. Then close the task with the completion report as the body: `atm task close {{ task_id }} completed --stdin <<'EOF' … EOF`, followed by `bd close {{ task_id }}` β€” the deliverable inventory and the exact gate output lines; for deletion or cleanup sprints, the before/after targeted symbol or code-path inventory (net LOC is secondary evidence). Only this paired close frees the task and opens dependent Beads: a plain `atm send` report closes neither. Use `atm task close {{ task_id }} refused "<reason>"` only when the whole assignment cannot be done; leave its bead open and add `bd update {{ task_id }} --notes "<reason>"`. {% if cc and cc != lead %}Copy a one-line summary to `{{ cc }}` with a plain `atm send {{ cc }} --stdin`.{% endif %}</step>
<step id="h">After the close, read ATM again: the next queued task starts only now.</step>
</workflow>
</atm-task>
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/codex-orchestration/fix-assignment.xml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ metadata:
</references>

<workflow>
<step id="a">Start the task immediately with `atm task start {{ task_id }} "<one line: what you will do first>"`, then begin executing it in the same work session unless blocked.</step>
<step id="a">Start the task immediately with `atm task start {{ task_id }} "<one line: what you will do first>"`, then claim the matching bead with `bd update {{ task_id }} --claim` and begin executing in the same work session unless blocked.</step>
<step id="b">Read `{{ sprint_doc }}` before editing. Treat it as the authoritative source for sprint scope, retained requirements, deletion targets, validation, and acceptance criteria. If this assignment summary and the sprint doc differ, the sprint doc wins and the mismatch must be reported.</step>
<step id="c">Update the assigned worktree from the target branch before editing. Include all earlier-sprint fixes already merged forward to that branch.</step>
<step id="c1">Honor the `<dependency-relations>` block above: must-follow merge-forward trigger is parent dev push, not QA; merge parent β†’ child before every round. PR-completion trigger is parent PR merge first. Stop if a parallel-safe relation intersects.</step>
<step id="d">Read the referenced triage records first. Treat the listed occurrences as the minimum required scope on this branch.</step>
<step id="d2">Before fixing each finding, verify the defect it describes is still actually present at the cited file:line in this worktree's current state. If a finding does not reproduce β€” already fixed, superseded by other work, or the described code path no longer exists β€” refuse to perform speculative or invented work to "address" it. Do not edit unrelated code in its name. Note it in your push/validation report as `not-reproducible` with the file:line you checked instead, and skip it. This applies per-finding, not to the whole task β€” fix every finding that does reproduce as normal.</step>
<step id="e">Fix every promoted-branch occurrence in scope. Do not stop at the first location when the triage record marks the finding as repeatable.</step>
<step id="f">As soon as the branch is pushable, commit and push immediately. Send branch name and commit hash right away to the assigner (the sender of this message) with a plain `atm send {{ lead }} --stdin` β€” a progress report, not a close; never close the task on a push. This lets follow-up QA start in parallel. {% if cc and cc != lead %}Copy a one-line summary to `{{ cc }}` with a plain `atm send {{ cc }} --stdin`.{% endif %}</step>
<step id="g">Run the required validation after the push report. While it is FAIL, keep fixing and report progress with plain `atm send`. When it is PASS, close the task with the validation report as the body: `atm task close {{ task_id }} completed --stdin <<'EOF' … EOF` β€” PASS plus the gate output lines and, per finding, fixed or `not-reproducible` with the file:line checked. Only this close frees your queue: the next assignment stays queued and never starts until `{{ task_id }}` is closed, and a plain `atm send` report does not close it. Use `atm task close {{ task_id }} refused "<reason>"` only when the whole assignment cannot be done. {% if cc and cc != lead %}Copy a one-line summary to `{{ cc }}` with a plain `atm send {{ cc }} --stdin`.{% endif %}</step>
<step id="g">Run the required validation after the push report. While it is FAIL, keep fixing and report progress with plain `atm send`. When it is PASS, close the task with the validation report as the body: `atm task close {{ task_id }} completed --stdin <<'EOF' … EOF`, followed by `bd close {{ task_id }}` β€” PASS plus the gate output lines and, per finding, fixed or `not-reproducible` with the file:line checked. Only this paired close frees the task and opens dependent Beads: a plain `atm send` report closes neither. Use `atm task close {{ task_id }} refused "<reason>"` only when the whole assignment cannot be done; leave its bead open and add `bd update {{ task_id }} --notes "<reason>"`. {% if cc and cc != lead %}Copy a one-line summary to `{{ cc }}` with a plain `atm send {{ cc }} --stdin`.{% endif %}</step>
{% if triage_records and triage_records|trim %} <step id="g1">Triage records are attached to this assignment. Use the `/closing-triage` skill to work them to zero before reporting: `{{ branch }}` is a stacked layer no phase structure declares, so its query runs as `python3 .claude/skills/closing-triage/scripts/query_open_findings.py --branch {{ branch }}{% if sprint_id %} --sprint {{ sprint_id }}{% endif %} --phase {{ phase }} --json` from your worktree. The finding ids it returns are the full scope of this assignment; fix every one in this pass.</step>
{% endif %} <step id="h">After the close, read ATM again: the next queued task starts only now.</step>
</workflow>
Expand Down
Loading
Loading