Skip to content

Live Acceptance Dry-Run of the PR Post-Merge Flow #132

Description

@sameera

Re-scoped 2026-07-25

The Success Metrics below describe a scratch-repo exercise. That is no longer the plan, and
the metrics that mention a scratch repo, the full chain, or a 30-minute reproduction are stale.

What changed. The epic's real question — does range derivation pick the right base against
real GitHub — needs a real merged PR, not a disposable one. This repo has a dozen. Measuring
against them read-only cost minutes, required no delete_repo scope, and returned 6/6 PASS with
zero divergences, including post-branch-delete pull/<N>/head reachability on four PRs whose
branches are actually gone. Recorded as
Run 2026-07-25.

Standing metrics, revised:

Why #134 and #136 were closed. Review publishing is unreachable on a single account, so the
analyze exercise would only have measured the comment fallback the next real epic exercises for
free; and close/distill failures are loud and recoverable, unlike a silently-wrong range. Neither
justified granting repo-delete to the maintainer's credential. Full rationale in each issue.

The nxs-pr-acceptance harness (#133) is retained as the controlled reproduction if something
misbehaves for real — it is no longer a gate.

Epic: Live Acceptance Dry-Run of the PR Post-Merge Flow

Description

The --pr post-merge flow — analyze --pr on the open PR, merge, then close --pr and
distill in one shared worktree — is the flow that decides which diff the distiller reads weeks
later. Its riskiest mechanics (merge-strategy-safe range derivation, the worktree lifecycle, the
analyze receipt that close reads back) live in libs/pr-worktree and are covered by unit tests
that inject a fake command runner. Those tests prove the logic given the git and gh output we
believe real GitHub produces. Nothing in the build environment has ever run the flow against an
actual pull request.

That gap matters most where the code already knows it is guessing. Range derivation cannot tell a
squash from a rebase by topology alone and disambiguates by comparing changed-file sets against a
fetched PR head; it deliberately refuses rather than stamps an ambiguous range. Whether real
GitHub merges produce the parent counts, SHAs, and post-branch-delete reachability those branches
assume is an empirical question, and a wrong answer is silent — it surfaces as the wrong concept
pages being rewritten long after the PR is forgotten.

This epic buys that evidence once and makes it cheap to re-buy. It builds a throwaway scratch
repo harness, drives the whole chain against it under each of the three merge strategies, and
leaves behind a runbook plus an acceptance record. It does not fix what it finds: divergences
between live behavior and the injected-runner assumptions are captured as filed issues or backlog
stubs, so the fix is a separately-sized decision rather than unbounded work smuggled into an
acceptance check.

Success Metrics

  • All three merge strategies (squash, merge commit, rebase) are exercised against a real hosted
    PR and each either yields a range verified against the authoritative PR file set or exits with a
    named diagnostic — zero silently-wrong ranges.
  • The full analyze --pr → merge → close --pr → distill chain completes on the scratch repo with
    no manual git or gh intervention beyond the harness's own commands.
  • A maintainer can reproduce the entire exercise from the runbook on a clean checkout in under
    30 minutes.
  • Every divergence between live behavior and the injected-runner unit tests is captured as a filed
    issue or backlog stub; the count is reported (and may legitimately be zero).
  • Teardown leaves zero residue — no scratch repo, no stray git worktrees, no branches in the host
    checkout.

Personas

Per docs/product/context.md. This epic is exercised by the maintainer/delivery lead persona
only; it adds no end-user-facing surface.

Assumptions

  • The scratch repo is created under the same GitHub owner as this repo, is treated as disposable,
    and is deleted at teardown; a keep-alive flag is available for debugging a failed run.
  • This is a maintainer-invoked, on-demand exercise, not a CI job — docs/system/stack.md
    records that no CI is configured for this repo yet.
  • gh is authenticated with sufficient scope to create, merge into, and delete a repository.
  • The exercise makes real GitHub API calls; no attempt is made to mock, record, or replay them.
  • Where live behavior contradicts an injected-runner unit test, the live behavior is treated
    as authoritative and the test is the thing recorded as suspect.

Out of Scope

  • Hub / multi-repo workspace live runs — the stub scopes this to a single scratch repo; member-repo
    --pr support remains the separate member-pr-post-merge-flow backlog stub.
  • Fork-originated PR heads (the pull/<N>/head fetch path) — proving it needs a second GitHub
    account, which is a larger setup than this check justifies.
  • Member-repo rejection of --pr, which is a pure role-gate check already covered by unit tests.
  • Wiring the acceptance run into CI.
  • Fixing whatever the dry-run finds. Divergences are recorded and filed; each fix is sized and
    scheduled separately.

Open Questions

None.

Metadata

Metadata

Assignees

No one assigned

    Labels

    epicEpic (created by nxs-gh-create-epic)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions