Skip to content

feat(0.2): report pr --fail-on + report impact --explain-selection (Tracks 3.1/3.2)#143

Open
pmclSF wants to merge 1 commit intofeat/0.2.1-gate-flagsfrom
feat/0.2-pr-impact-gates
Open

feat(0.2): report pr --fail-on + report impact --explain-selection (Tracks 3.1/3.2)#143
pmclSF wants to merge 1 commit intofeat/0.2.1-gate-flagsfrom
feat/0.2-pr-impact-gates

Conversation

@pmclSF
Copy link
Copy Markdown
Owner

@pmclSF pmclSF commented May 2, 2026

Summary

Two of the five Track-3 "load-bearing centerpiece" deliverables. These are what turn pitch claims into binary behavior.

Base branch: `feat/0.2.1-gate-flags` (PR #134, which adds the severity gate primitives this PR reuses). Will rebase onto main after #134 merges.

Track 3.1 — `terrain report pr --fail-on `

Pitch claim defended: "Gate changes based on that system as a whole."

Pre-fix, `--fail-on` existed only on `analyze`. The two-step primary workflow (`analyze && report pr`) silently lost the gate at the second step.

Implementation reuses the same `severityGateBlocked` helper #134 introduced. Added `prSeverityBreakdown(severities []string) analyze.SignalBreakdown` that converts a PR's `NewFindings` + `AI.BlockingSignals` into the same shape `analyze.SignalSummary` uses, so the gate decision logic is shared, not duplicated.

Same render-then-gate pattern as analyze: every output format renders before the gate decision returns through the error channel. `--json --fail-on=high` produces a valid JSON document on stdout AND exits with code 6 if the gate fired — the JSON-stdout-purity property #134 introduced.

Wired through both the legacy `terrain pr` command and the canonical `terrain report pr` namespace dispatcher.

Track 3.2 — `terrain report impact --explain-selection`

Pitch claim defended: "See which tests matter for a PR — and why."

Pre-fix, `report impact` showed selected tests but not the reason chains. The "and why" half of the pitch wasn't deliverable.

Implementation reuses `internal/explain.ExplainSelection` + `reporting.RenderSelectionExplanation` (already shipping for `terrain explain selection`). When the flag is set, runImpact computes the selection explanation and renders it with `verbose=true` so per-test evidence (selection reasons, code unit matches, confidence) appears.

`--json --explain-selection` emits the structured `SelectionExplanation` for tooling consumption.

Wired through both `terrain impact` and `terrain report impact`.

Test plan

  • `TestPRSeverityBreakdown` — 4 table cases (empty / mixed bag / case-insensitive + whitespace / unknown-severities-dropped-silently)
  • `go test ./cmd/terrain/` — green; `TestCLISmoke_PRCommand` updated for new `runPR` signature
  • `go test ./...` full suite green
  • `go test ./internal/testdata/` golden + CLI suite green

Plan link

`/Users/pzachary/.claude/plans/kind-mapping-turing.md` (Tracks 3.1 / 3.2). Three Track 3 items remain — 3.3 (integration-test classification), 3.4 (E2E attribution), 3.5 (unified PR-comment audit) — as separate follow-ups.

🤖 Generated with Claude Code

…racks 3.1/3.2)

Two of the five "load-bearing centerpiece" Track 3 deliverables that
turn the unified pitch into something the binary actually delivers.

Track 3.1 — `terrain report pr --fail-on <severity>`
  Defends the pitch claim "Gate changes based on that system as a
  whole." Pre-fix, --fail-on existed only on `analyze`; the gating
  flow (`analyze && report pr`) silently lost the gate at the second
  step.

  Implementation reuses the same severityGateBlocked helper that
  PR #134 introduced for analyze. Added prSeverityBreakdown(severities
  []string) that converts a PR's NewFindings + AI BlockingSignals
  into the same SignalBreakdown shape `analyze.SignalSummary` uses,
  so the gate decision logic is shared, not duplicated.

  Wired through both the legacy `terrain pr` command (deprecated
  alias of `terrain report pr`) and the canonical `terrain report
  pr` namespace dispatcher.

  Same render-then-gate pattern as analyze: every output format
  (json, markdown, comment, annotation, default text) renders
  before the gate decision returns through the error channel. So
  `--json --fail-on=high` produces a valid JSON document on stdout
  AND exits with code 6 if the gate fired — the property the launch-
  readiness review's "JSON stdout purity" gate test asks for.

  Tests:
    - TestPRSeverityBreakdown: empty / mixed bag / case-insensitive
      / unknown-severities-dropped-silently table
    - cli_smoke_test.go updated for the new runPR signature

Track 3.2 — `terrain report impact --explain-selection`
  Defends the pitch claim "See which tests matter for a PR — and
  why." Pre-fix, `report impact` showed selected tests but not the
  reason chains; the "and why" half of the pitch wasn't deliverable.

  Implementation reuses the existing internal/explain.ExplainSelection
  + reporting.RenderSelectionExplanation (already shipping for
  `terrain explain selection`). When --explain-selection is set,
  runImpact computes the selection explanation and renders it
  with verbose=true so per-test evidence (selection reasons, code
  unit matches, confidence) appears.

  Wired through both `terrain impact` (legacy) and `terrain report
  impact` (canonical). --json + --explain-selection emits the
  SelectionExplanation JSON structure for tooling consumption.

Pillar parity impact: Track 3.1 + 3.2 are the centerpiece work that
the plan calls "highest-priority track — every pitch claim must be
directly verifiable in the CLI output before 0.2.0 ships." This PR
closes two of the five Track 3 items; 3.3 (integration-test
classification rigor), 3.4 (E2E attribution), and 3.5 (unified
PR-comment audit) are separate follow-ups.

Verification:
  go build ./...                clean
  go test ./cmd/terrain/        green (4 new TestPRSeverityBreakdown
                                cases; existing TestCLISmoke_PRCommand
                                updated for new signature)
  go test ./...                 full suite green
  go test ./internal/testdata/  golden + CLI suite green

Plan link: /Users/pzachary/.claude/plans/kind-mapping-turing.md
(Tracks 3.1 / 3.2).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant