Skip to content

feat: migrate the fosmvvm-bootstrap scaffolder into FOSUtilities - #140

Merged
foscomputerservices merged 11 commits into
mainfrom
feat/fosmvvm-bootstrap-migration
Aug 23, 2026
Merged

feat: migrate the fosmvvm-bootstrap scaffolder into FOSUtilities#140
foscomputerservices merged 11 commits into
mainfrom
feat/fosmvvm-bootstrap-migration

Conversation

@foscomputerservices

Copy link
Copy Markdown
Owner

What this is

The fosmvvm-bootstrap scaffolder migrates into FOSUtilities, per the approved design in docs/superpowers/plans/2026-08-22-fosmvvm-bootstrap-migration-design.md (all ten ruling points ruled; the design and the workflow-session handoff ride in this PR).

Distribution story

  • swift run fosmvvm-bootstrap new --output ~/MyApp from a bare clone runs a short validated interview — project name defaulted from the output directory, per-device platform questions (Mac / iPhone / iPad / TV / Vision / Watch), the two "Designed for iPad/iPhone" compatibility questions, floors as version defaults. --config is the automation path; --verbose echoes the equivalent config; --verify opts into the build/test doors (CI verifies every release the same way).
  • DocC: CreatingAProject.md in FOSMVVM (linked from the FOSFoundation landing, SPI's default); README carries the one-minute block.
  • doctor is design-declared as an SPM command plugin; implementation remains Plan 5.

Structure

  • FOSMVVMBootstrap (library, templates as resources) + FOSMVVMBootstrapCLI → executable product fosmvvm-bootstrap + FOSMVVMBootstrapTests, all gated to Mac hosts at the manifest (FOSMVVMVapor precedent). Adds swift-argument-parser.
  • The release-stamped Release.version replaces the hand-maintained pin; docs/RELEASING.md records the ritual; ReleaseConsistencyTests fail CI on drift (version ↔ CHANGELOG stamp, floors ↔ this package's platforms).
  • Generated projects: destinations follow the config exactly (xcodegen supportedDestinations, target-level device-family/compat overrides — target settings beat project settings, measured), macOS opt-in like every platform, watch as its own target (a multiplatform app target cannot contain watchOS), verify door derives its destination from the config.

CI

  • Fast suite (~3 s) + env-gated walking skeletons + the generation-matrix job on every PR (ruled): generated UI tests on iOS Simulator and macOS, simulator pre-booted, one retry iteration against the measured cold-simulator first-run tap flake. The generated-UI-test legs are the design's declared least-proven part — this PR is their first live run; expect iteration.

Verified on the branch

  • Fast suite 40/40; walking skeletons 3/3 (all three shapes emit and verify from inside FOSUtilities).
  • Emission probes built green: iOS-only, tvOS Simulator, visionOS Simulator, watch targets (both shapes), iPhone-only device family, compat opt-outs (-showBuildSettings confirmed target-level wins).
  • David's live interview runs drove out and fixed: silent key-typo UX (→ interview), ignored iOS platform (→ destinations follow config), .xcodeproj missing under --skip-verify (→ xcodegen is generation, not verification), Mac-only destination editor (→ supportedDestinations), framework targets showing undeclined destinations (→ overrides on every target), compat rows uninvited (→ questions, Apple-default yes), prompts misnaming the device family.

Follow-ons (named, not in this PR)

  • FOSTestingUI first-interaction settle (cold-simulator first-run tap flake) + probe scenario; then the CI retry becomes belt-and-braces.
  • Watch UI-test harness in UITestingProbe (Xcode 27 ships XCUIAutomation for watchOS; README matrix re-measure).
  • Conditional entitlements/hardened-runtime for Mac-less projects (carried caveat in 8687389).
  • tvOS/visionOS legs in the generation matrix as those platforms get probe coverage.

Sources/tests move in from fosmvvm-bootstrap as FOSMVVMBootstrap(+CLI/Tests),
mac-host-gated at the manifest. The release-stamped Release.version replaces
the hand-maintained FOS pin, ReleaseConsistencyTests fail CI on stamp or
platform-floor drift, and the walking skeletons gate behind
FOSMVVM_BOOTSTRAP_SKELETONS=1 so bare swift test stays fast.
CreatingAProject.md (FOSMVVM DocC, linked from the FOSFoundation landing),
the README one-minute block, docs/RELEASING.md, and the
bootstrap_generation_matrix CI job: fast suite, gated skeletons, and the
generated apps' own UI tests on iOS Simulator and macOS, every PR.
…onfig's platforms exactly

new without --config runs a validated interview (name defaulted from the
output directory; Mac/iPhone/iPad/TV/Vision/Watch each opt-in; the two
Designed-for-iPad/iPhone compat modes asked with Apple's default;
--verbose echoes the equivalent config; --verify opts into the doors,
which pick their destination from the config; xcodegen runs as generation,
never as skippable verification). Emission uses xcodegen
supportedDestinations with target-level device-family/compat overrides, so
every target's destination surface reads exactly the answers; the watch
ships as its own target (a multiplatform app target cannot contain
watchOS), embedding the same frameworks, which carry the watchOS
destination.
CI simulators are always the cold case, which is the measured first-run
tap-flake condition; pre-boot plus -retry-tests-on-failure keeps a
settling flake visible without redding the PR. The durable fix is
FOSTestingUI's first-interaction settle (follow-on).
@foscomputerservices
foscomputerservices force-pushed the feat/fosmvvm-bootstrap-migration branch from a4decf7 to 3b2d0ef Compare August 22, 2026 16:31
The generated-app build is an inner xcodebuild spawned by the Verifier,
so the job's -skipMacroValidation flag never reaches it. Set
IDESkipMacroFingerprintValidation runner-wide so the generated project
can build against FOSMacros on a fresh runner.
Each skeleton resolves and builds the full FOSUtilities dependency
graph; in parallel they starve a hosted runner past the per-test time
limits, and the resulting kill also discards the not-yet-run tests.
…onment

When the scaffolder itself runs under xcodebuild test, the harness's
XCTest session variables leak into the Verifier's child processes; the
generated project's own test runner then tries to attach to the
harness's IDE session and hangs on a handshake that never comes, or
exits non-zero with every generated test green. Verifier.verify now
strips XCTest*/DYLD_* from the inherited environment before spawning
steps (caller overlay still wins), so verification behaves identically
from a shell and inside a test runner.

All three walking skeletons verified green locally under the
CI-identical xcodebuild invocation (sharedLibrary 64s, localOnly 58s,
clientServer 113s).
…stination

Generation follows the config's platforms exactly, so the macOS-only
demo configs produced projects with no iOS Simulator destination and
the iOS UI-test leg could not match one. Both configs now request
iOS 17.0 alongside macOS, and the SUPPORTED_PLATFORMS command-line
override — which papered over the missing platform — is gone.

All four legs (LocalDemo/ServerDemo x iPhone 17 simulator/macOS)
verified green locally with the CI-identical invocations.
CI showed a freshly launched app can discard its first synthesized tap
(the event synthesizes, the app idles, and the expected UI change never
comes — a per-launch window, so simulator pre-boot and test retries
don't close it). The generated test-support base gains
tap(_:until:timeout:): tap, poll for the UI change the tap must cause,
re-tap once at half timeout. All seven generated tap sites use it, ops
reads follow the witness instead of racing the transporter repaint, and
BoardViewTests' claim that no waiting is needed is corrected.

The primitive lives in the generated support layer because generated
projects pin released FOSUtilities; migrating it into FOSTestingUI is
the durable follow-on.

All four generated-app legs verified green locally (LocalDemo/ServerDemo
x iPhone 17 simulator/macOS, CI-identical invocations).
…uns them full-screen

Without the declaration iOS letterboxes the app (compatibility sizing:
a 603pt window centered on an 874pt iPhone 17 screen), and the reported
element frames disagree with the tap-dispatch coordinate space — every
synthesized tap misses, deterministically. The 26.5 runtime letterboxes
where 27.0 does not, which is why the generated UI tests failed on CI's
simulator and passed locally.

Reproduced and verified on the 26.5 runtime locally: the failing alert
tests go green (and drop from 16-28s of futile polling to 5-7s). All
four generated-app legs green locally.
@foscomputerservices
foscomputerservices merged commit 16fad08 into main Aug 23, 2026
14 checks passed
@foscomputerservices
foscomputerservices deleted the feat/fosmvvm-bootstrap-migration branch August 23, 2026 16:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant