A worked example of the artifact a coding agent produces after running Agents Shipgate end-to-end. Sibling examples (mcp-only-tool-server, openai-agents-sdk-refund-agent, openapi-support-agent) document the recipe for adopting Shipgate; this doc documents the output — the diff, the PR comment, and the structured summary an agent should generate.
Audience. Coding agents (Claude Code, Codex, Cursor) running Shipgate inside a host repo. Use this as the template for the message you post back to the user once the verify-first flow finishes.
The agent has just completed a verify-first run on a target repo:
agents-shipgate verify --preview --json
agents-shipgate init --workspace . --write --ci --agent-instructions=all
agents-shipgate verify --workspace . --config shipgate.yaml \
--ci-mode advisory --format jsonverify produced agents-shipgate-reports/verifier.json with:
merge_verdict: "blocked"capability_review.top_changes[]namesstripe.create_refundcontrol.next_action.actor: "human"fix_task.safe_to_attempt: false
The head scan also produced agents-shipgate-reports/report.json with:
release_decision.decision: "blocked"- 2 blockers on
stripe.create_refund(missing approval policy, missing idempotency) - 14 high / 2 medium release review items; 15 need human review
- 1 auto-applicable patch (a stale suppression removed by
apply-patches)
The agent now has to summarize this for the user.
## Agents Shipgate: blocked
**Merge verdict**: `blocked`
**Release decision**: `blocked`
This PR changes what `support-agent` can do: it adds the money-moving action
`stripe.create_refund`. Shipgate cannot clear this for merge because approval
and idempotency evidence are missing.
| Impact | Change | Subject | Why |
|---|---|---|---|
| blocks release | action added | `stripe.create_refund` | money-moving refund action lacks approval and idempotency evidence |
**Required before merge**:
1. Human owner: confirm or add approval-policy evidence for `stripe.create_refund`.
2. Human owner: confirm or add idempotency evidence for refund retries.
3. Re-run `agents-shipgate verify --workspace . --config shipgate.yaml --ci-mode advisory --format json`.
**Top blockers**:
1. `stripe.create_refund` — `SHIP-POLICY-APPROVAL-MISSING` (critical).
The refund tool ships without a declared approval policy. High-risk
actions need an explicit human approval gate before promotion. I
can draft `policies.require_approval_for_tools: [stripe.create_refund]`
for you; want me to add it with a placeholder reason you can edit?
2. `stripe.create_refund` — `SHIP-SIDEFX-IDEMPOTENCY-MISSING` (critical).
The tool has no `idempotency_key` parameter and no policy entry.
Without idempotency, retried refunds duplicate. The fix is either
adding a parameter to the tool spec or declaring
`policies.require_idempotency_for_tools: [stripe.create_refund]`
with an external idempotency-key generator. Same draft offer.
**What I already applied** (high-confidence, no manual review needed):
- Removed 1 stale suppression entry that referenced a check ID that
no longer exists in the catalog. Diff shown below.
**What needs your review next** (15 non-blocker review findings): I can
walk these one-by-one if you want, or you can read
`agents-shipgate-reports/report.md`. The full machine-readable list
is at `agents-shipgate-reports/report.json`; the top-level
`agent_summary` block carries the headline/action counts.
**Reports**:
- Verifier JSON: `agents-shipgate-reports/verifier.json`
- Markdown: `agents-shipgate-reports/report.md`
- JSON: `agents-shipgate-reports/report.json` (schema v0.12)
- Release Evidence Packet: `agents-shipgate-reports/packet.{md,json,html}`
**CI**: `.github/workflows/agents-shipgate.yml` already wires
`agents-shipgate@v0.15.0` in advisory mode; this PR will get a
sticky-marker comment from the Action on every push.
<details>
<summary>Diff applied by <code>apply-patches --confidence high --apply</code></summary>
```diff
--- shipgate.yaml
+++ shipgate.yaml
@@ -42,7 +42,3 @@
checks:
ignore:
- check_id: SHIP-RETIRED-CHECK-ID
tool: legacy_search
reason: removed in v0.10
- - check_id: SHIP-MANIFEST-STALE-SUPPRESSION
- tool: ghost_tool
- reason: tool removedThe removal is safe: the suppressed check ID either doesn't exist in the loaded catalog (orphaned) or matches no loaded tool (ghost). Either way, leaving the entry in place misleads future review.
Top human-review items (full list in report.json)
| # | Severity | Check | Tool | Action |
|---|---|---|---|---|
| 1 | high | SHIP-AUTH-SCOPE-COVERAGE-MISSING |
stripe.create_refund |
propose_patch_for_review (medium-confidence patch attached; I can show the diff) |
| 2 | high | SHIP-DOC-MISSING-DESCRIPTION |
wildcard_mcp_tools.* |
escalate_to_human (no patch; description belongs with the tool spec) |
| 3 | high | SHIP-INVENTORY-WILDCARD-TOOLS |
wildcard_mcp_tools.* |
escalate_to_human (replace wildcard with explicit allowlist) |
| ... | ... | ... | ... | ... |
The agent should also be ready to surface the structured form when asked.
In a real run, copy these fields directly from agent_summary in
report.json; the object below shows the expected shape and internally
consistent counts:
{
"merge_verdict": "blocked",
"control": {
"state": "human_review_required",
"next_action": {
"actor": "human",
"kind": "review",
"why": "Approval and idempotency evidence cannot be invented by a coding agent."
}
},
"fix_task": {
"actor": "human",
"safe_to_attempt": false
},
"release_decision": "blocked",
"headline": "2 active finding(s) block release; 16 review item(s) accepted as debt.",
"blocker_count": 2,
"review_item_count": 16,
"auto_appliable_patches": 1,
"needs_human_review": 17,
"first_recommended_action": {
"kind": "command",
"command": "agents-shipgate apply-patches --from /abs/path/agents-shipgate-reports/report.json --confidence high --apply",
"why": "1 finding(s) carry high-confidence patches safe to apply without human review."
}
}Here, needs_human_review includes the 2 blockers plus the 15 review
items whose agent_action requires human input. It is intentionally not
the same number as review_item_count, which mirrors
release_decision.review_items.
- ❌ Apply medium-confidence patches without showing the diff and getting confirmation. Scope strings encode policy decisions; the user has to pick.
- ❌ Add a
checks.ignoreentry to silence the approval-policy blocker. Suppression isn't a fix; thetriage-false-positive.mdworkflow names the (rare) case for it. - ❌ Edit the trace recording (
approval_trace.jsonl) to flipapproved: true. Trace findings are class-four "never auto-fix" — patching the trace patches the evidence, not the runtime gate. - ❌ Fabricate a recommendation that wasn't grounded in
recommendation,evidence,patches[].instructions, ordocs_url. - ❌ Dump the raw JSON in the PR comment. The structured summary above is the agent-to-agent form; the PR comment translates each finding into prose for the human reviewer.
- Lead with the merge verdict.
mergeable/human_review_required/insufficient_evidence/blocked/unknown, with the capability change on the same screen. - Show capability changes. Pull the highest-signal rows from
verifier.json.capability_review.top_changes[]before listing generic findings. - Name who acts next. Use
control.next_action.actorandfix_task.safe_to_attempt; a human-routed task is not safe for a coding agent to self-resolve. - Top blockers named by
check_idandtool_name, with a one-sentence "why it matters" pulled frommetadata.rationale(useagents-shipgate explain-finding <FINGERPRINT> --json). - Apply / review split. What you applied automatically, what needs human review. Always show the auto-applied diff.
- Reports paths. The agent shouldn't hide where the reports landed; the user may want to read them.
- CI status. Mention whether
init --ciwrote a workflow.
- Merge verdict and capability changes come from
verifier.json. - Summary counts in the headline come from
agent_summary.{blocker_count, review_item_count, auto_appliable_patches, needs_human_review}. - Top blockers come from
release_decision.blockers[]. For each, runagents-shipgate explain-finding <FINGERPRINT> --jsonto get the metadata + evidence + templated explanation; quote the explanation or rewrite for tone. - Diff blocks come from the
apply-patches --apply --jsonoutput'sfilesobject — keyed by file path, with each entry exposingstatus,patches,diff,error. IterateObject.entries(out.files)(orout["files"].items()in Python) and render eachdiffwith standard+/-markers. - Review-item table comes from walking
findings[]filtered byrelease_decision.review_items[].fingerprint.
human_review_required: replace the headline with "human review required; N review item(s)". Still split byagent_action. Still cite the auto-applied diff if there was one.mergeable: a one-liner is fine ("Agents Shipgate is mergeable; advisory CI is wired."). Mention the verifier/report paths so the user can verify.unknown: do not call the PR mergeable. Surfacebase_status,head_status, and the first next action fromverifier.json.- Evidence-only
human_review_required: the headline IS therelease_decision.reason. Surface it verbatim with a follow-up question about whether to gather more evidence (MCP/OpenAPI inputs, eval traces).
prompts/add-shipgate-to-repo.md— the recipe that produces this artifact.prompts/recommend-fixes.md— coordinated remediation pass.prompts/explain-finding-to-user.md— translate one finding into user-facing prose.docs/agent-action-guide.md— per-category recipes.mcp-only-tool-server/,openai-agents-sdk-refund-agent/,openapi-support-agent/— sibling golden PRs with full manifests.