LearnNewsExamplesServices
Frontmatter
id16157
titleagent-preflight misses stacked-PR foreign-ticket declarations
stateClosed
labels
bugdeveloper-experienceaitesting
assigneesneo-gpt-emmy
createdAtJul 30, 2026, 11:02 AM
updatedAtJul 30, 2026, 11:34 AM
githubUrlhttps://github.com/neomjs/neo/issues/16157
authorneo-gpt-emmy
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 30, 2026, 11:34 AM

agent-preflight misses stacked-PR foreign-ticket declarations

Closed Backlog/active-chunk-10 bugdeveloper-experienceaitesting
neo-gpt-emmy
neo-gpt-emmy commented on Jul 30, 2026, 11:02 AM

Context

PR #16156 exposed a deterministic local/hosted validation split.

The author ran:

npm run agent-preflight -- --no-fix --change-class restoration \
  --pr-title "fix(dashboard): retain topology across tear-out projection (#16153)" \
  --pr-body /private/tmp/pr16153-body.md

Local result:

agent-preflight: PR body contains the required template anchors.
agent-preflight: all requested gates passed.

The ready PR then failed hosted lint-pr-body immediately. Its stack legitimately contained two #15955 witness commits beneath the #16153 fix, while the body declared only Resolves #16153. Hosted lint enumerated the PR commits and required the inherited ticket to be declared. Adding Related: #15955 was the correct repair.

Live source confirms the parity gap:

  • .github/workflows/agent-pr-body-lint.yml parses Resolves / Refs / Related, enumerates PR commits, and rejects any ticket-suffixed commit whose ticket is undeclared.
  • buildScripts/util/agent-preflight.mjs --pr-body validates the body anchors locally but does not inspect the branch commit set.

Memory Core, Knowledge Base, live latest-open, and GitHub keyword sweeps found no ticket owning this specific stacked-PR preflight parity.

The Problem

The command presented as the local PR gate can return “all requested gates passed” for a PR body that hosted lint is guaranteed to reject seconds later.

This creates a needless create → CI red → read remote log → edit body cycle at exactly the point where the local preflight is supposed to prevent it. The hosted diagnostic is correct; the missing substrate is an equivalent pre-creation check.

The Architectural Reality

  • Legitimate stacked PRs are allowed. The rule is not “one ticket across every commit”; it is “every ticket claimed by a commit must be declared by the PR body.”
  • Before PR creation there is no pull-request number to query, but the local Git commit graph already contains the necessary commit subjects.
  • The comparison boundary must be the PR branch's commits relative to its intended base/merge-base, not an arbitrary commit count.
  • Ticket declarations and ticket-suffixed commit parsing must remain semantically aligned with hosted agent-pr-body-lint.yml.
  • The check must work before network mutation; requiring an already-created PR would preserve the current friction.

The Fix

  1. Extend the local agent-preflight --pr-body path with an intended-base input (or an equivalent deterministic base resolution).
  2. Enumerate the branch commits that the PR will carry and parse their trailing (#N) ticket claims.
  3. Parse Resolves, Refs, and Related ticket declarations from the candidate PR body using hosted-equivalent semantics.
  4. Fail locally when any ticket-suffixed commit is undeclared, listing the offending SHA, ticket, and subject.
  5. Add unit coverage for a legitimate declared stack, an undeclared inherited ticket, multiple commits for one declared ticket, and a commit without a ticket suffix.
  6. Document the stacked-body invocation in the pull-request workflow.

Decision Record impact

none — this closes parity inside the existing PR-body gate.

Acceptance Criteria

  • The exact #16156 pre-repair shape fails locally before gh pr create.
  • Adding Related: #15955 makes the same stack pass locally.
  • A normal single-ticket branch remains green.
  • Multiple commits for the same declared ticket remain green.
  • Commits without a trailing (#N) stay outside this check, matching hosted ownership.
  • Diagnostics name each offending short SHA, ticket, and subject.
  • Base resolution is explicit or deterministic and does not require an existing PR.
  • Local and hosted ticket-declaration semantics are covered by parity tests or a shared implementation boundary.

Out of Scope

  • Automatically editing the PR body.
  • Automatically rebasing or flattening legitimate stacks.
  • Replacing the ticket gate for commit subjects.
  • Changing which closing keywords Neo permits.

Avoided Traps

  • Do not reject every multi-ticket stack; declared related tickets are valid.
  • Do not use origin/dev..HEAD without accounting for the intended merge-base.
  • Do not require gh pr view or an existing remote PR.
  • Do not copy the hosted parser without a parity guard that can drift silently.
  • Do not report a generic body-template failure when the defect is an undeclared inherited ticket.

Evidence

  • Local preflight false-green: PR #16156 creation attempt, 2026-07-30.
  • Hosted failure: workflow run 30528853945, job 90826121319.
  • Hosted diagnosis: foreign commits 046d3571cd and 3088764ced, both claiming #15955 while the original body declared only #16153.

Origin Session ID: 019fac4d-7844-7422-9486-7f73ccf308f5

Retrieval Hint: agent-preflight stacked PR foreign commit declared ticket lint parity

tobiu referenced in commit 65092de - "fix(build): mirror stacked PR ticket guard locally (#16157) (#16158) on Jul 30, 2026, 11:34 AM
tobiu closed this issue on Jul 30, 2026, 11:34 AM