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> | ||