Both documents told the reader to pin Xcode 26.4 and to install it via a
Brewfile. A probe of novaloop-mac-studio-001 refutes the premise: it carries
exactly one Xcode, 26.6, globally selected, with no versioned siblings and no
26.4 anywhere. The design justified the pin with "the runner has it and the
legacy pipeline proves it works" — both halves are false, and a pin naming an
absent version does not fail fast: xcodes starts a multi-GB authenticated
download that no CI secret can satisfy, so before_all hangs.
Record the no-pin decision and its cost — whatever Xcode the runner has is what
ships, unrecorded — rather than only deleting the wrong instruction, so nobody
reintroduces the pin from the same reasoning. Drop the Brewfile with it: its only
purpose was installing xcodes for that pin, and brew has no business running on a
shared release machine where it could upgrade xcodegen mid-release.
Add the runner's real constraints (no passwordless sudo, single Xcode, five
missing tools installed by hand) to the design, since they are why upstream's
setup_github_actions_environment cannot run here.
Two new risks. The legacy element-ios pipeline pins the same absent 26.4, so it
is very likely broken right now — not this fork's problem to fix, but the human
needs to know before the next legacy release. And with no pin, an Xcode upgrade
on the runner silently changes the compiler for every subsequent release.
The plan's embedded Fastfile and skill now match the branches that implement
them byte-for-byte, so the plan cannot drift from the artefacts it describes.
Task 6 Step 3 asserted the guard must fail before xcodes runs. It cannot:
fastlane's before_all always executes before the lane body, and the plan puts
xcodes in before_all and the guard in the lane. The acceptance criterion was
unmeetable on any machine.
The guard still does what it exists for — aborting before the ~30 minutes of
signing — so the wording was wrong, not the pipeline. Also record that the step
needs the xcodes CLI, since without it the lane dies earlier with an error that
reads like a config problem.
Task 11 described the skill's sections rather than showing them, the one place
the plan told an implementer what to write instead of what to type. Replace it
with the complete SKILL.md.
Writing it surfaced a broken convention worth not copying: the legacy skill
documents healthchat-v1.5.0-rc1 style tag suffixes, but the workflow derives the
marketing version by stripping only the healthchat-v prefix, so the suffix reaches
CFBundleShortVersionString, which Apple caps at three integers. Tags are numeric
only here, and test builds go through workflow_dispatch with the marker in the
release notes.
Task-by-task plan for the three PRs in the release design: the classic migration
fix, the fastlane pipeline, and the releasing-healthchat skill.
The migration fix gets a real test cycle — an existing upstream test,
classicAppAccountRequiresBackup, encodes the behaviour we're changing, so it is
rewritten first and drives the view model change.
Spec for bringing App Store release capability to element-x-ios, targeting the
existing HealthChat record that the legacy element-ios fork ships to today.
Both apps share bundle id ch.healthchat.element and team 6G37K72W82, so element-x
arrives as an in-place update rather than a new listing. That drives the design:
the identity already aligns and 26.07.3 clears the legacy's 1.4.1, but the repo
has no release machinery at all, and upstream's Xcode Cloud path is unavailable
because it needs the private Enterprise submodule.
Records three parts: repointing CLASSIC_APP_* at HealthChat's own identifiers so
existing users keep their sessions and encrypted history, a fork-owned fastlane
pipeline ported from the legacy fork, and a releasing-healthchat skill.
Revised after an adversarial review of every factual claim; 26 issues found, none
rejected. Most consequential: the migration fix is not monotonic, because making
loadAccounts() succeed exposes a backup-instructions sheet whose only button opens
element://open — a scheme this app does not register and whose legacy owner has
been replaced in place.
Continue grouping the standalone modules under Components. Updates the
Secrets.swift references in the app, NSE and Share Extension targets along
with the SwiftLint, SwiftFormat, gitignore, post-checkout hook and forking
documentation paths.
* Bump the version for the next release.
* Ignore all generated sources.
* Use Pkl+XcodeGen to inject secrets instead of the project.
* Inject the PostHog/Sentry/Rageshake configuration from the environment.
* Fix bad unicode.
* Fix unit tests.