Skip to content

GitHub transport: whole-map GraphQL read and single-ticket REST refresh - #126

Merged
mayfieldiv merged 2 commits into
mainfrom
ticket-117-github-transport
Aug 28, 2026
Merged

GitHub transport: whole-map GraphQL read and single-ticket REST refresh#126
mayfieldiv merged 2 commits into
mainfrom
ticket-117-github-transport

Conversation

@mayfieldiv

Copy link
Copy Markdown
Owner

Implements #117 (spec §4 of the wayfinder ticket surface spec — the resolution comment on #112). Part of map #123.

What

  • Wire types in src/github/types.rs: Issue (the PR analog for issues), IssueState, SubIssuesSummary, DependenciesSummary — permissive #[serde(default)] posture — plus the IssueState → TicketState mapping and shared claim_from_assignees / ticket_type_from_labels rules, so the map read and the single-ticket refresh can't drift.
  • fetch_wayfinder_map in graphql.rs: the spec's verbatim one-query map read (cost 10, flat in map size), normalized straight into ticket::Effort. The envelope impl GraphQlErrors (with a test proving HTTP-200 errors can't parse as empty success). Blocked-ness inputs come from the blockedBy list with per-node state and repository.nameWithOwner — the eventually-consistent summary counters aren't even deserialized on this path.
  • get_issue + list_issues_with_label in rest.rs beside list_issue_comments, via a generalized get_all_with. GET …/parent is never called; every 404 stays a genuine error (including the missing-Issues-scope case). The issues listing drops the PRs the endpoint mixes in.
  • §4.4 fallback detection, detect-and-degrade only: a zero-sub-issue map with a task-list body flags fallback_dialect; has_fallback_dependency_lines covers Part of #n / Blocked by: #n leading lines for the drill-in path. Nothing is parsed into the model.
  • Per-Effort degradation (§5.5): a malformed map lands in failed_maps instead of discarding the repo's other Efforts.
  • Parsers are pure parse_* fns with fixture tests in graphql/tests.rs / rest/tests.rs (11 new tests; 761 total green).

Decisions the spec didn't settle (small, resolved in-ticket)

  • A same-repo blocker that isn't one of the map's sub-issues is an External Dependency, not Unknown — its state/title were captured, so "can't find or read" would be false.
  • Ticket URLs aren't stored: they derive from TicketKey (the PrKey::html_url() precedent); Ticket detail page #122 adds the /issues/ accessor.
  • parent_issue_url stays a raw wire string until a consumer navigates by it.
  • Assignees on closed tickets are kept (state × claim orthogonality, spec §1); GitHub's Claim is the first assignee when several exist.
  • A truncated blockedBy page (impossible under the first:50 cap) degrades to an Unknown Dependency so unseen blockers can't put a ticket on the Frontier.

…issue refresh

Implements #117 (spec §4). fetch_wayfinder_map runs the spec's verbatim
one-query map read (cost 10, flat in map size) and normalizes straight
into ticket::Effort: claims from assignees, Type from the wayfinder:
label, dependencies from the blockedBy list (same-effort / external /
unknown), never the eventually-consistent summary counters. get_issue /
list_issues_with_label cover the single-ticket refresh and label
listing; the §4.4 fallback dialect is detected (task-list map bodies,
leading Part of / Blocked by lines) but never parsed into the model.
…ules

Review fixes on #117: a malformed map now lands in failed_maps instead
of discarding the whole read (spec §5.5); the Claim and wayfinder-label
Type rules move to shared helpers so the single-ticket refresh (#120)
can't drift from the map read; Destination extraction accepts any
heading level; the summary types drop their unused GraphQL aliases and
their docs now tell the truth about who deserializes them.
Copilot AI lite review requested due to automatic review settings August 28, 2026 21:04
@mayfieldiv
mayfieldiv merged commit 0c2c187 into main Aug 28, 2026
2 checks passed
@mayfieldiv
mayfieldiv deleted the ticket-117-github-transport branch August 28, 2026 21:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new body_has_task_list helper uses strip_prefix(['-', '*', '+']), which is likely a compile error and must be corrected before merge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds the GitHub-side transport needed for the Wayfinder ticket surface: a single GraphQL whole-map read normalized into ticket::Effort, plus REST endpoints/parsers for single-ticket refresh and label-filtered issue discovery, with shared wire/domain mapping utilities to avoid drift.

Changes:

  • Introduces GitHub “Issue” wire/domain types and shared normalization helpers (IssueState parsing, claim/type derivation) in src/github/types.rs.
  • Implements whole-map GraphQL read + normalization into Effort (with degradation signals) and adds REST get_issue / list_issues_with_label with pagination support.
  • Adds fixture-driven parsing tests for both the GraphQL map read and REST issue refresh/listing behavior.
File summaries
File Description
src/ticket.rs Updates module TODO comment to reflect the local-parser/fetch-layer integration plan.
src/github/types.rs Adds issue-related wire types + shared claim/type derivation helpers used by both GraphQL and REST paths.
src/github/rest.rs Adds REST issue fetch + label-filtered listing; generalizes pagination helper to accept query params; adds issue parsing/filtering.
src/github/rest/tests.rs Adds tests for REST single-issue parsing defaults, state handling, and listing PR-filter behavior.
src/github/graphql.rs Adds GraphQL whole-map read response types + normalization pipeline and fallback-dialect detection helpers.
src/github/graphql/tests.rs Adds comprehensive tests for map parsing, dependency classification/degradation, and body helper behavior.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/github/graphql.rs
Comment on lines +673 to +681
fn body_has_task_list(body: &str) -> bool {
body.lines().any(|line| {
let Some(rest) = line.trim_start().strip_prefix(['-', '*', '+']) else {
return false;
};
let rest = rest.trim_start();
rest.starts_with("[ ]") || rest.starts_with("[x]") || rest.starts_with("[X]")
})
}
@augmentcode

augmentcode Bot commented Aug 28, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: This PR adds the GitHub transport foundation for the Wayfinder ticket surface.

Changes:

  • Adds permissive GitHub issue, issue-state, sub-issue, and dependency-summary wire types.
  • Introduces a whole-map GraphQL read for open, label-selected map issues.
  • Normalizes map sub-issues, claims, types, and blocker relationships into ticket-domain Efforts.
  • Preserves external blockers and degrades unreadable or truncated blocker data to Unknown dependencies.
  • Surfaces map pagination and per-map normalization failures without discarding healthy maps.
  • Adds REST single-issue refresh and label-filtered issue listing, excluding PRs from issue results.
  • Shares assignee and label mapping rules between GraphQL and REST paths.
  • Detects, but deliberately does not parse, legacy body-based fallback dialect signals.
  • Adds fixture coverage for map parsing, error handling, fallback detection, and REST issue parsing.
Technical Notes: GraphQL-level errors are surfaced despite HTTP 200 responses; frontier status is derived from individual blocker states rather than eventually consistent summary counters.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread src/github/graphql.rs
}
let lower = trimmed.to_ascii_lowercase();
let is_dependency_line = lower.starts_with("part of ") || lower.starts_with("blocked by:");
if is_dependency_line && line_has_issue_ref(trimmed) {

@augmentcode augmentcode Bot Aug 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/github/graphql.rs:700: This loop never tracks fenced code blocks, so a leading code sample containing Part of #123 returns true even though the function documents that references in code fences do not match. That incorrectly reports the fallback dialect for a ticket using only native data.

Severity: low

Other Locations
  • src/github/graphql.rs:679

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

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.

2 participants