diff --git a/.github/workflows/agent-verify.yml b/.github/workflows/agent-verify.yml new file mode 100644 index 00000000..4b85fecb --- /dev/null +++ b/.github/workflows/agent-verify.yml @@ -0,0 +1,133 @@ +name: Agent Verification Workflow + +on: + issues: + types: [labeled] + +jobs: + # When work is claimed, track the implementer + track-implementer: + if: github.event.label.name == 'agent:wip' + runs-on: ubuntu-latest + steps: + - name: Record implementer + run: | + echo "Implementer: ${{ github.actor }}" + # Could store in issue body or external system + + # When work is submitted for review, add to verification queue + request-verification: + if: github.event.label.name == 'agent:review' + runs-on: ubuntu-latest + steps: + - name: Add to Workstation for verification + uses: actions/add-to-project@v1.0.2 + with: + project-url: https://github.com/orgs/host-uk/projects/2 + github-token: ${{ secrets.PROJECT_TOKEN }} + + - name: Comment verification needed + uses: actions/github-script@v7 + with: + script: | + const implementer = context.payload.sender.login; + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `## 🔍 Verification Required\n\nWork submitted by @${implementer}.\n\n**Rule:** A different agent must verify this work.\n\nTo verify:\n1. Review the implementation\n2. Run tests if applicable\n3. Add \`verified\` or \`verify-failed\` label\n\n_Self-verification is not allowed._` + }); + + # Block self-verification + check-verification: + if: github.event.label.name == 'verified' || github.event.label.name == 'verify-failed' + runs-on: ubuntu-latest + steps: + - name: Get issue details + id: issue + uses: actions/github-script@v7 + with: + script: | + const issue = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + + // Check timeline for who added agent:wip + const timeline = await github.rest.issues.listEventsForTimeline({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + per_page: 100 + }); + + const wipEvent = timeline.data.find(e => + e.event === 'labeled' && e.label?.name === 'agent:wip' + ); + + const implementer = wipEvent?.actor?.login || 'unknown'; + const verifier = context.payload.sender.login; + + console.log(`Implementer: ${implementer}`); + console.log(`Verifier: ${verifier}`); + + if (implementer === verifier) { + core.setFailed(`Self-verification not allowed. ${verifier} cannot verify their own work.`); + } + + return { implementer, verifier }; + + - name: Record verification + if: success() + uses: actions/github-script@v7 + with: + script: | + const label = context.payload.label.name; + const verifier = context.payload.sender.login; + const status = label === 'verified' ? '✅ Verified' : '❌ Failed'; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `## ${status}\n\nVerified by @${verifier}` + }); + + // Remove agent:review label + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'agent:review' + }); + } catch (e) { + console.log('agent:review label not present'); + } + + # If verification failed, reset for rework + handle-failure: + if: github.event.label.name == 'verify-failed' + runs-on: ubuntu-latest + needs: check-verification + steps: + - name: Reset for rework + uses: actions/github-script@v7 + with: + script: | + // Remove verify-failed after processing + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'verify-failed' + }); + + // Add back to ready queue + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['agent:ready'] + });