What it solves
Answering “what actually shipped under this Objective?” used to mean walking the tree by hand: open the Objective, expand its sub-issues, click into each child, check whether a PR closed it, note it down, go back, do the next one. Five levels deep, that is dozens of clicks to answer one question — and it has to be redone every sprint.
But the clicking is the smaller problem. The tree does not stay in one repo. An Objective’s work spills into other repositories, other orgs, and other projects, and GitHub’s own UI will not show you a sub-issue tree that crosses those boundaries. So the manual walk doesn’t just take an afternoon — it goes cold at the first boundary. You end up with a partial answer and no way to know what you missed.
The crawler doesn’t care where a child lives. Every node it fetches carries its own
repository.nameWithOwner, so traversal simply continues across repos and orgs; a repo you can’t
read degrades to empty children instead of aborting the whole crawl. One pass, one report, whatever
boundaries the work happens to straddle.
The tree is the same on both sides — what changes is whether a repository boundary is a wall or
just another edge to follow. Each node carries its own repository.nameWithOwner, so
one crawl spans repos, orgs and projects and emits a single report.
What it does
Answers “what actually shipped under this Objective?”. For every Objective on a board, the PR Finder action walks the sub-issue tree — up to 5 levels, across repos and orgs — and lists the pull requests that close those issues. This dashboard is the reading surface: a report picker across accumulated PI/sprint-named reports, each rendered as USWDS-styled HTML.
The relationship it follows is closedByPullRequestsReferences(includeClosedPrs: true) — the
closes #N / linked-branch link, not loose cross-references. includeClosedPrs also surfaces
PRs that were closed without merging.
Where the data comes from
.github/workflows/pr-finder.yml runs the action weekly and publishes CSV + Markdown + HTML to the
pr-finder/report branch, accumulating one report per PI/sprint plus a reports/index.json. The
shell fetches that index at runtime into the picker, then loads the chosen report HTML into an
iframe via srcdoc. It falls back to the bundled index.snapshot.json + pr_finder_all.html.
Run it locally
# The dashboard is static — just open it.
open pr-dashboard/index.html
# Regenerate a report offline against a canned tree (no network):
python pr-finder/generate_pr_finder.py \
--tree-json seed/sample_tree.json --out-dir reports
Related
- The generating Action:
NASA-IMPACT/veda-github-actions/pr-finder@v1 - Crawl model, seed harness and gotchas:
docs/PR_FINDER.md