version: '3'

vars:
  DEFT_ROOT: '{{joinPath .TASKFILE_DIR ".."}}'

# pr:* tasks for PR-level merge-discipline checks.
#
# pr:check-protected-issues is the Taskfile-level encoding of the Layer 3
# pre-merge protected-issue link inspection from
# skills/deft-directive-swarm/SKILL.md Phase 6 Step 1 (#701). Per the Rule
# Authority [AXIOM] block in main.md, deterministic and Taskfile encodings
# rank above prose -- this target wraps the canonical
#   gh pr view <N> --json closingIssuesReferences
# query so a swarm monitor (or any operator) can verify in one command that
# no protected (umbrella / staying-OPEN) issue is GitHub-side linked to the
# PR before squash-merging.
#
# Companion script: scripts/pr_check_protected_issues.py
# Companion test:   tests/cli/test_pr_check_protected_issues.py

tasks:
  check-protected-issues:
    desc: "Verify NO protected (umbrella / staying-OPEN) issue is GitHub-side linked to a PR before squash merge (#701)"
    deps: [":engine:_ts-build"]
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - task: :engine:invoke
        vars:
          ENGINE_CMD: 'pr-protected-issues {{.CLI_ARGS}}'

  # pr:check-closing-keywords -- Layer 0 prevention (#737 FP + #3015 intent).
  # Default --mode both: FP (negation/quote/example/code) + intent (any real
  # Closes/Fixes/Resolves #N unless --allow-close N,M). Body trailers are not
  # an authorization path. Pairs with Layer 3 ``pr:check-protected-issues`` (#701).
  #
  # Per ``conventions/task-caching.md`` (#574): NO ``sources:`` /
  # ``generates:`` because user-facing recovery flags (``--pr``,
  # ``--body-file``, ``--commits-file``, ``--allow-known-false-positives``,
  # ``--allow-close``, ``--mode``) MUST NOT be silently swallowed by go-task cache.
  check-closing-keywords:
    desc: "Scan PR body + commits for closing-keyword FP contexts (#737) and unallowlisted real closes / intent mode (#3015 class D). Default --mode both."
    dir: '{{.USER_WORKING_DIR}}'
    deps: [":engine:_ts-build"]
    env:
      PYTHONUTF8: "1"
    cmds:
      - task: :engine:invoke
        vars:
          ENGINE_CMD: 'pr-closing-keywords {{.CLI_ARGS}}'

  # pr:merge-ready -- programmatic Greptile-body verdict gate. Closes the
  # SUCCESS-with-findings blind spot in the Phase 5 -> 6 merge-readiness
  # checklist. Parses the Greptile rolling-summary comment body (NOT the
  # CheckRun status) for confidence, P0/P1 findings, errored sentinel
  # (#526), and HEAD-SHA freshness. Companion to the swarm SKILL Phase 6
  # Step 1 prose rule. PR #652 incident motivated this gap-closer.
  #
  # Companion script: scripts/pr_merge_readiness.py
  # Companion test:   tests/cli/test_pr_merge_readiness.py
  merge-ready:
    desc: "Verify a PR's Greptile review body satisfies the merge exit condition (confidence >3, no P0/P1, HEAD-SHA fresh, not errored)"
    deps: [":engine:_ts-build"]
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - task: :engine:invoke
        vars:
          ENGINE_CMD: 'pr-merge-readiness {{.CLI_ARGS}}'

  # pr:wait-mergeable-and-merge -- cascade automation surface (#1369).
  # Wraps scripts/pr_wait_mergeable.py which composes the resilient
  # wait-until-ready monitor (#1368) and the Layer-3 protected-issue
  # link inspector (#701) into a single end-to-end primitive so a swarm
  # monitor can request "wait until this PR is mergeable, then merge it"
  # without hand-rolling the loop. The companion script invokes
  # scripts/pr_check_protected_issues.py (Layer-3 #701) BEFORE the wait
  # loop when --protected is supplied, so a persistent
  # closingIssuesReferences link short-circuits the cascade with exit 1
  # ahead of any gh pr merge call. Cascade automation on the Grok Build
  # hybrid path MUST go through this surface per the AGENTS.md
  # `## Cascade automation surface (#1369)` rule.
  #
  # Per `conventions/task-caching.md` (#574): NO `sources:` / `generates:`
  # because user-facing flags (`--cap-minutes` / `--protected` / `--repo`
  # / `--json`) MUST NOT be silently swallowed by go-task's incremental-
  # build cache.
  #
  # Companion script: scripts/pr_wait_mergeable.py
  # Companion test:   tests/cli/test_pr_wait_mergeable.py
  wait-mergeable-and-merge:
    desc: "Wait until PR is mergeable (resilient cascade, #1368) and squash-merge with admin (#1369); Layer-3 protected-issue check (#701) chains before any merge call"
    deps: [":engine:_ts-build"]
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - task: :engine:invoke
        vars:
          ENGINE_CMD: 'pr-wait-mergeable {{.CLI_ARGS}}'

  # pr:watch -- deterministic PR-verdict polling surface (#1056). A
  # blocking-by-default poll that resolves to a terminal three-state verdict
  # (exit 0 CLEAN / 1 NEW_P0_P1 / 2 ERRORED|STALL|TIMEOUT|config), so an
  # orchestrator that promises to poll a PR review to conclusion cannot
  # silently forget (the invocation IS the wait). --one-shot degrades to a
  # single probe. Reuses the CANONICAL Greptile/SLizard verdict detector
  # (packages/core/src/content-contracts/skills/greptile-detector.ts -- the
  # same module pr:merge-ready and the swarm poller template consume); no
  # second detector. SHA-match gating means a stale pre-push review is never
  # read as the verdict. All gh access routes through the UTF-8-safe
  # execFile shim (#1366). Cross-referenced from the AGENTS.md
  # `## Multi-agent orchestration discipline (#954)` Tier-4 pointer.
  #
  # Per `conventions/task-caching.md` (#574): NO `sources:` / `generates:`
  # because user-facing flags (`--one-shot` / `--max-wait-minutes` /
  # `--poll-seconds` / `--json` / `--repo` / `--project-root`) MUST NOT be
  # silently swallowed by go-task's incremental-build cache.
  #
  # Companion module: packages/core/src/pr-watch/
  # Companion tests:  packages/core/src/pr-watch/*.test.ts
  watch:
    desc: "Blocking poll of a PR to a terminal three-state verdict (0 CLEAN / 1 NEW_P0_P1 / 2 ERRORED|STALL|TIMEOUT|config); --one-shot for a single probe (#1056)"
    deps: [":engine:_ts-build"]
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - task: :engine:invoke
        vars:
          ENGINE_CMD: 'pr-watch {{.CLI_ARGS}}'

  # pr:finish-loop -- walk-away PR shepherd (#871 Wave 5 / #2948).
  # Grant-gated wrap of pr:watch until CLEAN; address path is agent-
  # orchestrated (exit 1 on NEW_P0_P1). Respects requireHumanMerge —
  # never force bot merge. Fail closed without finish-loop grant.
  #
  # Companion module: packages/core/src/finish-loop/
  # Contract: content/contracts/finish-loop.md
  finish-loop:
    desc: "Walk-away PR finish loop: grant gate + pr:watch until CLEAN; exit 1 address / human-merge; exit 2 BLOCKED without grant (#871)"
    deps: [":engine:_ts-build"]
    dir: '{{.USER_WORKING_DIR}}'
    cmds:
      - task: :engine:invoke
        vars:
          ENGINE_CMD: 'pr-finish-loop {{.CLI_ARGS}}'
