Polish v1 release flow and prepare v2 rebuild#1
Open
yamcy1225 wants to merge 20 commits into
Open
Conversation
5aba511 to
d20f05a
Compare
added 2 commits
April 6, 2026 17:39
Runimal already has a working phone/watch/mac app and core tooling, so the safest rebuild path is to preserve proven assets while creating separate v2 boundaries for domain, sync, reward, export, UI, and app-shell exploration. This commit adds the documentation and skeleton structure for that path without wiring new targets into XcodeGen or SwiftPM yet. Constraint: project.yml is the XcodeGen source of truth and must not be changed during first-pass skeleton work Constraint: Existing RunimalPhone, RunimalWatch, RunimalMac, SharedUI, RunimalCore, and RunimalCoreTests behavior must remain untouched Rejected: Replacing RunimalCore immediately | too risky before the v2 recording/sync boundaries are proven Rejected: Committing .omx runtime state | local workflow state should not be shared through GitHub Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not connect the V2 skeletons to Package.swift or project.yml until the next phase adds tests and an explicit integration plan Tested: swiftc -parse Sources/RunimalDomainV2/RunimalDomainV2.swift Sources/RunimalSyncV2/SyncBoundaryDraft.swift Sources/RunimalRewardV2/RewardBoundaryDraft.swift Sources/RunimalExportV2/ExportBoundaryDraft.swift Tested: swift test (37 XCTest + 73 Swift Testing tests passed) Not-tested: XcodeGen regeneration or device install, because no project.yml/app-target files changed
added 15 commits
April 23, 2026 18:05
The rebuild plan needed a first executable success beyond documentation, so the v2 domain, sync, reward, and export skeletons are now SwiftPM products with focused tests. The models still sit beside the existing app targets and do not alter the v1 Phone/Watch/Mac surfaces. Constraint: Keep project.yml and app target wiring unchanged during this phase Constraint: Preserve RunimalCore as the calculation and legacy archive backend while v2 boundaries are proven Rejected: Integrating v2 modules into XcodeGen app targets now | premature before adapter tests exist Rejected: Generating bitmap assets in this pass | design needs briefs first and should not block recording-loop verification Confidence: high Scope-risk: moderate Reversibility: clean Directive: Add Watch/Phone adapter tests before importing these v2 modules into app targets Tested: swift test --filter RunimalV2Tests (6 Swift Testing tests passed) Tested: swift test (37 XCTest + 79 Swift Testing tests passed) Tested: git diff --check Not-tested: XcodeGen regeneration or real-device install because project.yml and app target source lists were not changed
RunimalWatch already creates canonical WorkoutSessionArchive values, so the next safe v2 step is a pure SwiftPM adapter that wraps those archives into CompletedRunArchive and SyncEnvelope without importing watch frameworks or touching app targets. Constraint: Do not modify project.yml or app target source wiring during adapter validation Constraint: Preserve WatchRunSessionManager and WorkoutArchiveCanonicalizer as the proven recording/canonicalization path Rejected: Rebuilding the watch session manager now | too risky before adapter and phone-ingest boundaries are tested Rejected: Importing HealthKit/CoreLocation into v2 adapter target | would make the boundary harder to test outside the app Confidence: high Scope-risk: narrow Reversibility: clean Directive: Add the phone-side v2 ingest adapter before wiring RunimalWatchAdapterV2 into WatchConnectivity or app targets Tested: swift test --filter RunimalWatchAdapterV2Tests (4 Swift Testing tests passed) Tested: swift test (37 XCTest + 83 Swift Testing tests passed) Tested: git diff --check Not-tested: XcodeGen regeneration or real-device install because project.yml and app target files were not changed
The phone side now has a SwiftPM-only v2 adapter that turns CompletedRunArchive payloads into existing WorkoutSessionArchive persistence candidates while keeping growth as an unspent RunResource. This keeps RunimalPhone wiring out of scope until app-target tests define the exact store integration. Constraint: project.yml and existing app targets must remain untouched during this phase Rejected: Wire directly into PhoneDashboardStore now | would mix app-target migration with the testable SwiftPM boundary Rejected: Auto-create CompletedRunRecord during ingest | violates v2's resource-first growth boundary Confidence: high Scope-risk: narrow Directive: Do not spend RunResource or create growth records in ingest; keep that in a later explicit reward allocation step Tested: swift test --filter RunimalPhoneAdapterV2Tests Tested: swift test Tested: git diff --check Tested: git diff --name-only -- project.yml RunimalPhone RunimalWatch RunimalMac SharedUI Sources/RunimalCore Tests/RunimalCoreTests Not-tested: iPhone app target runtime wiring is intentionally not connected yet
The v2 reward boundary now includes a Codable RunResourceLedger that deduplicates archive resources, records spend intents, and prevents duplicate sync from resurrecting already-spent resources. The phone adapter gains a pure application use case that applies an ingest plan to archive candidates and the resource ledger without importing RunimalPhone. Constraint: keep app targets and project.yml untouched until the app wiring step has its own XcodeGen/xcodebuild validation Rejected: Persist resources directly in RunimalPhone now | would couple storage migration to the pure SwiftPM boundary Rejected: Treat duplicate sync as a new resource | would let repeated watch transfers create duplicate growth opportunities Confidence: high Scope-risk: narrow Directive: Ingest may upsert resources, but spending must remain behind explicit SpendIntent validation Tested: swift test --filter RunimalResourceLedgerV2Tests Tested: swift test --filter RunimalPhoneIngestApplicationV2Tests Tested: swift test Tested: git diff --check Tested: git diff --name-only -- project.yml RunimalPhone RunimalWatch RunimalMac SharedUI Sources/RunimalCore Tests/RunimalCoreTests Not-tested: RunimalPhone runtime persistence wiring is intentionally not connected yet
The v2 resource ledger now has a versioned JSON snapshot codec and a reserved phone-side sidecar filename. The phone ingest application can produce a persistence draft that carries the updated workout archive list plus the ledger snapshot, letting the app wiring step stay small and ordered. Constraint: RunimalPhone and project.yml remain untouched until the app integration pass can run XcodeGen and xcodebuild together Rejected: Write files directly from SwiftPM adapter | would couple the pure boundary to app filesystem policy too early Rejected: Store resources inside completed-runs.json now | would conflate workout receipt with growth record migration Confidence: high Scope-risk: narrow Directive: Persist archive changes before ledger sidecar writes, and keep CompletedRunRecord creation outside ingest Tested: swift test --filter RunimalResourceLedgerPersistenceV2Tests Tested: swift test --filter RunimalPhoneIngestPersistenceDraftV2Tests Tested: swift test Tested: git diff --check Tested: git diff --name-only -- project.yml RunimalPhone RunimalWatch RunimalMac SharedUI Sources/RunimalCore Tests/RunimalCoreTests Not-tested: app-target file IO wrapper is intentionally documented but not wired yet
The phone app now applies the v2 ingest boundary when receiving a canonical workout archive, while preserving the existing WorkoutSessionArchive identity and payload for the current v1 store. A separate run-resource-ledger-v2.json sidecar keeps post-run resources unspent until a later explicit growth action. Constraint: project.yml remains the XcodeGen source of truth for app target package dependencies Constraint: CompletedRunRecord creation and resource spending must remain outside archive receipt Rejected: Convert core archives through the v2 archive round trip in the app path | legacy non-UUID run IDs could be rewritten before existing UI and persistence read them Confidence: high Scope-risk: moderate Directive: Do not spend RunResource during sync receipt; wire spending only through an explicit post-run growth use case Tested: swift test --filter RunimalPhoneCoreArchiveIngestPlanV2Tests Tested: swift test Tested: xcodegen generate Tested: xcodebuild -project RunimalApple.xcodeproj -scheme RunimalPhone -destination 'generic/platform=iOS' -derivedDataPath /tmp/runimal-phone-v2-ledger-build CODE_SIGNING_ALLOWED=NO build Tested: git diff --check Not-tested: Simulator or physical-device runtime sidecar file creation
Run deletion and imported-run clearing now map removed core archive IDs through the same v2 stable archive-ID helper used by ingest, then prune only unspent ledger resources tied to those source archives. Constraint: Spent resources are preserved to avoid erasing future spend and audit evidence. Rejected: Clear all resources for a deleted archive | would erase spent resource history before v2 reward audit is designed. Confidence: high Scope-risk: narrow Directive: Keep ingest and delete paths using the same resourceArchiveID(forExistingCoreArchiveID:) mapping for non-UUID legacy archive IDs. Tested: swift test --filter RunimalResourceLedgerV2Tests Tested: swift test --filter RunimalPhoneCoreArchiveIngestPlanV2Tests Tested: swift test Tested: xcodebuild -project RunimalApple.xcodeproj -scheme RunimalPhone -destination 'generic/platform=iOS' -derivedDataPath /tmp/runimal-phone-v2-ledger-build CODE_SIGNING_ALLOWED=NO build Tested: git diff --check
The first phone-side spend wiring keeps workout receipt separate from growth allocation, then marks a v2 resource spent only after an existing user action succeeds: companion feed, egg forge, or egg incubation. Legacy records without sidecars remain usable while already-spent v2 resources block double consumption. Constraint: Existing v1 records may not have a v2 ledger sidecar, so missing sidecars must not block legacy growth actions. Rejected: Spend resources during workout receipt | violates the v2 separation between recording trust and growth intent. Confidence: high Scope-risk: moderate Directive: Keep receipt and spend paths separate; do not mark a RunResource spent until a user-facing growth action succeeds. Tested: swift test --filter RunimalPhoneSpendApplicationV2Tests Tested: swift test Tested: xcodebuild -project RunimalApple.xcodeproj -scheme RunimalPhone -destination 'generic/platform=iOS' -derivedDataPath /tmp/runimal-phone-v2-spend-build CODE_SIGNING_ALLOWED=NO build Tested: git diff --check
The phone-side resource ledger now has an app-target runtime check that launches under an explicit environment flag, runs isolated receipt/spend/prune scenarios, and writes a JSON report from inside the simulator app sandbox. The same pass records the first post-run resource allocation UI brief so visual work starts from the verified manual-spend model instead of guessing. Constraint: The check must not mutate normal app data, so it uses isolated Application Support directories under RunimalPhoneRuntimeChecks. Rejected: Treat pure SwiftPM tests as enough runtime evidence | they do not prove app-target persistence paths or simulator launch wiring. Rejected: Add OpenGame or imagegen outputs to app targets | design tools remain external until accepted assets are translated deliberately. Confidence: high Scope-risk: moderate Directive: Keep RUNIMAL_RUNTIME_CHECK entry points isolated and environment-gated; never show them in normal launches. Tested: xcodegen generate Tested: swift test --filter RunimalPhoneSpendApplicationV2Tests Tested: swift test Tested: xcodebuild -project RunimalApple.xcodeproj -scheme RunimalPhone -destination 'platform=iOS Simulator,name=iPhone 17 Pro' -derivedDataPath /tmp/runimal-phone-v2-runtime-check-build CODE_SIGNING_ALLOWED=NO build Tested: SIMCTL_CHILD_RUNIMAL_RUNTIME_CHECK=resource-ledger-v2 xcrun simctl launch --terminate-running-process booted com.jaw.runimal.phone; report failures=[] and all ledger checks true Tested: xcodebuild -project RunimalApple.xcodeproj -scheme RunimalPhone -destination 'generic/platform=iOS' -derivedDataPath /tmp/runimal-phone-v2-runtime-device-build CODE_SIGNING_ALLOWED=NO build Tested: git diff --check Not-tested: Real Apple Watch to iPhone hardware sync sidecar creation/spend/prune path.
The v2 rebuild now has an explicit design-quality track that turns image generation into reviewed candidate references instead of production assets. The docs define the Watch-first metric hierarchy, phone route-detail priorities, growth-resource UX constraints, and batch-ready prompts for the first Runimal v2 UI concepts. Constraint: Existing app targets, project.yml, and Package.swift must remain untouched for this design-only pass Rejected: Generate ad hoc production assets immediately | current session exposes no live image tool namespace and OPENAI_API_KEY is missing Confidence: high Scope-risk: narrow Directive: Treat output/imagegen artifacts as candidate references until reviewed for readability, accessibility, copyright safety, and SwiftUI feasibility Tested: Parsed output/imagegen/runimal-v2-ui-briefs.jsonl with Python json; git diff --check Not-tested: Live image generation API call
Codex CLI was updated to 0.123.0 so image_generation is now stable and exposed in a fresh tmux session. The first Runimal v2 imagegen brief generated a Watch running HUD candidate and copied the native output into the repo's candidate artifact directory. Constraint: Existing app code, project.yml, and Package.swift remain untouched Rejected: Use the imagegen skill CLI | user asked to fix Codex native image generation and OPENAI_API_KEY is not needed for the native tool Confidence: high Scope-risk: narrow Directive: Keep this PNG as a candidate reference only; do not wire it into app targets without design/accessibility review Tested: codex-cli 0.123.0 reports image_generation stable true; native image tool generated PNG; file reports PNG image data 1254 x 1254 Not-tested: SwiftUI implementation of the visual direction
The image-generation track now has candidate references for every prepared Runimal v2 brief: phone route detail, resource allocation, companion growth, and app icon, alongside the existing Watch HUD candidate. The output README records first-read design judgments and keeps the artifacts explicitly non-production until accessibility and SwiftUI feasibility review. Constraint: Existing app code, project.yml, and Package.swift remain untouched Rejected: Wire generated PNGs into asset catalogs now | candidates need design/accessibility review and vector/SwiftUI translation first Confidence: high Scope-risk: narrow Directive: Use these images only as references; extract hierarchy, palette, spacing, and silhouettes before implementation Tested: Parsed runimal-v2-ui-briefs.jsonl; verified all five expected PNG files exist; file identified each PNG; git diff --check Not-tested: In-app rendering or small-size icon review
The user preferred a Tamagotchi-adjacent direction, so this adds a separate candidate batch that translates that taste into Runimal's existing PixelPetView, GameSurface, GameBoyPalette, and RunimalVisualTile language without wiring generated bitmaps into the app. Constraint: Existing app targets, project.yml, Package.swift, and asset catalogs remain untouched Rejected: Copy Tamagotchi branding, device shapes, or characters | IP risk and inconsistent with Runimal's existing original pixel-pet system Confidence: high Scope-risk: narrow Directive: Treat generated PNGs as design references only; redraw accepted ideas as SwiftUI/vector/pixel assets before production use Tested: jsonl parsed with python3; file verified each pixel PNG; git diff --check Not-tested: Watch-size SwiftUI implementation and accessibility contrast in production views
The prior pixel batch captured the handheld virtual-pet UI mood but used generic companion silhouettes. This adds a species-locked candidate batch based on the documented five base species, fixed colors, and five rare-variant overlay rules, plus design-direction guardrails so future UI work does not regress. Constraint: Existing app targets, project.yml, Package.swift, and asset catalogs remain untouched Rejected: Generic green pixel pet direction | fails the documented Windrunner/Stoneback/Sparkfang/Mosshop/Seedle identity rules Rejected: Treat rare variants as replacement species | docs require variant overlays on top of base species silhouette and color Confidence: high Scope-risk: narrow Directive: Production companion UI must preserve species silhouette, base color, and variant-as-overlay separation before LCD chrome polish Tested: Read Runimal world/species docs and external research note; jsonl parsed with python3; file verified generated PNGs; git diff --check Not-tested: SwiftUI implementation, watch-size accessibility, and exact text fidelity inside generated mockups
The character art direction now needs the full five-stage growth flow, not only variant overlays. This adds a 5 base species x 5 growth stages matrix plus one per-species evolution sheet based on the documented level/growth blueprints. Constraint: Existing app targets, project.yml, Package.swift, and asset catalogs remain untouched Rejected: Mix rare variants into base growth sheets | this batch must validate clean species growth before variant overlays Confidence: high Scope-risk: narrow Directive: Use these images as references only; production silhouettes should be encoded in SpeciesVisualRenderProfile and growthStageBlueprints Tested: file verified all evolution PNGs; jsonl parsed with python3; git diff --check Not-tested: SwiftUI pixel implementation and exact generated in-image text fidelity
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Commit Guide
Validation
Notes