Skip to content

Adds GitHub Projects V2 fetching to skill-tree.#29

Open
gme-muriuki wants to merge 13 commits into
nikomatsakis:masterfrom
gme-muriuki:design/projects-fetch
Open

Adds GitHub Projects V2 fetching to skill-tree.#29
gme-muriuki wants to merge 13 commits into
nikomatsakis:masterfrom
gme-muriuki:design/projects-fetch

Conversation

@gme-muriuki
Copy link
Copy Markdown
Collaborator

Adds GitHub Projects V2 fetching to skill-tree.

  • fetch_project() returns a complete ProjectFetch -- project metadata, paginated items, and fully-resolved sub-issue connections -- in a single async call. Config typos are caught after one cheap metadata query, before the paginated item fetch.

Changes:

  • Add fetch_project() plus fetch_project_meta, fetch_project_items, and resolve_sub_issue_overflow (three GraphQL documents)
  • Validate [colors] and [[field]] against returned project metadata, collecting every mismatch into one error
  • Detect organization vs. user owner in a single round-trip by probing both namespaces in one document
  • Add design docs: project-fetch, node-model, edge-convention
  • Deploy mdbook to GitHub Pages on master pushes

Tests:

  • integration coverage via wiremock fixtures in tests/project_metadata.rs, tests/project_items.rs, tests/project_fetch.rs -- covers happy path, pagination, sub-issue overflow, config-mismatch fail-fast, and both owner-kind branches.

gme-muriuki and others added 12 commits May 12, 2026 13:01
Add an AGENTS.md / CLAUDE.md pair: CLAUDE.md imports AGENTS.md;
AGENTS.md holds the agent contract for documentation updates,
build/test discipline, and co-authorship. Restructure the
design docs to be factual and descriptive. md/summary.md gains
a style block codifying these conventions.

- AGENTS.md, CLAUDE.md: new at repo root.
- md/summary.md: add style block.
- md/design/01-config.md: rewrite, 184 → 75 lines.
- md/design/02-github-client.md: rewrite, 285 → 94 lines;
  remove the v2-scope appendix.

Co-authored-by: Claude <claude@anthropic.com>
Describes the three-query strategy for github/projects.rs
(metadata, items, sub-issue overflow), the typed FieldValue enum
with #[serde(other)] Unknown for forward-compat, and ItemContent
carrying Issue / PullRequest / DraftIssue / Redacted unfiltered
through the transport layer.

- md/design/project-fetch.md: new.
- md/summary.md: repoint design TOC at the three docs that exist.
- fix naming of the md files

Co-authored-by: Claude <claude@anthropic.com>
mdbook serve was failing on the additional-css reference because
the theme directory does not exist.

fix: mdbook path failures due to inconcistency in the naming convention
in the summary.md file

git ignore the generated book directory by the mdbook
Define the typed response shapes for the items half of the
project-fetch query: FieldValue (Text, Number, SingleSelect, Date,
Iteration, plus an Unknown variant for forward-compat), ItemContent
(Issue, PullRequest, DraftIssue, plus Redacted for null content or
unrecognized __typename), and the supporting struct types
(ProjectItem, IssueContent, PullRequestContent, DraftIssueContent,
SubIssueRef, NodeList).

Includes serde fixture tests for every typed FieldValue and
ItemContent variant, the Unknown / Redacted forward-compat paths,
and a full ProjectItem round-trip.

Co-authored-by: Claude <claude@anthropic.com>
Co-Authored-By: Claude <claude@anthropic.com>
node-model and edge-convention cover the graph layer that slice 2
will build: node identity, label format with auto repo prefix,
cluster derivation from a SingleSelect field, ghost nodes for
off-board endpoints, and deterministic node and edge sort.

Edge sources are GitHub-native only — sub-issue, blocking, and
cross-reference — with on-board endpoint filter and an optional
source-issue label filter on cross-refs. Blocking and cross-refs
both come from github/issues.rs in a later slice.

