From dacecfbbb72c923c3645262de92fe2dc1f02b109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 05:21:19 +0000 Subject: [PATCH 1/5] feat: create .workflows/solve-issue.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TDD-driven issue resolution workflow with 5 roles: - planner: analyzes issue, outputs TDD test spec (stored in CAS) - developer: implements code following TDD - reviewer: code standards compliance check (not functionality) - tester: functional correctness verification - committer: commits and creates PR Graph handles bounce-backs: reviewer→developer, tester→developer, tester→planner (fix_spec), committer→developer (hook_failed). Refs #370 --- .workflows/solve-issue.yaml | 187 ++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 .workflows/solve-issue.yaml diff --git a/.workflows/solve-issue.yaml b/.workflows/solve-issue.yaml new file mode 100644 index 0000000..0b5ff20 --- /dev/null +++ b/.workflows/solve-issue.yaml @@ -0,0 +1,187 @@ +name: "solve-issue" +description: "TDD-driven issue resolution for small, focused changes" +roles: + planner: + description: "Analyzes issue and outputs a TDD test spec" + goal: "You are a planning agent. You analyze Gitea issues and produce a TDD test specification that downstream roles will implement and verify." + capabilities: + - issue-analysis + - planning + procedure: | + On first run (no previous steps): + 1. Read the issue and all comments from Gitea using `tea issues --repo ` + 2. Read CLAUDE.md (or equivalent project conventions file) to understand coding standards + 3. Assess whether the issue has enough information to produce a test spec + 4. If insufficient info: comment on the issue via `tea issues comment "..."` (skip if you already commented), then output status=insufficient_info and terminate + 5. If sufficient: produce a detailed TDD test spec in markdown covering all scenarios + + On subsequent runs (bounced back by tester with fix_spec): + 1. Read the tester's output from the previous step to understand what's wrong with the spec + 2. Revise the test spec accordingly + + After producing the test spec: + 1. Store it via `uwf cas put ""` and capture the returned hash + 2. Put the hash in meta.plan + output: "Output a brief summary of the test spec. The full spec is stored in CAS — put its hash in meta.plan." + meta: + type: object + properties: + status: + type: string + enum: [ready, insufficient_info] + plan: + type: string + required: [status] + developer: + description: "TDD implementation per test spec" + goal: "You are a developer agent. You implement code changes following TDD — write tests first, then implementation." + capabilities: + - cursor-agent + procedure: | + 1. Read the test spec from CAS: `uwf cas get ` (find the hash from the latest planner step's meta.plan) + 2. If bounced back from reviewer or tester: read the previous role's output to understand what needs fixing + 3. Write tests first based on the spec + 4. Implement the code to make tests pass + 5. Ensure `npm run build` passes with no errors + 6. Run `npm test` to verify all tests pass + output: "List all files changed and provide a summary of the implementation." + meta: + type: object + properties: + status: + type: string + enum: [done, failed] + required: [status] + reviewer: + description: "Code standards compliance check" + goal: "You are a code reviewer. You verify code standards compliance — NOT functionality (that's the tester's job)." + capabilities: + - code-review + - static-analysis + procedure: | + Hard checks (must all pass): + 1. `npm run build` — no build errors + 2. `npx biome check` — no lint violations + 3. TypeScript strict mode — no type errors + + Soft checks (review against CLAUDE.md conventions): + - Functional-first: `function` + `type`, not `class` + `interface` + - No optional properties (`?:`) — use `T | null` + - 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 + + Only review standards compliance. Do NOT test functionality. + If rejecting, you MUST explain the specific reason in your output. + output: "Approve or reject with detailed comments explaining your decision." + meta: + type: object + properties: + approved: + type: boolean + required: [approved] + tester: + description: "Functional correctness verification" + goal: "You are a tester agent. You verify that the implementation correctly satisfies every scenario in the test spec." + capabilities: + - testing + procedure: | + 1. Run `npm test` for automated test verification + 2. Read the test spec from CAS: `uwf cas get ` (find the hash from the latest planner step's meta.plan) + 3. Verify each scenario in the spec is covered and passing + 4. Determine outcome: + - passed: all scenarios verified, tests pass + - fix_code: tests fail or implementation doesn't match spec → send back to developer + - fix_spec: the spec itself is wrong or incomplete → send back to planner + output: "Report test results and verification status for each scenario in the spec." + meta: + type: object + properties: + status: + type: string + enum: [passed, fix_code, fix_spec] + required: [status] + committer: + description: "Commits and creates PR" + goal: "You are a committer agent. You create a clean commit and push a PR linking the original issue." + capabilities: [] + procedure: | + 1. Stage all changes: `git add -A` + 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 ` + - 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 --title "..." --description "..."` + - PR description must link the issue with `Fixes #N` + output: "Report whether commit and PR creation succeeded. Include the PR URL on success or error log on failure." + meta: + type: object + properties: + success: + type: boolean + required: [success] +conditions: + insufficientInfo: + description: "Planner determined there's not enough info to proceed" + expression: "steps[-1].output.status = 'insufficient_info'" + ready: + description: "Planner produced a test spec" + expression: "steps[-1].output.status = 'ready'" + devDone: + description: "Developer finished implementation" + expression: "steps[-1].output.status = 'done'" + devFailed: + description: "Developer failed to implement" + expression: "steps[-1].output.status = 'failed'" + notApproved: + description: "Reviewer rejected the implementation" + expression: "steps[-1].output.approved = false" + approved: + description: "Reviewer approved the implementation" + expression: "steps[-1].output.approved = true" + fixCode: + description: "Tester found code issues" + expression: "steps[-1].output.status = 'fix_code'" + fixSpec: + description: "Tester found spec issues" + expression: "steps[-1].output.status = 'fix_spec'" + passed: + description: "Tester verified all scenarios pass" + expression: "steps[-1].output.status = 'passed'" + hookFailed: + description: "Push hook failed" + expression: "steps[-1].output.success = false" + pushSuccess: + description: "Commit and PR created successfully" + expression: "steps[-1].output.success = true" +graph: + $START: + - role: "planner" + condition: null + planner: + - role: "$END" + condition: "insufficientInfo" + - role: "developer" + condition: "ready" + developer: + - role: "$END" + condition: "devFailed" + - role: "reviewer" + condition: "devDone" + reviewer: + - role: "developer" + condition: "notApproved" + - role: "tester" + condition: "approved" + tester: + - role: "developer" + condition: "fixCode" + - role: "planner" + condition: "fixSpec" + - role: "committer" + condition: "passed" + committer: + - role: "developer" + condition: "hookFailed" + - role: "$END" + condition: "pushSuccess" From fd7609fe90ce385aabe848ff998108622771c3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 05:27:21 +0000 Subject: [PATCH 2/5] fix: address review feedback from xingyue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. npm/npx → bun/bunx (project standard) 2. Fix tea CLI usage (tea comment + -r flag) 3. cursor-agent → coding (abstract capability) 4. Clarify committer inherits developer's worktree 5. Mark meta.plan required when status=ready 6. PR description must follow What/Why/Changes/Ref template 7. Note maxRounds loop protection in description --- .workflows/solve-issue.yaml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.workflows/solve-issue.yaml b/.workflows/solve-issue.yaml index 0b5ff20..38863ab 100644 --- a/.workflows/solve-issue.yaml +++ b/.workflows/solve-issue.yaml @@ -1,5 +1,5 @@ name: "solve-issue" -description: "TDD-driven issue resolution for small, focused changes" +description: "TDD-driven issue resolution for small, focused changes. Loop protection relies on engine maxRounds." roles: planner: description: "Analyzes issue and outputs a TDD test spec" @@ -9,10 +9,10 @@ roles: - planning procedure: | On first run (no previous steps): - 1. Read the issue and all comments from Gitea using `tea issues --repo ` + 1. Read the issue and all comments from Gitea using `tea issues -r ` 2. Read CLAUDE.md (or equivalent project conventions file) to understand coding standards 3. Assess whether the issue has enough information to produce a test spec - 4. If insufficient info: comment on the issue via `tea issues comment "..."` (skip if you already commented), then output status=insufficient_info and terminate + 4. If insufficient info: comment on the issue via `echo "..." | tea comment -r ` (skip if you already commented), then output status=insufficient_info and terminate 5. If sufficient: produce a detailed TDD test spec in markdown covering all scenarios On subsequent runs (bounced back by tester with fix_spec): @@ -21,7 +21,7 @@ roles: After producing the test spec: 1. Store it via `uwf cas put ""` and capture the returned hash - 2. Put the hash in meta.plan + 2. Put the hash in meta.plan (required when status=ready) output: "Output a brief summary of the test spec. The full spec is stored in CAS — put its hash in meta.plan." meta: type: object @@ -36,14 +36,14 @@ roles: description: "TDD implementation per test spec" goal: "You are a developer agent. You implement code changes following TDD — write tests first, then implementation." capabilities: - - cursor-agent + - coding procedure: | 1. Read the test spec from CAS: `uwf cas get ` (find the hash from the latest planner step's meta.plan) 2. If bounced back from reviewer or tester: read the previous role's output to understand what needs fixing 3. Write tests first based on the spec 4. Implement the code to make tests pass - 5. Ensure `npm run build` passes with no errors - 6. Run `npm test` to verify all tests pass + 5. Ensure `bun run build` passes with no errors + 6. Run `bun test` to verify all tests pass output: "List all files changed and provide a summary of the implementation." meta: type: object @@ -60,8 +60,8 @@ roles: - static-analysis procedure: | Hard checks (must all pass): - 1. `npm run build` — no build errors - 2. `npx biome check` — no lint violations + 1. `bun run build` — no build errors + 2. `bunx biome check` — no lint violations 3. TypeScript strict mode — no type errors Soft checks (review against CLAUDE.md conventions): @@ -87,7 +87,7 @@ roles: capabilities: - testing procedure: | - 1. Run `npm test` for automated test verification + 1. Run `bun test` for automated test verification 2. Read the test spec from CAS: `uwf cas get ` (find the hash from the latest planner step's meta.plan) 3. Verify each scenario in the spec is covered and passing 4. Determine outcome: @@ -107,12 +107,13 @@ roles: goal: "You are a committer agent. You create a clean commit and push a PR linking the original issue." capabilities: [] procedure: | + Note: You inherit the developer's worktree and branch. Do NOT create a new branch. 1. Stage all changes: `git add -A` 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 ` - 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 --title "..." --description "..."` - - PR description must link the issue with `Fixes #N` + - PR description must follow the project template: What / Why / Changes / Ref sections, with `Fixes #N` in Ref output: "Report whether commit and PR creation succeeded. Include the PR URL on success or error log on failure." meta: type: object From 355594d07409e2854bd6e6571dcef59715d798e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 05:31:43 +0000 Subject: [PATCH 3/5] refactor: graph fallback pattern + positive condition names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Last transition in each graph node is now the fallback (no condition) - Remove redundant positive conditions (ready, devDone, approved, passed, pushSuccess) - notApproved → rejected (positive naming) --- .workflows/solve-issue.yaml | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/.workflows/solve-issue.yaml b/.workflows/solve-issue.yaml index 38863ab..7a52e81 100644 --- a/.workflows/solve-issue.yaml +++ b/.workflows/solve-issue.yaml @@ -125,36 +125,21 @@ conditions: insufficientInfo: description: "Planner determined there's not enough info to proceed" expression: "steps[-1].output.status = 'insufficient_info'" - ready: - description: "Planner produced a test spec" - expression: "steps[-1].output.status = 'ready'" - devDone: - description: "Developer finished implementation" - expression: "steps[-1].output.status = 'done'" devFailed: description: "Developer failed to implement" expression: "steps[-1].output.status = 'failed'" - notApproved: + rejected: description: "Reviewer rejected the implementation" expression: "steps[-1].output.approved = false" - approved: - description: "Reviewer approved the implementation" - expression: "steps[-1].output.approved = true" fixCode: description: "Tester found code issues" expression: "steps[-1].output.status = 'fix_code'" fixSpec: description: "Tester found spec issues" expression: "steps[-1].output.status = 'fix_spec'" - passed: - description: "Tester verified all scenarios pass" - expression: "steps[-1].output.status = 'passed'" hookFailed: description: "Push hook failed" expression: "steps[-1].output.success = false" - pushSuccess: - description: "Commit and PR created successfully" - expression: "steps[-1].output.success = true" graph: $START: - role: "planner" @@ -163,26 +148,21 @@ graph: - role: "$END" condition: "insufficientInfo" - role: "developer" - condition: "ready" developer: - role: "$END" condition: "devFailed" - role: "reviewer" - condition: "devDone" reviewer: - role: "developer" - condition: "notApproved" + condition: "rejected" - role: "tester" - condition: "approved" tester: - role: "developer" condition: "fixCode" - role: "planner" condition: "fixSpec" - role: "committer" - condition: "passed" committer: - role: "developer" condition: "hookFailed" - role: "$END" - condition: "pushSuccess" From f174f2fd0a7bb8f54c33416bf9605014131d80a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 05:33:39 +0000 Subject: [PATCH 4/5] fix: remove redundant condition null from $START --- .workflows/solve-issue.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.workflows/solve-issue.yaml b/.workflows/solve-issue.yaml index 7a52e81..6e9824d 100644 --- a/.workflows/solve-issue.yaml +++ b/.workflows/solve-issue.yaml @@ -143,7 +143,6 @@ conditions: graph: $START: - role: "planner" - condition: null planner: - role: "$END" condition: "insufficientInfo" From 8a425521dae8c45a01a23f903c4b88af26b93e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Fri, 22 May 2026 05:42:17 +0000 Subject: [PATCH 5/5] fix: output instructions now specify required frontmatter meta fields --- .workflows/solve-issue.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.workflows/solve-issue.yaml b/.workflows/solve-issue.yaml index 6e9824d..aa09753 100644 --- a/.workflows/solve-issue.yaml +++ b/.workflows/solve-issue.yaml @@ -22,7 +22,7 @@ roles: After producing the test spec: 1. Store it via `uwf cas put ""` and capture the returned hash 2. Put the hash in meta.plan (required when status=ready) - output: "Output a brief summary of the test spec. The full spec is stored in CAS — put its hash in meta.plan." + output: "Output a brief summary of the test spec. Frontmatter must include: status (ready or insufficient_info) and plan (CAS hash of the test spec, required when status=ready)." meta: type: object properties: @@ -44,7 +44,7 @@ roles: 4. Implement the code to make tests pass 5. Ensure `bun run build` passes with no errors 6. Run `bun test` to verify all tests pass - output: "List all files changed and provide a summary of the implementation." + output: "List all files changed and provide a summary. Frontmatter must include: status (done or failed)." meta: type: object properties: @@ -74,7 +74,7 @@ roles: Only review standards compliance. Do NOT test functionality. If rejecting, you MUST explain the specific reason in your output. - output: "Approve or reject with detailed comments explaining your decision." + output: "Explain your decision with specific file/line references. Frontmatter must include: approved (true or false)." meta: type: object properties: @@ -94,7 +94,7 @@ roles: - passed: all scenarios verified, tests pass - fix_code: tests fail or implementation doesn't match spec → send back to developer - fix_spec: the spec itself is wrong or incomplete → send back to planner - output: "Report test results and verification status for each scenario in the spec." + output: "Report test results per scenario. Frontmatter must include: status (passed, fix_code, or fix_spec)." meta: type: object properties: @@ -114,7 +114,7 @@ roles: - 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 --title "..." --description "..."` - PR description must follow the project template: What / Why / Changes / Ref sections, with `Fixes #N` in Ref - output: "Report whether commit and PR creation succeeded. Include the PR URL on success or error log on failure." + output: "Include PR URL on success or error log on failure. Frontmatter must include: success (true or false)." meta: type: object properties: