Commit cf8a3ed49f
Unsigned
Layout: unified · split
ROADMAP.md added +112
| @@ -0,0 +1,112 @@ | ||
| 1 | # Roadmap | |
| 2 | ||
| 3 | Planned work for Hutch, ordered by dependency. Feature gaps below were | |
| 4 | identified by diffing the GraphQL schema dumps in `Docs/API` against actual | |
| 5 | call sites in the Swift source. | |
| 6 | ||
| 7 | See [SCOPE.md](SCOPE.md) for features that are intentionally out of scope. | |
| 8 | ||
| 9 | ## Phase 0: Unblock CI — done (v3.5.0) | |
| 10 | ||
| 11 | Nothing downstream is trustworthy until the build badge means something. | |
| 12 | ||
| 13 | - ~~Fix `repo-structure-check` in `builds/swift-ci.yml`~~. It asserted | |
| 14 | `test -d "website"`, but `website/` was removed in `24c8bc6` (2026-04-10), so | |
| 15 | the check had failed since then. | |
| 16 | - ~~Add a macOS CI job that runs `xcodebuild test`~~. builds.sr.ht has no macOS | |
| 17 | image and its maintainer has ruled them out, so `xcodebuild` cannot run there. | |
| 18 | The test plan now runs on the GitHub mirror via `.github/workflows/test.yml`; | |
| 19 | builds.sr.ht keeps secret scanning and structure checks. | |
| 20 | ||
| 21 | Turning the gate on first required making the suite green. All 214 tests had | |
| 22 | been running only on demand in Xcode, and ten had rotted: | |
| 23 | ||
| 24 | - The `Hutch` scheme referenced `container:HutchTests` without the | |
| 25 | `.xctestplan` extension, so `xcodebuild test -scheme Hutch` — the path the | |
| 26 | README sends contributors down — could not run at all. | |
| 27 | - Five were test-side rot: uppercase GraphQL enum rawValues asserted as | |
| 28 | lowercase, an ordering expectation predating `sortBuildItemsForTriage`, | |
| 29 | `request.httpBody` read inside a `URLProtocol` (always nil; the body lives on | |
| 30 | `httpBodyStream`), an incident fixture contradicting its own RSS input, and an | |
| 31 | image assertion that treated the correct `&` attribute encoding as a bug. | |
| 32 | - Four were real bugs the suite had been right about all along: repository | |
| 33 | descriptions could not be cleared (a nil subscript assignment drops the key | |
| 34 | instead of sending JSON null), `serviceNotProvisioned` was unreachable behind | |
| 35 | a broader `no such` match, code spans rendered their contents as live markup, | |
| 36 | and inbox threads keyed `id` on a subject-derived grouping key so two threads | |
| 37 | sharing a subject on one list collided under `Identifiable`. | |
| 38 | ||
| 39 | ## Phase 1: Close the write gaps | |
| 40 | ||
| 41 | Small, independently shippable mutations that already exist in the API but are | |
| 42 | never called. Each removes a "why can't I do this here?" moment. | |
| 43 | ||
| 44 | - `updateTicket` — edit ticket title and description after creation. Currently | |
| 45 | a ticket can be created and its status changed, but never edited. | |
| 46 | - `deleteTicket` — delete a ticket. | |
| 47 | - `trackerSubscribe` / `trackerUnsubscribe`, `ticketSubscribe` / | |
| 48 | `ticketUnsubscribe`, `mailingListSubscribe` / `mailingListUnsubscribe` — | |
| 49 | subscriptions are currently read-only. `MailingListListView` reads the | |
| 50 | `subscriptions` query, but nothing can subscribe or unsubscribe. | |
| 51 | - `updatePreferences` (todo.sr.ht and lists.sr.ht) — email notification | |
| 52 | preferences. | |
| 53 | ||
| 54 | ### Refactors to fold in | |
| 55 | ||
| 56 | These are touched by everything in later phases, so they belong here rather | |
| 57 | than as standalone work. | |
| 58 | ||
| 59 | - `SRHTClient` has four near-identical request-and-decode paths (`execute`, | |
| 60 | `executeMultipart`, `executeMultipartFiles`, `executeAndCache`, plus the | |
| 61 | private `performGraphQLRequest`). The token guard, header setup, status-code | |
| 62 | handling, and a ~35-line `#if DEBUG` logging block are each duplicated about | |
| 63 | five times. Collapse to one request builder and one decode helper. | |
| 64 | - Two caches overlap: the in-memory `responseCache` and the persistent `cache`, | |
| 65 | reached through two different `executeCached` overloads with different return | |
| 66 | types and semantics (one does stale-while-revalidate with TTLs, the other only | |
| 67 | checks memory). Unify on the TTL-aware path. | |
| 68 | ||
| 69 | ## Phase 2: Patchsets | |
| 70 | ||
| 71 | The flagship gap. There is currently no reference to `patchset` anywhere in the | |
| 72 | Swift source, yet lists.sr.ht exposes a full `Patchset` type (subject, version, | |
| 73 | prefix, status, coverLetter, patches, tools, mbox), a `patchset` query, and an | |
| 74 | `updatePatchset` mutation. Sending and reviewing patches over email is the | |
| 75 | SourceHut contribution model, and Hutch cannot currently participate in it. | |
| 76 | ||
| 77 | Scope this as review-and-triage, not submission: | |
| 78 | ||
| 79 | - Patchset list per mailing list. | |
| 80 | - Patchset detail: cover letter, per-patch diffs (reuse the existing | |
| 81 | `DiffView`), version and superseded-by chain. | |
| 82 | - Status transitions via `updatePatchset`. | |
| 83 | ||
| 84 | Patch *submission* is an email / `git send-email` flow and is likely out of | |
| 85 | reach from the app. Treat that boundary as explicit rather than half-building | |
| 86 | it. | |
| 87 | ||
| 88 | ## Phase 3: Polish and reach | |
| 89 | ||
| 90 | - **Localization.** The project sets `LOCALIZATION_PREFERS_STRING_CATALOGS = | |
| 91 | YES` but ships no string catalog, so every user-facing string is hardcoded | |
| 92 | English. | |
| 93 | - **Accessibility.** Labels and hints appear in only 16 of roughly 130 view | |
| 94 | files. | |
| 95 | - `uploadArtifact` / `deleteArtifact` — artifacts are read-only today. | |
| 96 | - Webhook management. Zero calls to any `create*Webhook` across every service. | |
| 97 | Push notifications are out of scope because they need a relay server (see | |
| 98 | [SCOPE.md](SCOPE.md)), but webhook management is client-side only and is a | |
| 99 | prerequisite if that relay ever ships. | |
| 100 | - `auditLog` (meta.sr.ht) — unused security surface. | |
| 101 | - Build groups (`createGroup`, `startGroup`) and secret management | |
| 102 | (`shareSecret`, the `secrets` query). Today `secrets` is only a submit toggle. | |
| 103 | - Mailing list creation and settings (`createMailingList`, `updateMailingList`, | |
| 104 | `deleteMailingList`). | |
| 105 | - `events` feed (todo.sr.ht) and `archiveMessage` (lists.sr.ht). | |
| 106 | ||
| 107 | ## Housekeeping | |
| 108 | ||
| 109 | - `Hutch/Hutch/App/AccountSession.swift` sits in a stray nested directory; | |
| 110 | `Hutch/HutchTests/` is empty. | |
| 111 | </content> | |
| 112 | </invoke> | |