Commit 9c41ef5269

9c41ef52694ff59e40d2bcc02780146136802f61

parent: fec160e859

Unsigned

cmc <hello@cleberg.net> · 2026-07-16 16:07 UTC

chore: record the SonarCloud + housekeeping pass, bump to 3.8.1

Update the roadmap's SonarCloud section to the live 53-issue / 10-rule
reality and mark what v3.8.1 fixed, silenced-as-bug, and left Won't Fix.
Bump MARKETING_VERSION on the app, widget, and Safari extension.

Layout: unified · split

Hutch.xcodeproj/project.pbxproj +6 −6
@@ -614,7 +614,7 @@
614614 "$(inherited)",
615615 "@executable_path/Frameworks",
616616 );
617 MARKETING_VERSION = 3.8.0;
617 MARKETING_VERSION = 3.8.1;
618618 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
619619 PRODUCT_NAME = "$(TARGET_NAME)";
620620 STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -651,7 +651,7 @@
651651 "$(inherited)",
652652 "@executable_path/Frameworks",
653653 );
654 MARKETING_VERSION = 3.8.0;
654 MARKETING_VERSION = 3.8.1;
655655 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch;
656656 PRODUCT_NAME = "$(TARGET_NAME)";
657657 STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -724,7 +724,7 @@
724724 "@executable_path/Frameworks",
725725 "@executable_path/../../Frameworks",
726726 );
727 MARKETING_VERSION = 3.8.0;
727 MARKETING_VERSION = 3.8.1;
728728 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
729729 PRODUCT_NAME = "$(TARGET_NAME)";
730730 SKIP_INSTALL = YES;
@@ -753,7 +753,7 @@
753753 "@executable_path/Frameworks",
754754 "@executable_path/../../Frameworks",
755755 );
756 MARKETING_VERSION = 3.8.0;
756 MARKETING_VERSION = 3.8.1;
757757 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchWidgetExtension;
758758 PRODUCT_NAME = "$(TARGET_NAME)";
759759 SKIP_INSTALL = YES;
@@ -782,7 +782,7 @@
782782 "@executable_path/Frameworks",
783783 "@executable_path/../../Frameworks",
784784 );
785 MARKETING_VERSION = 3.8.0;
785 MARKETING_VERSION = 3.8.1;
786786 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchSafariExtension;
787787 PRODUCT_NAME = "$(TARGET_NAME)";
788788 SKIP_INSTALL = YES;
@@ -811,7 +811,7 @@
811811 "@executable_path/Frameworks",
812812 "@executable_path/../../Frameworks",
813813 );
814 MARKETING_VERSION = 3.8.0;
814 MARKETING_VERSION = 3.8.1;
815815 PRODUCT_BUNDLE_IDENTIFIER = net.cleberg.Hutch.HutchSafariExtension;
816816 PRODUCT_NAME = "$(TARGET_NAME)";
817817 SKIP_INSTALL = YES;
ROADMAP.md +58 −24
@@ -198,23 +198,54 @@ Labels and hints appear in 17 of 89 view files. Mechanical and low-risk, but it
198198cannot be verified from a build — it needs VoiceOver driven on a device.
199199Independent of every other bucket, so it can move if a device pass is convenient.
200200
201### SonarCloud backlog — v3.8.1
202
20351 open issues: **0 bugs, 0 vulnerabilities, 51 code smells**, plus 3 security
204hotspots. The headline number is misleading, so trust the breakdown before
205budgeting:
206
207- **35× `swift:S1075` (hardcoded URI)** — 28 of them in
208 `SourceHutWebDeepLinkMapperTests`, 5 in `Shared/HutchDeepLinkURLs`. A deep-link
209 mapper's tests exist precisely to assert against literal URLs, and a client for
210 one forge has fixed endpoints by definition. These want triaging as *Won't
211 Fix* in SonarCloud, not refactoring. "Fixing" them would make the code worse.
212- **5× `swift:S1135`** — TODO comments. Two are in `HutchIntents` and name real
213 gaps.
214- **3× `swift:S1186` (empty closure)** — all three CRITICAL, all three trivial:
215 `Button("Cancel", role: .cancel) {}` needs no body. A comment settles it.
216- **2× `javascript:S4624`** in the Safari extension; **2× `swift:S1172`** unused
217 parameters.
201### SonarCloud backlog — done in code (v3.8.1)
202
203The live count is **53 issues / 10 rules**, not the 51 / 5 an earlier pass
204recorded — a reminder that this section rots like everything else, so query the
205API before budgeting. **0 bugs, 0 vulnerabilities**; everything is a code smell
206or hotspot. What the code side of v3.8.1 actually did:
207
208Fixed (`e93972f`):
209
210- **`swift:S1871`** — `RootView` had byte-identical `.home` / `.recentActivity`
211 deep-link cases. Merged; recent activity is a *section* of Home, not a screen,
212 so both correctly land on the Home tab.
213- **3× `swift:S1186` (empty closure/function, CRITICAL)** — two are
214 `Button("Cancel", role: .cancel) {}` (dialog dismissal needs no body); the
215 third is an empty `URLProtocol.stopLoading()` override in a test. All three now
216 carry a nested comment. Note the earlier claim that "all three are Cancel
217 buttons" was wrong — only two are.
218- **`swift:S108`** — the expected-miss `catch` in `APICacheTests` is commented.
219- **`swift:S1172`** — the unused `url` in `mimeType(for:)` is now `_`.
220- **2× `javascript:S4624`** — the nested template literal in the deep-link
221 builders (`background.js`, `content.js`) is extracted to a `pathSegment` var.
222
223Fixed as a real bug instead (`65412ee`), not silenced:
224
225- **2× `swift:S1172` on `forceRefresh`** — `HomeViewModel.loadProjects` and
226 `loadSystemStatusSnapshot` took the flag and dropped it, so dashboard
227 pull-to-refresh returned cached projects and status. This is the trap named at
228 the top of this file. `ProjectsListView` carried the same defect via its own
229 `.refreshable`. Both fixed at the root in `ProjectService.fetchProjects`.
230
231Won't Fix, with reasons (resolve in SonarCloud's web UI, not in code):
232
233- **35× `swift:S1075` (hardcoded URI)** — 28 in `SourceHutWebDeepLinkMapperTests`,
234 the rest in `HutchDeepLinkURLs`. A deep-link mapper's tests exist to assert
235 literal URLs, and a one-forge client has fixed endpoints. "Fixing" them makes
236 the code worse.
237- **`swift:S107`** — `executeCached` has 8 params across **38 call sites**. A
238 param object would rewrite the hottest networking method for no behaviour or
239 correctness gain against an arbitrary 7-param line. Not worth the regression
240 surface.
241- **`swift:S1481`** — `ArtifactsView`'s `@Bindable var vm` is flagged unused, but
242 `$vm.error` is used at line 134; Sonar's Swift analyzer misses the projected
243 value. False positive — removing it breaks the build.
244- **`javascript:S7785`** — prefers top-level `await` for `injectBannerIfEnabled()`,
245 but `content.js` is a classic content script, not a module. Top-level `await`
246 would be a syntax error. Not applicable.
247- **5× `swift:S1135`** — TODO comments (INFO). Two in `HutchIntents` name real
248 gaps; leave them until those features land.
218249
219250The 3 hotspots are the part actually worth thought:
220251
@@ -234,10 +265,11 @@ The 3 hotspots are the part actually worth thought:
234265Query it with:
235266`https://sonarcloud.io/api/issues/search?componentKeys=zerolabsco_hutch&resolved=false`
236267
237This is a patch because nothing executes differently afterwards. The 35 hardcoded-URI
238issues are resolved as *Won't Fix* in SonarCloud's web UI — not a commit at all — and
239the rest is three comments and one annotation. If it produces a diff that changes a
240runtime path, something has gone wrong.
268This was scoped as a patch on the assumption nothing executes differently — and
269that mostly held: the cosmetic fixes are comments, a merge, and a rename. The one
270exception earns the release its own line: the `forceRefresh` fix changes what
271pull-to-refresh does, so it needs a manual pass on a device before v3.8.1 ships,
272not just a green suite.
241273
242274### Ingest "What's cooking on SourceHut?" — v3.9.0
243275
@@ -309,7 +341,9 @@ which already consults the persistent cache before the memory layer.
309341Like Swift 6 above, this is internal and rides along with whatever release
310342already touches that area. Neither justifies a tag.
311343
312## Housekeeping — v3.8.1
344## Housekeeping
313345
314- `Hutch/Hutch/App/AccountSession.swift` sits in a stray nested directory;
315 `Hutch/HutchTests/` is empty.
346- ~~`Hutch/Hutch/App/AccountSession.swift` sits in a stray nested directory;
347 `Hutch/HutchTests/` is empty.~~ Done (v3.8.1, `9834b78`). Moved beside the rest
348 of `App/`; both stray dirs removed. No pbxproj change — the target is a
349 synchronized root group, so the file compiled by path all along.