chore: make solve-issue.yaml portable and add developer failed exit

- Remove hardcoded ~/repos/workflow paths from procedure text
- Use .worktrees/ relative to repo root instead of global path
- Add developer failed → $END exit for unrecoverable situations
- Add worktree field to reviewer rejected variant
- Fix test workflowPath to use import.meta.dirname

Refs #506
This commit is contained in:
2026-05-25 09:07:28 +00:00
parent 45f479e60f
commit 9c26285424
2 changed files with 62 additions and 45 deletions
+50 -41
View File
@@ -10,9 +10,9 @@ roles:
procedure: | procedure: |
On first run (no previous steps): On first run (no previous steps):
1. Read the issue and all comments from Gitea using `tea issues <number> -r <owner/repo>` 1. Read the issue and all comments from Gitea using `tea issues <number> -r <owner/repo>`
2. Read CLAUDE.md (or equivalent project conventions file) to understand coding standards 2. Look for project conventions files (CLAUDE.md, CONTRIBUTING.md, .cursor/rules/) in the repo
3. Assess whether the issue has enough information to produce a test spec 3. Assess whether the issue has enough information to produce a test spec
4. If insufficient info: comment on the issue via `echo "..." | tea comment <number> -r <owner/repo>` (skip if you already commented), then output status=insufficient_info and terminate 4. If insufficient info: comment on the issue via `echo "..." | tea comment <number> -r <owner/repo>` (skip if you already commented), then output $status=insufficient_info
5. If sufficient: produce a detailed TDD test spec in markdown covering all scenarios 5. If sufficient: produce a detailed TDD test spec in markdown covering all scenarios
On subsequent runs (bounced back by tester with fix_spec): On subsequent runs (bounced back by tester with fix_spec):
@@ -21,7 +21,8 @@ roles:
After producing the test spec: After producing the test spec:
1. Store it via `uwf cas put-text "<markdown content>"` and capture the returned hash 1. Store it via `uwf cas put-text "<markdown content>"` and capture the returned hash
2. Put the hash in frontmatter.plan (required when status=ready) 2. Put the hash in frontmatter.plan (required when $status=ready)
3. Set repoPath to the absolute path of the repository root
output: "Output a brief summary of the test spec. Set $status to ready (with plan hash and repoPath) or insufficient_info." output: "Output a brief summary of the test spec. Set $status to ready (with plan hash and repoPath) or insufficient_info."
frontmatter: frontmatter:
oneOf: oneOf:
@@ -40,32 +41,41 @@ roles:
- coding - coding
procedure: | procedure: |
IMPORTANT: Always work in a git worktree, NEVER modify the main working directory directly. IMPORTANT: Always work in a git worktree, NEVER modify the main working directory directly.
The repo path and other details are provided in your task prompt.
Before starting any work, set up an isolated worktree: Before starting any work, set up an isolated worktree:
1. `cd ~/repos/workflow && git fetch origin` to get latest refs 1. cd into the repo path provided in your task prompt
2. First time (no existing branch): 2. `git fetch origin` to get latest refs
- `git worktree add ~/repos/workflow-worktrees/fix/<issue-number>-<short-slug> -b fix/<issue-number>-<short-slug> origin/main` 3. First time (no existing branch):
- `cd ~/repos/workflow-worktrees/fix/<issue-number>-<short-slug> && bun install` - `git worktree add .worktrees/fix/<issue-number>-<short-slug> -b fix/<issue-number>-<short-slug> origin/main`
3. If bounced back from reviewer or tester (branch already exists): - `cd .worktrees/fix/<issue-number>-<short-slug> && bun install`
- The worktree should already exist at `~/repos/workflow-worktrees/fix/<issue-number>-<short-slug>` 4. If bounced back from reviewer or tester (branch already exists):
- `cd ~/repos/workflow-worktrees/fix/<issue-number>-<short-slug>` - cd into the existing worktree under `.worktrees/fix/<issue-number>-<short-slug>`
- `git fetch origin && git rebase origin/main` - `git fetch origin && git rebase origin/main`
4. ALL subsequent work must happen inside the worktree directory. 5. ALL subsequent work must happen inside the worktree directory.
Then implement TDD: Then implement TDD:
5. Read the test spec from CAS: `uwf cas get <plan hash>` (find the hash from the latest planner step's frontmatter.plan) 6. Read the test spec from CAS: `uwf cas get <plan hash>` (find the hash from the planner's output in your task prompt)
6. If bounced back from reviewer or tester: read the previous role's output to understand what needs fixing 7. If bounced back from reviewer or tester: read the previous role's feedback in your task prompt
7. Write tests first based on the spec 8. Write tests first based on the spec
8. Implement the code to make tests pass 9. Implement the code to make tests pass
9. Ensure `bun run build` passes with no errors 10. Ensure `bun run build` passes with no errors
10. Run `bun test` to verify all tests pass 11. Run `bun test` to verify all tests pass
output: "List all files changed and provide a summary. Include branch name and worktree path in frontmatter."
If you cannot complete the implementation (e.g. the issue is too complex, blocked by external factors,
or repeated attempts fail), set $status=failed with a reason.
output: "List all files changed and provide a summary. Set $status to done (with branch/worktree), or failed (with reason)."
frontmatter: frontmatter:
type: object oneOf:
properties: - properties:
$status: { const: "done" }
branch: { type: string } branch: { type: string }
worktree: { type: string } worktree: { type: string }
required: [branch, worktree] required: [$status, branch, worktree]
- properties:
$status: { const: "failed" }
reason: { type: string }
required: [$status, reason]
reviewer: reviewer:
description: "Code standards compliance check" description: "Code standards compliance check"
goal: "You are a code reviewer. You verify code standards compliance — NOT functionality (that's the tester's job)." goal: "You are a code reviewer. You verify code standards compliance — NOT functionality (that's the tester's job)."
@@ -73,7 +83,7 @@ roles:
- code-review - code-review
- static-analysis - static-analysis
procedure: | procedure: |
First, cd into the worktree: `cd ~/repos/workflow-worktrees/fix/<issue-number>-*` (find the exact directory) The worktree path is provided in your task prompt. cd into it first.
Before reviewing, verify the git branch: Before reviewing, verify the git branch:
1. Run `git branch --show-current` — confirm the branch name references the issue number being worked on 1. Run `git branch --show-current` — confirm the branch name references the issue number being worked on
@@ -85,12 +95,9 @@ roles:
4. `bunx biome check` — no lint violations 4. `bunx biome check` — no lint violations
5. TypeScript strict mode — no type errors 5. TypeScript strict mode — no type errors
Soft checks (review against CLAUDE.md conventions): Soft checks (review against project conventions if CLAUDE.md / .cursor/rules exist):
- Functional-first: `function` + `type`, not `class` + `interface` - Naming conventions, module boundaries, code style
- No optional properties (`?:`) — use `T | null` - No `console.log` in production code
- Naming conventions (kebab-case files, PascalCase types, camelCase functions)
- Module boundary discipline (folder exports via index.ts)
- No `console.log` (use structured logger)
- No dynamic imports in production code - No dynamic imports in production code
Only review standards compliance. Do NOT test functionality. Only review standards compliance. Do NOT test functionality.
@@ -106,17 +113,18 @@ roles:
- properties: - properties:
$status: { const: "rejected" } $status: { const: "rejected" }
comments: { type: string } comments: { type: string }
required: [$status, comments] worktree: { type: string }
required: [$status, comments, worktree]
tester: tester:
description: "Functional correctness verification" description: "Functional correctness verification"
goal: "You are a tester agent. You verify that the implementation correctly satisfies every scenario in the test spec." goal: "You are a tester agent. You verify that the implementation correctly satisfies every scenario in the test spec."
capabilities: capabilities:
- testing - testing
procedure: | procedure: |
First, cd into the worktree: `cd ~/repos/workflow-worktrees/fix/<issue-number>-*` (find the exact directory) The worktree path is provided in your task prompt. cd into it first.
1. Run `bun test` for automated test verification 1. Run `bun test` for automated test verification
2. Read the test spec from CAS: `uwf cas get <plan hash>` (find the hash from the latest planner step's frontmatter.plan) 2. Read the test spec from CAS: `uwf cas get <plan hash>` (find the hash from the planner step in the thread history)
3. Verify each scenario in the spec is covered and passing 3. Verify each scenario in the spec is covered and passing
4. Determine outcome: 4. Determine outcome:
- passed: all scenarios verified, tests pass - passed: all scenarios verified, tests pass
@@ -143,21 +151,21 @@ roles:
goal: "You are a committer agent. You create a clean commit and push a PR linking the original issue." goal: "You are a committer agent. You create a clean commit and push a PR linking the original issue."
capabilities: [] capabilities: []
procedure: | procedure: |
First, cd into the worktree: `cd ~/repos/workflow-worktrees/fix/<issue-number>-*` (find the exact directory) The worktree path, branch name, and repo info are provided in your task prompt.
cd into the worktree first.
Note: You inherit the developer's worktree and branch. Do NOT create a new branch. Note: You inherit the developer's worktree and branch. Do NOT create a new branch.
1. Stage all changes: `git add -A` 1. Stage all changes: `git add -A`
2. Commit with a descriptive message referencing the issue: `git commit -m "type: description\n\nFixes #N"` 2. Commit with a descriptive message referencing the issue: `git commit -m "type: description\n\nFixes #N"`
3. Push the branch: `git push -u origin <branch-name>` 3. Push the branch: `git push -u origin <branch-name>`
- If push hook fails: capture the error log in your output, mark hook_failed - If push hook fails: capture the error log in your output, mark hook_failed
4. On push success: create a PR via `tea pr create --repo uncaged/workflow --title "..." --description "..."` 4. On push success: create a PR via `tea pr create --repo <owner/repo> --title "..." --description "..."`
- The `--repo` flag is required to work in worktree directories (fixes #474 "path segment [0] is empty" error) - Extract owner/repo from: `git remote get-url origin | sed 's/.*[:/]\([^/]*\/[^.]*\).*/\1/'`
- If working on a different repo, extract owner/repo from: `git remote get-url origin | sed 's/.*[:/]\([^/]*\/[^.]*\).*/\1/'` - PR description must include: What / Why / Changes / Ref sections, with `Fixes #N` in Ref
- PR description must follow the project template: What / Why / Changes / Ref sections, with `Fixes #N` in Ref - On tea failure: capture stderr/stdout, include PR details for manual creation, mark hook_failed
- On tea failure: capture stderr/stdout, log the error clearly, include PR details (title, description, branch) for manual creation, and mark success=false
5. After PR creation, clean up the worktree: 5. After PR creation, clean up the worktree:
- `cd ~/repos/workflow` - cd to the repo root (parent of .worktrees)
- `git worktree remove ~/repos/workflow-worktrees/fix/<issue-number>-<slug>` - `git worktree remove <worktree-path>`
output: "Include PR URL on success or error log on failure. Set $status to committed (with prUrl) or hook_failed (with error)." output: "Include PR URL on success or error log on failure. Set $status to committed (with prUrl) or hook_failed (with error)."
frontmatter: frontmatter:
oneOf: oneOf:
@@ -176,9 +184,10 @@ graph:
insufficient_info: { role: "$END", prompt: "Insufficient information to proceed; end the workflow." } insufficient_info: { role: "$END", prompt: "Insufficient information to proceed; end the workflow." }
ready: { role: "developer", prompt: "Implement the TDD test spec (CAS hash: {{{plan}}}) in repo {{{repoPath}}}." } ready: { role: "developer", prompt: "Implement the TDD test spec (CAS hash: {{{plan}}}) in repo {{{repoPath}}}." }
developer: developer:
_: { role: "reviewer", prompt: "Review branch {{{branch}}} at {{{worktree}}} for code standards compliance." } done: { role: "reviewer", prompt: "Review branch {{{branch}}} at {{{worktree}}} for code standards compliance." }
failed: { role: "$END", prompt: "Developer failed: {{{reason}}}. Ending workflow." }
reviewer: reviewer:
rejected: { role: "developer", prompt: "Reviewer rejected: {{{comments}}}. Fix the issues." } rejected: { role: "developer", prompt: "Reviewer rejected: {{{comments}}}. Fix the issues in repo {{{worktree}}}." }
approved: { role: "tester", prompt: "Review passed. Run tests on branch {{{branch}}} at {{{worktree}}}." } approved: { role: "tester", prompt: "Review passed. Run tests on branch {{{branch}}} at {{{worktree}}}." }
tester: tester:
fix_code: { role: "developer", prompt: "Tests found code issues: {{{report}}}. Fix and re-submit." } fix_code: { role: "developer", prompt: "Tests found code issues: {{{report}}}. Fix and re-submit." }
@@ -13,8 +13,16 @@ import { parse } from "yaml";
*/ */
describe("solve-issue workflow: tea pr create worktree fix", () => { describe("solve-issue workflow: tea pr create worktree fix", () => {
// Navigate up from packages/cli-workflow to repo root // Navigate up from packages/cli-workflow/src/__tests__ to repo root
const workflowPath = join(process.cwd(), "..", "..", ".workflows", "solve-issue.yaml"); const workflowPath = join(
import.meta.dirname,
"..",
"..",
"..",
"..",
".workflows",
"solve-issue.yaml",
);
test("committer procedure should include --repo flag in tea pr create command", async () => { test("committer procedure should include --repo flag in tea pr create command", async () => {
const yamlContent = await readFile(workflowPath, "utf-8"); const yamlContent = await readFile(workflowPath, "utf-8");