kind: WavePipeline metadata: name: audit-closed description: "Audit closed GitHub issues and merged PRs for implementation fidelity" release: true skills: - "{{ project.skill }}" requires: tools: - gh input: source: cli example: "last 30 days -- audit recent closed work" schema: type: string description: "Audit scope: empty for full audit, time range ('last 30 days', 'since 2026-01-01'), or label filter ('label:enhancement')" steps: - id: inventory persona: "gitea-analyst" model: claude-haiku workspace: mount: - source: ./ target: /project mode: readonly exec: type: prompt source: | Fetch all closed issues and merged PRs for audit inventory. ## Detect Repository Run: `{{ forge.cli_tool }} repo view --json nameWithOwner --jq .nameWithOwner` ## Parse Scope Input: {{ input }} Determine the scope mode from the input: - **Empty or blank input**: Full audit — fetch ALL closed issues and merged PRs - **Time range** (e.g., "last 30 days", "last 7 days", "since 2026-01-01"): - For "last N days": calculate the date N days ago, use `closed:>YYYY-MM-DD` / `merged:>YYYY-MM-DD` - For "since YYYY-MM-DD": use `closed:>YYYY-MM-DD` / `merged:>YYYY-MM-DD` - **Label filter** (e.g., "label:enhancement", "label:bug"): - Extract the label name after "label:" - Add `--label ` to both issue and PR queries ## Fetch Closed Issues ```bash {{ forge.cli_tool }} issue list --state closed --json number,title,body,labels,closedAt,stateReason,url \ --limit 500 [--search "closed:>YYYY-MM-DD"] [--label ] ``` Filter out issues where `stateReason` is `NOT_PLANNED` — these represent intentional non-implementation and should be excluded. If the result count equals the limit (500), make additional paginated calls to fetch remaining items. ## Fetch Merged PRs ```bash {{ forge.cli_tool }} {{ forge.pr_command }} list --state merged --json number,title,body,files,mergeCommit,closedAt,url \ --limit 500 [--search "merged:>YYYY-MM-DD"] [--label ] ``` If the result count equals the limit, paginate for more. ## Build Inventory For each closed issue: - `number`, `type` ("issue"), `title`, `url`, `body`, `labels` (array) - `closed_at`: ISO 8601 timestamp - `linked_prs`: Search body for "Fixes #N", "Closes #N", or PR cross-references - `acceptance_criteria`: Extract from issue body by looking for checklist patterns (`- [ ]`, `- [x]`) or sections titled "Acceptance Criteria", "Requirements", or similar headers For each merged PR: - `number`, `type` ("pr"), `title`, `url`, `body`, `labels` (array) - `merged_at`: ISO 8601 timestamp (from `closedAt`) - `merge_commit`: the mergeCommit SHA - `files_changed`: count of modified files from the PR ## Output Write the inventory as structured JSON to `.wave/artifacts/inventory.json`. The JSON must include: - `scope`: object with `mode` ("full", "time_range", or "label"), `filter` (the raw scope expression), `repository` (owner/repo) - `items`: array of inventory items (issues and PRs combined) - `summary`: object with `total_issues`, `total_prs`, `excluded_not_planned` counts - `timestamp`: current ISO 8601 timestamp output_artifacts: - name: inventory path: .wave/artifacts/inventory.json type: json retry: policy: patient max_attempts: 2 handover: contract: type: json_schema source: .wave/artifacts/inventory.json schema_path: .wave/contracts/audit-inventory.schema.json on_failure: retry - id: audit persona: "gitea-analyst" model: claude-haiku dependencies: [inventory] memory: inject_artifacts: - step: inventory artifact: inventory as: inventory workspace: mount: - source: ./ target: /project mode: readonly exec: type: prompt source: | Audit each closed issue and merged PR against the current codebase to verify implementation fidelity. ## Read Inventory Read the injected inventory artifact to get the list of items to audit. ## Verification Methodology For each inventory item, perform static analysis verification: 1. **Read the item description** — identify what should exist in the codebase: specific functions, types, handlers, configuration options, CLI flags, test files, documentation 2. **Check file existence** — use Glob to verify that referenced files still exist at HEAD 3. **Search for key artifacts** — use Grep to find function names, type definitions, handler registrations, and other code artifacts mentioned in the issue/PR 4. **Read relevant code** — use Read to verify logic matches the described behavior 5. **Check test coverage** — verify related test files exist and contain assertions matching the acceptance criteria 6. **Detect regressions** — run `git log --oneline --all -- ` to check if key files were modified after implementation. Run `git log --grep="Revert" --oneline` to find revert commits that may have undone the work ## Classification Rules Assign exactly ONE fidelity category per item: - **fully_implemented**: All referenced files exist, key functions/types are present via Grep, logic reads match the described behavior, related tests exist - **partial**: Some but not all acceptance criteria have matching code evidence. For each partial finding, list WHICH criteria passed and WHICH did not - **regressed**: Was implemented but later broken or reverted. Include the revert commit SHAs and affected file paths as evidence - **obsolete**: Referenced files have been deleted at HEAD, or the codebase has diverged significantly enough that the item no longer applies - **not_implemented**: No evidence of implementation; issue or PR describes work that does not appear in the codebase ## Evidence Requirements Every finding MUST include evidence: - For **fully_implemented**: file paths confirming existence, Grep matches for key code artifacts - For **partial**: which criteria passed (with file:line references) and which did not (what was searched for but not found) - For **regressed**: revert commit SHAs, `git log` output showing modification/deletion after the implementing PR - For **obsolete**: evidence that files no longer exist or architecture has changed - For **not_implemented**: description of what was expected to exist but does not ## Edge Cases - **Issues with no traceable code changes**: Mark as "not_implemented" with a note explaining the lack of implementation evidence - **Issues referencing deleted files**: Mark as "obsolete" with evidence that the referenced code no longer exists at HEAD - **Large inventories**: Focus on the most impactful items first — non-trivial issues with acceptance criteria. If context limits approach, prioritize quality of analysis over quantity ## Output Write the findings as structured JSON to `.wave/artifacts/audit-report.json`. The JSON must include: - `findings`: array of finding objects, each with: - `item_number`: issue or PR number - `item_type`: "issue" or "pr" - `item_url`: GitHub URL - `title`: item title - `status`: one of (fully_implemented, partial, regressed, obsolete, not_implemented) - `evidence`: array of strings describing evidence found - `unmet_criteria`: array of strings describing criteria not met (for partial/regressed) - `remediation`: string describing remediation needed (empty for fully_implemented/obsolete) - `summary`: object with counts by status (fully_implemented, partial, regressed, obsolete, not_implemented) - `timestamp`: current ISO 8601 timestamp output_artifacts: - name: audit-report path: .wave/artifacts/audit-report.json type: json retry: policy: patient max_attempts: 2 handover: contract: type: json_schema source: .wave/artifacts/audit-report.json schema_path: .wave/contracts/audit-findings.schema.json on_failure: retry - id: triage persona: navigator model: claude-haiku dependencies: [audit] memory: inject_artifacts: - step: inventory artifact: inventory as: inventory - step: audit artifact: audit-report as: audit_report workspace: mount: - source: ./ target: /project mode: readonly exec: type: prompt source: | Compose a triage summary from the audit findings with prioritized remediation recommendations. ## Read Inputs Read the injected inventory artifact to get scope and repository metadata. Read the injected audit report artifact to get the per-item verification results. ## Group Findings by Status Organize all findings into groups by implementation status, in this order: 1. **regressed** — highest priority, was working but now broken 2. **partial** — some criteria unmet 3. **not_implemented** — no implementation found 4. **obsolete** — no longer applicable 5. **fully_implemented** — fully intact (included for reference) ## Summary Statistics Calculate counts for each status: - `fully_implemented`: number of fully verified items - `partial`: number with some criteria unmet - `regressed`: number that were broken or reverted - `obsolete`: number no longer applicable - `not_implemented`: number with no implementation evidence ## Prioritized Remediation Actions Generate an ordered list of remediation actions for non-fully-implemented items. Priority ranking: 1. **regressed** items (highest priority — was working, now broken) 2. **partial** items with many unmet criteria (sort by unmet count descending) 3. **partial** items with fewer unmet criteria 4. **not_implemented** items (moderate priority — work was never done) 5. **obsolete** items are EXCLUDED from actions — they are intentionally non-applicable ## Output Format Write a markdown summary to `.wave/artifacts/triage-report.md` with: 1. **Audit Scope** — Description of what was audited (time range, labels, etc.) 2. **Summary Statistics** — Counts by status as a table or list 3. **Regressed Items** (if any) — Bulleted list with issue numbers, titles, revert commit SHAs, and remediation steps 4. **Partial Implementation Items** (if any) — Bulleted list with issue numbers, titles, which criteria failed, and remediation steps 5. **Not Implemented Items** (if any) — Bulleted list with issue numbers, titles, and what would need to be done 6. **Obsolete Items** — Count only, explanation that these are no longer applicable 7. **Fully Implemented Items** — Count only, confirmation of fidelity 8. **Recommended Next Steps** — Actionable recommendations for the team All issue/PR references should be clickable links to their GitHub URLs. output_artifacts: - name: triage-report path: .wave/artifacts/triage-report.md type: markdown handover: contract: type: non_empty_file source: .wave/artifacts/triage-report.md