feat(v0): post-findings subcommand with --execute flag (closes #30) #50
No reviewers
Labels
No labels
agent/claude-code
agent/codex
agent/gemini
agent/hermes
agent/iskra
agent/ollama
agent/patchwarden
area:business-model
area:competitive
area:discovery
area:forgejo
area:metrics
area:product-strategy
area:v0-core
cagan-grade-approved
client:platform
dependency/blocked
dependency/blocks-others
dependency/cross-repo
dependency/needs-confirmation
domain:agents
domain:ci
domain:docs
domain:forgejo
domain:infra
domain:memory
domain:runtime
domain:signal
domain:ux
flow/architecture
flow/blocked
flow/deployed
flow/done
flow/implementation
flow/intake
flow/maintained
flow/observed
flow/ready
flow/refining
flow/retired
flow/review
judge/codex-candidate
judge/hermes-candidate
judge/low-confidence
judge/needs-refinement
judge/operator-needed
judge/p0
judge/p1
judge/p2
judge/p3
judge/park
judge/patchwarden-candidate
judge/stale-priority
kind/adr
kind/bug
kind/chore
kind/feature
kind/infra
kind/ops
kind/refactor
kind/research
kind:artifact
kind:decision
kind:dogfood
kind:epic
kind:implementation
kind:research
merge/auto
merge/manual
merge/manual-dependency-conflict
merge/manual-failing-tests
merge/manual-merge-conflict
merge/manual-missing-review
merge/manual-operator-preference
merge/manual-red-zone
merge/manual-security-sensitive
merge/manual-unclear-scope
merge/manual-unknown
mode:operator-only
mode:patchwarden-iskra-approved
mode:safe-auto
observed/erroring
observed/needs-followup
observed/pending
observed/retire-candidate
observed/unused
observed/used
priority:p0
priority:p1
priority:p2
priority:p3
ready-for-agent
review:claude-reviewed
review:codex-reviewed
review:dziadek-reviewed
review:needs-human
safety:external-write
safety:no-prod-mutation
safety:prod-impact
safety:secret-touch
size/large
size/medium
size/small
size/tiny
size/unknown
source/adr
source/agent-generated
source/manual
source/operator-chat
source/voice-note
status:blocked
status:blocked-on-discovery
status:cagan-grade-review-pending
status:codex-ready
status:merged:pending-evidence
status:needs-evidence
status:needs-operator-decision
status:operator-needed
status:parked
tier:0-anchor
tier:0-platform-substrate
tier:1-core
tier:1-iskra-value-layer
tier:2-supporting
tier:2-tools-products-modules
type:bug
type:chore
type:docs
type:feat
type:policy
type:research
wave:1-foundation
wave:2-positioning
wave:3-validation
wave:4-economics
wave:5-operating
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
pdurlej/patchwarden!50
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "claude/patchwarden-post-findings-execute"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
New CLI subcommand bridges existing
render_findingsto existingforgejo_client.post_comment. Dry-run by default — no Forgejo mutation without--execute. Fail-closed on Forgejo errors (exit 2).Default = renders markdown body to stdout (or
--output FILE), zero network. With--execute: also posts the rendered body as a single PR comment viaPOST /issues/{pr}/comments.Wave position — step 4/4 CLOSED
--executePatchwarden can now run end-to-end on a Forgejo PR: fetch metadata → render prompt → call Ollama → emit artifact → resolve findings → render comment body → post to PR. Each step gated by explicit operator flag before any Forgejo write.
D20 enforcement
/issues/{pr}/commentsendpoint reachable from this code path.create_pr_review(no APPROVED reviews from the bot).merge_pull_request(Patchwarden = merge authority, sensors never bypass).--base-url/env (FORGEJO_TOKEN), never argv.Empty findings — pdurlej decision
When the artifact has no findings,
render_findingsemits the literal placeholder"No Patchwarden findings to render.". With--execute, that placeholder IS posted — operator sees the run happened. Silence is a worse signal than "nothing to flag." (SeePostFindingsExecuteTests.test_execute_posts_empty_placeholder_when_no_findings.)Reuse, not new module
Zero new modules. Wires together:
render_findings.render_findings— already returns one combined body (separator\n\n---\n\nbetween findings, single string out).forgejo_client.post_comment— already exists; exception hierarchy already in place (ForgejoAuthError401/403,ForgejoNotFoundError404,ForgejoApiErrorfor network).This deviates from my own prior handoff (which speculated about a new
forgejo_post.pywith per-finding idempotency markers). I followed codex's issue spec instead — it's authoritative andready-for-agentlabelled, and the simpler shape is the right one.Tests — 120 → 132 green (+12)
tests/test_cli_post_findings.py:PostFindingsDryRunTests (3)
post_commentnever invoked)PostFindingsExecuteTests (6)
--executeposts body viapost_commentwith correct positional args--executepasses--base-urloverride topost_comment--executeposts placeholder when no findings (per pdurlej decision)ForgejoAuthError→ exit 2ForgejoNotFoundError→ exit 2ForgejoApiError(network) → exit 2PostFindingsArgparseTests (3)
--artifact-file→ argparse SystemExit--resolution-file→ argparse SystemExitAtomic per ADR-0017
cli.py+ new test file. Noforgejo_client.py/render_findings.py/pipeline.pychanges.base=main, no stacking on #49 (already merged anyway).Token-accounting note (agent-kanban)
This PR on Opus directly (sacred-adjacent: first mutating Forgejo call from cousin code, D20 boundary line). No sub-agent — the change is small (~70 LOC src + ~300 LOC tests) and verification overhead would have exceeded the delegation savings.
Wave totals:
Well within the 21% upper estimate. The agent-kanban prototype shows: Sonnet sub-agent shines on isolated HTTP boilerplate (ollama_client), Opus is right for sacred path + glue under boundary pressure (review_run, post-findings). Single data point each, but the pattern reads clean.
Closes #30.
New CLI subcommand bridges existing render_findings to the existing forgejo_client.post_comment. Dry-run by default — no Forgejo mutation without --execute. Fail-closed on Forgejo errors (exit 2). ## What ```bash patchwarden post-findings \ --artifact-file artifact.json \ --resolution-file resolution.json \ --repo-host git.pdurlej.com \ --repo-owner pdurlej \ --repo-name patchwarden \ --pr-number 49 \ [--base-url URL] \ [--execute] ``` Default = dry-run: renders markdown body to stdout (or --output FILE), zero network. With --execute: also posts the rendered body as a single PR comment via `POST /issues/{pr}/comments`. ## D20 enforcement - Only `/issues/{pr}/comments` endpoint is reachable from this code path. - NEVER `create_pr_review` (no APPROVED reviews from the bot). - NEVER `merge_pull_request` (Patchwarden = merge authority, sensors never bypass). - Token comes from `--base-url`/env (`FORGEJO_TOKEN`), never argv. ## Empty findings When the artifact has no findings, render_findings emits the literal placeholder "No Patchwarden findings to render." With --execute, that placeholder IS posted — operator sees the run happened. Silence is a worse signal than "nothing to flag" (per pdurlej decision). ## Reuse, not new module Zero new modules. Wires together: - `render_findings.render_findings` (already returns one combined body) - `forgejo_client.post_comment` (already exists, exception hierarchy already in place: ForgejoAuthError 401/403, ForgejoNotFoundError 404, ForgejoApiError for network) ## Tests (+12, suite 120 → 132 green) `tests/test_cli_post_findings.py`: PostFindingsDryRunTests (3): - dry-run does NOT call forgejo (mocked post_comment never invoked) - dry-run renders findings to stdout (header + path + rationale visible) - dry-run with no findings emits placeholder string PostFindingsExecuteTests (6): - --execute posts body via post_comment with correct positional args - --execute passes --base-url override to post_comment - --execute posts placeholder when no findings (per pdurlej decision) - ForgejoAuthError → exit 2 - ForgejoNotFoundError → exit 2 - generic ForgejoApiError (network) → exit 2 PostFindingsArgparseTests (3): - missing --artifact-file → argparse SystemExit - missing --resolution-file → argparse SystemExit - nonexistent artifact path → exit 2 (not crash) ## Wave step 4/4 closed 1. PR #47 (#29 prompt) — merged 2. PR #48 (ollama_client) — merged 3. PR #49 (review_run invokes) — merged 4. THIS PR (#30 post comments with --execute) — wave complete Patchwarden can now run end-to-end on a Forgejo PR: fetch metadata → render prompt → call Ollama → emit artifact → resolve findings → render comment body → post to PR. Each step still gated by an explicit operator flag (--execute) before any Forgejo write. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>