project-fetch tightened. fetch_project now takes &Config and
validates against ProjectMeta after the metadata query, before the
items query, so a misconfigured field name fails fast on one cheap
call instead of after the full paginated fetch. Sub-issue overflow
is resolved eagerly inside fetch — graph layer receives complete
sub-issue lists, never pagination state. Errors gain a
ConfigMismatch variant.

  Co-authored-by: Claude <claude@anthropic.com>
Labels move to slice 2 — github/issues.rs fetches them alongside
blocking and cross-references, where the cross-ref label filter
needs them. Slice 1 doesn't render labels, so carrying LabelRef
on IssueContent and PullRequestContent is dead weight.

createdAt on DraftIssueContent gives drafts a deterministic sort
key. Issues and pull requests sort by (repository, number); drafts
have no number, so the sort tail is (created_at, id) per the
node-model determinism rule.

Co-authored-by: Claude <claude@anthropic.com>
  Probes organization(login) and user(login) in a single GraphQL
  document — at most one branch is non-null since GitHub's account
  namespaces are disjoint — and returns ProjectMeta carrying the
  detected owner_kind for downstream queries to reuse. Saves one
  round-trip on user-owned projects compared to a sequential
  org-then-user fallback.

  Three project field shapes ride through one flat RawProjectField
  (typename + dataType + options + configuration) and collapse to
  the typed ProjectField + FieldKind in code, keeping the Unknown
  variant cheap and forward-compatible with future GitHub field
  kinds. Iteration fields carry their iteration list fully modeled
  (id, title, startDate, duration), not stubbed.

  Two new error variants: OwnerUnreachable when both probes return
  null (nonexistent or token-private owner — GitHub returns null in
  both cases, so we don't pretend to distinguish them); ProjectNotFound
  { owner_kind } when the owner resolves but the project number does
  not, so the message can say "organization X has no project #N"
  rather than a generic not-found.

  Tests: unit fixtures cover RawProjectField → FieldKind routing for
  each typename and the dataType sub-cases. Integration tests against
  MockGitHub cover both owner kinds, the both-null path, the
  project-null path on each owner kind, and the mixed-FieldKind
  deserialization end-to-end.

  Co-authored-by: Claude <claude@anthropic.com>
  Replace the project_meta_fixture() helper with inlined JSON to keep
  each test readable top-to-bottom. project-fetch.md now records that
  metadata fetch probes organization and user in one GraphQL document.
  fetch_project_items pages the project items connection at first:100,
  stitches the pages, and returns a flat Vec<ProjectItem>. Sub-issues
  ride along inline at first:50.

  resolve_sub_issue_overflow walks the items, finds issues whose inline
  sub-issue connection reports has_next_page, and follows up with the
  per-issue overflow query at first:100 until the list is complete.
  Sets has_next_page false on every resolved issue so the graph layer
  can rely on nodes being the full list.

  IssueContent.sub_issues changes from NodeList<SubIssueRef> to
  Connection<SubIssueRef> to expose the overflow flag during fetch;
  existing tests updated for the new shape.

  Co-authored-by: Claude <claude@anthropic.com>
  fetch_project sequences metadata fetch, Config::validate_against,
  items fetch, and sub-issue overflow resolution into one async call
  returning ProjectFetch { meta, items }. Validation runs after the
  cheap metadata query and before the paginated items query, so a typo
  in .skill-tree.toml fails fast on one round-trip.

  Config::validate_against walks every applicable rule, accumulating
  mismatches into Vec<ConfigIssue>. A missing colors.github-name, an
  option value that isn't on the SingleSelect, and a [[field]]
  github-name that doesn't exist on the project surface together
  instead of one at a time. GitHubError::ConfigMismatch carries the
  vec and renders one line per issue.

  Project numbers widen from u32 to u64 throughout the metadata path
  to match the existing GithubConfig.project field type.

  Co-authored-by: Claude <claude@anthropic.com>
@gme-muriuki gme-muriuki requested a review from nikomatsakis May 12, 2026 10:36
@gme-muriuki gme-muriuki self-assigned this May 12, 2026
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