krz/hutch

an ios client for sourcehut

clone: git clone https://gitbay.org/krz/hutch.git

76cb006b87d30928ec23a3c4bf95bd145aad8e9c

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2026-07-16T05:03:06Z

chore: bump to 3.8.0 and record Phase 3 API features

MARKETING_VERSION 3.7.0 -> 3.8.0, build 89 -> 90.

SCOPE.md gains the items that did not survive contact with the API: archiveMessage
and mailingListSubscribe are blocked, while webhooks, shareSecret, and build
groups are reachable but declined on judgement. The reasoning is recorded so
they do not get re-proposed as gaps.

ROADMAP.md notes that Phase 3 is several releases rather than one, with the
measured size of each.
 Hutch.xcodeproj/project.pbxproj | 24 ++++++++++----------
 README.md                       |  5 ++++-
 ROADMAP.md                      | 50 ++++++++++++++++++++++++++++-------------
 SCOPE.md                        | 21 +++++++++++++++++
 4 files changed, 71 insertions(+), 29 deletions(-)

diff --git a/Hutch.xcodeproj/project.pbxproj b/Hutch.xcodeproj/project.pbxproj
index 8f71248..32da475 100644
--- a/Hutch.xcodeproj/project.pbxproj
+++ b/Hutch.xcodeproj/project.pbxproj
@@ -597,7 +597,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 89;
+				CURRENT_PROJECT_VERSION = 90;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				ENABLE_PREVIEWS = YES;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -614,7 +614,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 3.7.0;
+				MARKETING_VERSION = 3.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -634,7 +634,7 @@
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				CODE_SIGN_ENTITLEMENTS = Hutch/Hutch.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 89;
+				CURRENT_PROJECT_VERSION = 90;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				ENABLE_PREVIEWS = YES;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -651,7 +651,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 3.7.0;
+				MARKETING_VERSION = 3.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -714,7 +714,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 89;
+				CURRENT_PROJECT_VERSION = 90;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = HutchWidgetExtension/Info.plist;
@@ -724,7 +724,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 3.7.0;
+				MARKETING_VERSION = 3.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
@@ -743,7 +743,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				CODE_SIGN_ENTITLEMENTS = HutchWidgetExtension/HutchWidgetExtension.entitlements;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 89;
+				CURRENT_PROJECT_VERSION = 90;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = HutchWidgetExtension/Info.plist;
@@ -753,7 +753,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 3.7.0;
+				MARKETING_VERSION = 3.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
@@ -772,7 +772,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 89;
+				CURRENT_PROJECT_VERSION = 90;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = HutchSafariExtension/Info.plist;
@@ -782,7 +782,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 3.7.0;
+				MARKETING_VERSION = 3.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchSafariExtension;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
@@ -801,7 +801,7 @@
 				APPLICATION_EXTENSION_API_ONLY = YES;
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 89;
+				CURRENT_PROJECT_VERSION = 90;
 				DEVELOPMENT_TEAM = ZCNAX3VL9D;
 				GENERATE_INFOPLIST_FILE = NO;
 				INFOPLIST_FILE = HutchSafariExtension/Info.plist;
@@ -811,7 +811,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 3.7.0;
+				MARKETING_VERSION = 3.8.0;
 				PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchSafariExtension;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
diff --git a/README.md b/README.md
index fd553a8..721d456 100644
--- a/README.md
+++ b/README.md
@@ -14,13 +14,16 @@ The app currently includes:
 - Home dashboard with assigned tickets, recent builds, and projects
 - Repository browsing for Git and Mercurial repositories
 - Repository details including README, references, commits, diffs, files, artifacts, and settings
+- Artifact upload and deletion on release tags
 - Tracker and ticket browsing, ticket detail views, and tracker creation
 - Ticket editing and deletion, with subscriptions for tickets and trackers
 - Build job browsing, build detail views, and build submission
 - Inbox and mailing list reading flows
 - Patchset review: cover letters, per-patch diffs, checks, version chains, and status changes
+- Mailing list creation, settings, and deletion
+- Ticket activity feed across every tracker you follow
 - Paste browsing, creation, and detail views
-- Profile and account settings, including SSH keys, PGP keys, and personal access token management
+- Profile and account settings, including SSH keys, PGP keys, personal access token management, and the audit log
 - Email preferences for todo.sr.ht and lists.sr.ht
 - Deep links for repositories, tickets, and build jobs
 
