Receber por email
← Voltar para o catálogo

postmerge

This skill should be used when verifying a merged PR deployed correctly and production is healthy.

14estrelas
Atualizado há 2 meses

Ver no GitHub ↗ Licença: NOASSERTION

Como adicionar

/plugin marketplace add jikig-ai/soleur

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/postmerge/svg)](https://www.skillteca.com.br/skills/postmerge)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

postmerge Skill

<!-- postmerge-harness-protocol:start -->

Harness adapter (Claude vs Grok Build)

Invoke via Claude: soleur:postmerge <PR> | Grok: /postmerge <PR>.

Polling CI / health checks without asking the operator:

  • Claude Code: Monitor tool for Phase 2 main CI and Phase 3 health retries.
  • Grok Build: AwaitShell with pattern (completed success, postmerge verification complete) or Shell with block_until_ms.

Canonical: plugins/soleur/lib/harness.ts → pollInstructions(). Parent skills (ship Step 3.8, one-shot Step 8) MUST invoke postmerge before <promise>DONE</promise>. <!-- postmerge-harness-protocol:end -->

Purpose: Enforce post-merge verification so bugs that only appear in production context are caught immediately after merge -- not days later. This closes the "last mile" gap where QA passes locally but production diverges (stale files, unapplied migrations, CSP violations from injected scripts).

CRITICAL: No command substitution. Never use $() in Bash commands. When a step says "get value X, then use it in command Y", run them as two separate Bash tool calls -- first get the value, then use it literally in the next call.

Arguments

$ARGUMENTS should contain the PR number. If omitted, detect from the most recently merged PR on the current branch.

Phase 1: Verify PR is Merged

Confirm the PR reached MERGED state:

gh pr view <number> --json state,mergeCommit,headRefName --jq '{state, mergeCommit: .mergeCommit.oid, branch: .headRefName}'

If state is not MERGED, stop:

STOPPED: PR #<number> is not merged (state: <state>). Run /soleur:merge-pr first.

Record the merge commit SHA for later verification.

Phase 2: Wait for CI on Main

Check the latest CI run on main triggered by the merge:

gh run list --branch main --limit 3 --json databaseId,status,conclusion,headSha

Find the run matching the merge commit SHA. If no matching run yet, poll with the harness adapter (max 5 minutes) — Claude: Monitor tool; Grok: AwaitShell/Shell per pollInstructions(). Do NOT ask the operator to watch CI. Do NOT use Bash run_in_background:

for i in $(seq 1 20); do
  result=$(gh run view <run-id> --json status,conclusion --jq '{status, conclusion}')
  echo "$(date +%H:%M:%S) $result"
  echo "$result" | grep -q '"completed"' && break
  sleep 15
done

React to the final status from the Monitor output.

If CI passes: Proceed to Phase 3.

If CI fails: Report the failure with details:

gh run view <run-id> --log-failed 2>&1 | tail -50

Stop:

STOPPED: CI failed on main after merge.

Run ID: <run-id>
Conclusion: <conclusion>

Failed log tail:
<last 50 lines>

Investigate before proceeding. The merge is complete but production may not deploy.

Phase 3: Verify Production Deployment

Check if a health endpoint is configured. Look for deployment URLs in environment or project config:

# Check for DEPLOY_URL or PRODUCTION_URL in environment
echo "${DEPLOY_URL:-not_set}"
echo "${PRODUCTION_URL:-not_set}"

If a production URL is available, verify the deployment:

curl -sf --max-time 10 "<production-url>/health" | jq .

Use /health (the public, middleware-/CSP-bypassed health route returning {"status":"ok","version","build_sha","supabase","sentry",...}), NOT /api/health — the latter is an authenticated API route that 307-redirects an unauthenticated probe to /login, so curl -sf fails and HEALTH_VERIFIED is left false even when production is healthy. The build_sha field also confirms the merge commit is the live build.

If health check succeeds: Record the response, set HEALTH_VERIFIED=true, and proceed.

If health check fails or no URL configured: set HEALTH_VERIFIED=false, warn, and proceed (not all PRs trigger deployments):

WARNING: No production health check available. Skipping deployment verification.

HEALTH_VERIFIED is the explicit signal Phase 3.8 gates the feature-tweet draft on — a ship tweet must only be drafted for a feature confirmed live. Track it as a literal true/false; do NOT infer "verified" from "reached this line" (the warn-and-proceed branch also falls through to the next phase).

Phase 3.5: Sentry Cron Monitor Health

Verify scheduled functions are healthy post-deploy by querying Sentry cron monitors.

Prerequisites: SENTRY_AUTH_TOKEN (or SENTRY_API_TOKEN fallback) must be available. If missing, warn and skip:

WARNING: SENTRY_AUTH_TOKEN not set. Skipping Sentry health verification.

Query cron monitors:

SENTRY_TOKEN=$(doppler secrets get SENTRY_AUTH_TOKEN -p soleur -c prd --plain 2>/dev/null || \
  doppler secrets get SENTRY_API_TOKEN -p soleur -c prd --plain)
SENTRY_ORG=$(doppler secrets get SENTRY_ORG -p soleur -c prd --plain 2>/dev/null || echo "jikigai")
API_HOST="${SENTRY_ORG}.sentry.io"

curl -sfS -H "Authorization: Bearer ${SENTRY_TOKEN}" \
  "https://${API_HOST}/api/0/organizations/${SENTRY_ORG}/monitors/?per_page=100" \
  | jq '[.[] | {slug: .slug, status: .status}] | map(select(.status != "ok" and .status != "active"))'
  • If all monitors report ok or active: "Sentry cron monitors: all healthy"
  • If any monitor reports error or missed: flag with monitor name and status. This is a WARNING, not a blocker — the monitor may have been unhealthy before this deploy.
  • If Sentry API is unreachable or returns non-200: warn and skip (do not block on Sentry outages).

Graceful degradation: This check is advisory. A Sentry API failure does not block the postmerge pipeline.

Inngest liveness awareness (#6374)

Surface any OPEN inngest-down alarm so the operator is never told "prod is healthy" while the durable trigger layer (armed reminders + all server/inngest/functions/ crons) is dark. The external watchdog (scheduled-inngest-health.yml) files [ci/inngest-down] on a confirmed down; this is a cheap read that needs no Sentry token:

gh issue list --label ci/inngest-down --state open \
  --json number,title,createdAt --jq '.[] | "#\(.number) \(.title) (opened \(.createdAt))"'
  • If it prints an open issue: surface a one-line advisory — "ADVISORY: inngest reports down (#<n>) — armed reminders and scheduled crons may not be firing; the external watchdog is auto-restarting / escalating. Do not assume scheduled work ran." Include it prominently in the Phase 7 report.
  • If empty: silent (no line needed).

Advisory only — never hard-block the turn. inngest-down does not block all work; the operator retains agency. (An optional deeper probe — curl the /hooks/inngest-liveness HMAC+CF-Access hook — is available for a live verdict but is not required here; the open-issue read is the cheap default.)

Phase 3.6: Sentry Error-Count Delta (Fix Efficacy)

A merged-and-deployed fix can pass every gate above and still not work — the deploy is healthy, monitors are alive, files are fresh, but the error keeps firing because the fix addressed the wrong root cause (the KB-sync / oauth-probe failure class). Phase 3.5 proves the monitor is alive; this phase asks the harder question: did the error this PR claims to fix actually stop?

Run only when the PR body or linked issue names a specific Sentry issue (a *.sentry.io/issues/<id> URL, a SENTRY-<SHORTID>, or a Closes #N whose issue references one). If no Sentry issue is identified, skip silently — there is no error to measure.

Prerequisites: same SENTRY_AUTH_TOKEN resolution as Phase 3.5 for the aggregate Discover count. The single-issue GET below, however, requires the write-scoped SENTRY_ISSUE_RW_TOKEN — the /organizations/<org>/issues/<id>/ endpoint returns 403 on the read-only SENTRY_AUTH_TOKEN/SENTRY_API_TOKEN (they carry Discover/ingest scope, not event:read on the issue resource). Using the read token here makes the curl -sfS GET exit non-zero, leaving `ISSUE_J

Compartilhar X LinkedIn