Repository navigation
feat(lists): finish GitHub-backed list creation and add Refresh from GitHub #51
Description
Summary
The macOS New List sheet shows GitHub source fields that do nothing:
App/Features/Lists/NewListSheetView.swift:85—Section("GitHub source (optional)")
App/Features/Lists/NewListSheetView.swift:98—Text("GitHub source fields will be sent in a future update.")
So a user can fill in a repo and get a plain local list. The web, meanwhile, has a full GitHub-backed list flow, and the client already ships the reading half (issue browser, create-issue-from-message, close/reopen, labels/assignees — G4 + the PR #24 route fixes).
The missing piece is creation and refresh.
What the web does (/help/lists)
Creating:
- Prerequisite: GitHub connected with the Issues scope. "If you already linked GitHub for sign-in, you may need to click Reconnect for GitHub Issues to grant access."
- On the GitHub-backed List tab, select a repository you have access to (a picker, not a free-text field)
- List title defaults to the repo name
- Optional parent list; optional Public toggle
Behaviour once created:
- Rows map to issues (title, body, labels, assignees, state). Adding a row creates an issue; editing a row updates it; deleting a row closes it.
- Schema is fixed — Edit changes only the parent list. "You cannot modify the issue fields … they are defined by GitHub."
- Refresh from GitHub pulls the latest issues (the list caches locally).
- Visibility is re-read from GitHub on every sync (create, manual refresh, scheduled sync).
Live facts (2026-09-07)
GET /api/github/repos → 200 (test account is now GitHub-linked) but the list is EMPTY
GET /api/github/orgs → 200 []
GET /api/auth/github/status → 200 {"configured":true,"clientId":"Ov23li9eXYK1i6psJW6G",
"manageOrgAccessUrl":"https://github.com/settings/connections/applications/…"}
githubSource-on-create request shape cannot be exercised end-to-end today. Before building, either grant the .env test account access to a repo, or capture the web app's own network calls for a create. Do not guess the create-time field names — work-consolidation.md P3-C records githubSource: { owner, repo, path, ref } as unconfirmed.
Also unconfirmed (P3-C)
The refresh metadata the UI needs — lastRefreshedAt, refreshStatus (idle|pending|failed), refreshError — is modelled in the domain as GitHubListSource but has never been seen on the wire. Probe before rendering a refresh state, or render only what is actually returned.
Division of labor
Kit
- Accept
githubSourceonPOST /api/listsonce the shape is confirmed. - A repo-picker request builder over
GET /api/github/repos(already present — confirm the populated shape against a repo-bearing account). - Whatever route drives Refresh from GitHub; if none exists, file the backend ask rather than inventing one.
- Contract tests against a repo-bearing account.
Domain
- Extend list creation with a GitHub source, gated on the subscriber entitlement and on a GitHub identity with Issues scope.
- Model the fixed-schema rule so the schema editor refuses field edits on a GitHub-backed list and offers only the parent-list change.
- Refresh action + refresh state, only for the fields the probe confirms.
App
- Replace the dead GitHub section in
NewListSheetViewwith a real repo picker populated from the account's repos, plus the title default. - An inline Reconnect for GitHub Issues CTA when the identity lacks the scope — reuse the OAuth flow from the Integrations issue rather than building a second one.
- Refresh from GitHub in the list toolbar, with its state surfaced.
- Schema editor: parent-list-only mode for GitHub-backed lists, with an explanation rather than a silently disabled form.
Tests
- happy — pick a repo, create the list, rows arrive as issues
- invalid — GitHub not linked, or linked without Issues scope → the reconnect CTA, no create attempt
- upstream-failure — the repo list 500s → the picker shows an error and the local-list tab still works
- boundary — an account with zero accessible repos (today's test account) → an honest empty picker, not a spinner
Acceptance criteria
- No control in the New List sheet promises something "in a future update".
- A GitHub-backed list created on the Mac behaves the same as one created on the web.
- Full E2E gate green.
Notes
New finding from the 2026-09-07 parity sweep. Depends on P3-C (create-time and refresh shapes) and shares the OAuth scope-upgrade flow with the Integrations issue. Size M.
Activity
Adron commentedon Sep 16, 2026
Blocked — and the blocker is one account permission, not code
Re-probed 2026-09-15. Every other prerequisite is now in place; this is waiting on one thing.
What is ready
GET /api/auth/github/status→200 {"configured":true,"clientId":"Ov23li9eXYK1i6psJW6G","manageOrgAccessUrl":"…"}InterlinedListMessenger).manageOrgAccessUrl"Update organization access…" affordance, and the identity verify/disconnect surface — so the reconnect path this issue shares has somewhere to live.githubRepoPrivate, which this issue lists as item 4.What blocks it
The test account can see no repositories. So:
githubSourcecreate-time field names cannot be exercised end to end (work-consolidation.mdP3-C records{owner, repo, path, ref}as unconfirmed)lastRefreshedAt/refreshStatus/refreshErrorhave never been seen on the wire, so a refresh-state UI would be rendering invented fieldsBuilding a picker and a create body against an empty array is exactly how the G21 link-metadata and G25 org-member defects happened: green tests against fabricated fixtures, a feature that never worked.
What we need from you
Either grant the
.envcontract-test account (messenger@interlinedlist.com) access to at least one repository — a throwaway public repo with two or three issues is enough — or capture the web app's own network calls for a GitHub-backed list creation and paste them here:POST /api/listswhen creating from a repoGET /api/github/repospopulatedOption 1 is better: it also unblocks the Refresh from GitHub route, which this issue notes may not exist at all — and that cannot be determined from an account with no repos.
One thing that can ship without it
The New List sheet still says "GitHub source fields will be sent in a future update." If you would rather not wait, that dead section can be removed and replaced with an honest "connect a repository on the web for now" pointer — this issue's acceptance criterion "no control in the New List sheet promises something in a future update" would then be met. Say the word and I will do that as a small PR.