Skip to content

I1405 — A pull request names the issue it realises, and the edge is derived rather than remembered

Derive the relation between an issue and the pull requests, branches and commits that realised it, from git and from GitHub, and make it traversable in both directions.

DONE wave 1 · p1 · implementation profile · runs alone

Part of work-graph-github — The projection to GitHub is gated, identified and traversable, and a merged pull request leads back to the outcome it served.

Objective

Derive the relation between an issue and the pull requests, branches and commits that realised it, from git and from GitHub, and make it traversable in both directions.

Why

The model reaches as far as a branch: `worktree/state.rs` reads an issue id out of a branch name and the topology gate enforces it. Above the branch there is nothing. A merged pull request does not lead back to the acceptance criteria it satisfied, and an outcome does not lead forward to the code that reached it, which is the question the whole model exists to answer.

Current state

Evidence carries an optional `commit` string written by hand. No canonical record names a pull request, a check run or a branch. `issue_of()` in apps/majordomus-cli/src/worktree/state.rs infers the issue from a branch path component and is the only edge that exists.

Desired state

Given an issue, the branches, commits and pull requests that realised it are derivable. Given a merged commit or a pull request, the issue and the outcome it served are derivable. Nothing is stored that git or GitHub already knows.

Scope

  • apps/majordomus-cli/src/worktree
  • apps/majordomus-cli/src/git
  • apps/majordomus-cli/src/graph.rs
  • scripts/github-sync
  • test/cases
  • docs

Out of scope

  • Requiring a branch to encode an issue id where doctrine does not already require it
  • Storing a commit list in a canonical record; git owns commits

Dependencies

What waits on this

Acceptance criteria

  • Given an issue id, the branches, commits and pull requests that realised it are listed, derived from git and GitHub
  • Given a commit or a pull request, the issue and the milestone it served are named, or it is reported as unattributed
  • Work with no execution contract is reported as unattributed rather than silently omitted
  • The derivation reads no stored edge that git or GitHub already holds

Validation

  • cargo test --workspace --all-features
  • bash test/run.sh

Evidence required

  • traceability_both_ways

Evidence

coverstypecommandresultat commit
traceability_both_waystestenv -u MAJORDOMUS_SHARE bash test/run.sh 98_traceabilityok 98_traceability: over real MCP frames, I0001 (merged with a merge commit) lists its branch, its merge commit and its two commits; I0002 (open) is measured against the trunk; I0003 (fast-forwarded) reports itself absorbed and claims none of the trunk's commits; I0004 (declared, unstarted) traces to nothing and stays declared; I9999 answers declared:false. Backwards, a commit of the merged branch names I0001 and milestone M0, and the commit made straight on the trunk is reported unattributed with a reason. The report's buckets sum to the commits examined, and the absorbed branch's commit is present in it rather than omitted. Then scripts/traceability over a pull-request fixture joins PR #1 to I0001, answers #2 with I0002 and M0, reports #3 (head branch chore/tidy-up) unattributed rather than dropping it, tallies 3 read / 2 attributed / 1 unattributed, and exits 10 under --strict on a commit with no contract. Finally: no canonical record under .ai/repo/project/ names a branch after the run, and git status is unchanged.990bd05

Risk

A commit-to-issue edge inferred from a branch name is only as good as the branch discipline; unattributed must be a reported state, not an assumption.

Timeline

started
2026-09-09T18:55:15Z
verified
2026-09-09T18:55:34Z
completed
2026-09-09T18:55:36Z

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I1405.yaml. Read it back with majordomus plan show I1405.