diff --git a/ROADMAP.md b/ROADMAP.md
index f08981d..7c64af3 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -131,22 +131,40 @@ GraphQL mutation. Treat that boundary as explicit rather than half-building it.
 
 ## Phase 3: Polish and reach
 
-- **Localization.** The project sets `LOCALIZATION_PREFERS_STRING_CATALOGS =
-  YES` but ships no string catalog, so every user-facing string is hardcoded
-  English.
-- **Accessibility.** Labels and hints appear in only 16 of roughly 130 view
-  files.
-- `uploadArtifact` / `deleteArtifact` — artifacts are read-only today.
-- Webhook management. Zero calls to any `create*Webhook` across every service.
-  Push notifications are out of scope because they need a relay server (see
-  [SCOPE.md](SCOPE.md)), but webhook management is client-side only and is a
-  prerequisite if that relay ever ships.
-- `auditLog` (meta.sr.ht) — unused security surface.
-- Build groups (`createGroup`, `startGroup`) and secret management
-  (`shareSecret`, the `secrets` query). Today `secrets` is only a submit toggle.
-- Mailing list creation and settings (`createMailingList`, `updateMailingList`,
-  `deleteMailingList`).
-- `events` feed (todo.sr.ht) and `archiveMessage` (lists.sr.ht).
+Unlike Phases 1 and 2, this is not one shippable thing. It is several, and they
+are sized very differently — measure before committing to one.
+
+### API features — done (v3.8.0)
+
+- ~~`uploadArtifact` / `deleteArtifact`~~ — artifacts were read-only.
+- ~~`auditLog` (meta.sr.ht)~~ — surfaced under the tokens in Profile.
+- ~~Mailing list creation and settings~~ (`createMailingList`,
+  `updateMailingList`, `deleteMailingList`).
+- ~~`events` feed (todo.sr.ht)~~ — a ticket activity feed under More.
+
+Four of the six planned. The other two did not survive contact:
+
+- `archiveMessage` is `@internal` and inaccessible.
+- Webhook management, `shareSecret`, and build groups are reachable but declined
+  on judgement — see [SCOPE.md](SCOPE.md) for the reasoning, so they do not get
+  re-proposed.
+
+### Localization
+
+The project sets `LOCALIZATION_PREFERS_STRING_CATALOGS = YES` but ships no
+string catalog, so every user-facing string is hardcoded English. Roughly 634
+literals: 239 `Text(`, 150 `Label(`, 117 `Button(`, 77 `Section(`, 51
+`navigationTitle(`.
+
+Worth knowing before starting: a catalog containing only English changes nothing
+for users until translations exist. It is groundwork, and it is the largest diff
+in the roadmap — it touches nearly every view, with the regression risk that
+implies.
+
+### Accessibility
+
+Labels and hints appear in 17 of 89 view files. Mechanical and low-risk, but it
+cannot be verified from a build — it needs VoiceOver driven on a device.
 
 ### Swift 6 language mode
 
diff --git a/SCOPE.md b/SCOPE.md
index b4f668f..008d084 100644
--- a/SCOPE.md
+++ b/SCOPE.md
@@ -7,3 +7,24 @@
 - Explore / search (hub.sr.ht) (no public discovery API)
 - Pronouns on profile (not in GraphQL schema)
 - Revoke personal access tokens (`@internal` in schema, inaccessible)
+- Archive a message to a list (`archiveMessage` is `@internal`, inaccessible)
+- Subscribe to a mailing list (`mailingListSubscribe` exists, but `MailingList`
+  has no `subscription` field and sr.ht has no discovery API, so there is no way
+  to find a list you are not already subscribed to — see hub.sr.ht above)
+- Submitting patches (a `git send-email` flow, not a GraphQL mutation; Hutch
+  reviews patchsets but cannot send them)
+
+## Declined rather than blocked
+
+These are reachable in the API. They are left out on judgement, not capability.
+
+- **Webhook management** (24 fields across five services). A webhook needs an
+  HTTPS endpoint you control to receive POSTs. Without the relay above, this
+  only serves someone already running their own endpoint, and that person is not
+  managing it from a phone. Reconsider if `hutch-notify` ever ships.
+- **`shareSecret`.** Shares a build secret — an SSH key or PAT — with another
+  user. A mistap grants someone else a credential, and nothing in the app can
+  take it back. That belongs on the web behind a full-size confirmation. The
+  read-only `secrets` list would be fine on its own.
+- **Build groups** (`createGroup`, `startGroup`). Multi-job pipelines are
+  authored in `.build.yml`, not composed on a phone.