Plan phase 1
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
---
|
||||
phase: 01-project-infrastructure-module-wiring
|
||||
plan: 07
|
||||
type: execute
|
||||
wave: 3
|
||||
depends_on: [01, 02, 03, 04, 05, 06]
|
||||
files_modified:
|
||||
- shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep
|
||||
autonomous: true
|
||||
requirements: [INFRA-01, INFRA-02, INFRA-03, INFRA-06]
|
||||
requirements_addressed: [INFRA-01, INFRA-02, INFRA-03, INFRA-06]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/ package scaffold exists (as .gitkeep marker) — INFRA-06 file-existence criterion"
|
||||
- "./gradlew spotlessApply runs green (no files need formatting, OR all files are auto-formatted)"
|
||||
- "./gradlew build succeeds across composeApp, server, shared — produces Android APK + iOS framework + server JAR (SC1)"
|
||||
- "tools/verify-no-version-literals.sh exits 0 across the whole repo (SC2 / INFRA-01)"
|
||||
- "tools/verify-ios-flags.sh exits 0 (SC3 / INFRA-03)"
|
||||
- "tools/verify-shared-pure.sh exits 0 (SC5 / INFRA-06)"
|
||||
- "./gradlew :composeApp:help emits 'recipe.kotlin.multiplatform' among applied plugins (SC4 / INFRA-02)"
|
||||
- "./gradlew check runs spotlessCheck + all tests and exits 0"
|
||||
artifacts:
|
||||
- path: "shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep"
|
||||
provides: "Empty package scaffold marker ensuring dev.ulfrx.recipe.shared package exists in git (Phase 2+ adds DTOs here)"
|
||||
- path: "composeApp/build/outputs/apk/debug/composeApp-debug.apk"
|
||||
provides: "Android debug APK artifact from ./gradlew build (SC1 proof)"
|
||||
- path: "composeApp/build/bin/iosSimulatorArm64/debugFramework/ComposeApp.framework"
|
||||
provides: "iOS framework artifact from ./gradlew build (SC1 proof)"
|
||||
key_links:
|
||||
- from: "./gradlew build"
|
||||
to: "composeApp/build.gradle.kts + shared/build.gradle.kts + server/build.gradle.kts"
|
||||
via: "recipe.* convention plugin application (Plan 03 refactor)"
|
||||
pattern: "id\\(\"recipe\\."
|
||||
- from: "./gradlew :composeApp:help"
|
||||
to: "build-logic/src/main/kotlin/recipe.kotlin.multiplatform.gradle.kts"
|
||||
via: "help task enumerates applied plugins"
|
||||
pattern: "recipe\\.kotlin\\.multiplatform"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Create the final piece of INFRA-06 (empty `dev.ulfrx.recipe.shared` package scaffold under `shared/src/commonMain`) and then run the full phase verification gate: `./gradlew spotlessApply`, `./gradlew build`, the 3 `tools/verify-*.sh` invariant scripts, and `./gradlew check`. This is the "green build" moment that every prior plan in Phase 1 has been building toward.
|
||||
|
||||
Purpose: Phase 1 success is defined by 5 ROADMAP success criteria (SC1-SC5) and 4 phase requirements (INFRA-01/02/03/06). Plans 01-06 delivered the files and refactors; this plan PROVES they integrate cleanly. Any regression here is a phase-completion blocker.
|
||||
|
||||
Output: 1 `.gitkeep` placeholder + verification artifacts (APK + iOS framework) + proof of all 5 SCs + green `./gradlew check`.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@$HOME/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@.planning/phases/01-project-infrastructure-module-wiring/01-CONTEXT.md
|
||||
@.planning/phases/01-project-infrastructure-module-wiring/01-RESEARCH.md
|
||||
@.planning/phases/01-project-infrastructure-module-wiring/01-PATTERNS.md
|
||||
@.planning/phases/01-project-infrastructure-module-wiring/01-VALIDATION.md
|
||||
@tools/verify-no-version-literals.sh
|
||||
@tools/verify-shared-pure.sh
|
||||
@tools/verify-ios-flags.sh
|
||||
@CLAUDE.md
|
||||
|
||||
<interfaces>
|
||||
<!-- Inputs from prior plans -->
|
||||
|
||||
From Plan 01:
|
||||
- tools/verify-no-version-literals.sh — greps every *.gradle.kts for version literals (exits 0 if none except build-logic/build.gradle.kts)
|
||||
- tools/verify-shared-pure.sh — greps shared/src/commonMain/ for forbidden imports (exits 0 if none OR if directory absent)
|
||||
- tools/verify-ios-flags.sh — greps gradle.properties for the two iOS K/N flags (exits 0 if both present)
|
||||
|
||||
From Plan 02:
|
||||
- build-logic/ with 5 precompiled plugins applied via settings.gradle.kts pluginManagement.includeBuild
|
||||
|
||||
From Plan 03:
|
||||
- composeApp/, shared/, server/ build.gradle.kts applying recipe.* convention plugins
|
||||
|
||||
From Plan 04:
|
||||
- composeApp common/iOS/Android/Desktop/Wasm entry points calling initKoin() + configureLogging()
|
||||
- iosApp/iosApp/iOSApp.swift calling KoinIosKt.doInitKoin()
|
||||
|
||||
From Plan 05:
|
||||
- server Application.kt with /health + Database.migrate + ContentNegotiation + extracted configureRouting()
|
||||
- server ApplicationTest.kt passing without Postgres
|
||||
|
||||
From Plan 06:
|
||||
- docker-compose.yml with postgres:16 + matching credentials
|
||||
- README.md with Local development section
|
||||
|
||||
Phase gate commands (from 01-VALIDATION.md § Sampling Rate):
|
||||
- Quick: `./gradlew spotlessCheck :server:test :shared:jvmTest` (<30s)
|
||||
- Per-wave: `./gradlew build` (full — iOS framework link + Android APK + server JAR)
|
||||
- Phase gate: `./gradlew check` + manual curl + iOS simulator boot (simulator boot is a manual-only verification, 01-VALIDATION.md § Manual-Only)
|
||||
</interfaces>
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create shared/ package scaffold placeholder</name>
|
||||
<files>shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep</files>
|
||||
<read_first>
|
||||
- shared/src/commonMain/kotlin/dev/ulfrx/recipe/ (current contents: Greeting.kt, Platform.kt, Constants.kt — these are the TEMPLATE classes; they stay in place for now. Phase 2+ reorganizes.)
|
||||
- .planning/phases/01-project-infrastructure-module-wiring/01-CONTEXT.md D-19 (shared/commonMain stays pure; Phase 1 ships an empty package scaffold under dev.ulfrx.recipe.shared)
|
||||
- .planning/phases/01-project-infrastructure-module-wiring/01-PATTERNS.md lines 73-77 (shared package scaffold as .gitkeep marker)
|
||||
- .planning/phases/01-project-infrastructure-module-wiring/01-RESEARCH.md line 289 (shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/ NEW empty pkg)
|
||||
</read_first>
|
||||
<action>
|
||||
Create an empty `.gitkeep` file at `shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep`. The parent directories do not exist yet — create them as part of the write.
|
||||
|
||||
The file content is zero bytes (empty). Its purpose is purely to make `dev.ulfrx.recipe.shared` package discoverable in git and in the IDE, ready for Phase 2+ DTO additions.
|
||||
|
||||
DO NOT:
|
||||
- Touch or delete `shared/src/commonMain/kotlin/dev/ulfrx/recipe/Greeting.kt` — template class, stays
|
||||
- Touch `Platform.kt` or `Constants.kt` — template classes, stay
|
||||
- Add any other file under the new `shared/` package
|
||||
- Add `expect`/`actual` declarations anywhere in shared/ (Phase 2+ scope)
|
||||
|
||||
Note the namespace layering: `shared/src/commonMain/kotlin/dev/ulfrx/recipe/` is the ROOT package (`dev.ulfrx.recipe` — where Constants.kt lives), and `shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/` is a SUB-package (`dev.ulfrx.recipe.shared` — where Phase 2+ DTOs will live). Both are valid; Phase 1 keeps the root-package template files and adds the sub-package placeholder.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>test -f shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep && test -d shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared && test -f shared/src/commonMain/kotlin/dev/ulfrx/recipe/Greeting.kt && test -f shared/src/commonMain/kotlin/dev/ulfrx/recipe/Constants.kt && bash tools/verify-shared-pure.sh</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep` exists (file test: `test -f`)
|
||||
- Parent directory `shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared` exists (directory test: `test -d`)
|
||||
- Existing template files are preserved: `shared/src/commonMain/kotlin/dev/ulfrx/recipe/Greeting.kt`, `Platform.kt`, `Constants.kt` all still exist
|
||||
- `tools/verify-shared-pure.sh` exits 0 — the `.gitkeep` file is not a `.kt` file so the grep skips it; the existing Greeting/Platform/Constants files still contain no forbidden imports
|
||||
</acceptance_criteria>
|
||||
<done>Empty package scaffold created; shared/ is ready for Phase 2+ DTOs.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Run Spotless apply + full ./gradlew build + invariant scripts</name>
|
||||
<files></files>
|
||||
<read_first>
|
||||
- .planning/phases/01-project-infrastructure-module-wiring/01-VALIDATION.md lines 40-58 (Per-Task Verification Map — the exact commands this task runs)
|
||||
- .planning/phases/01-project-infrastructure-module-wiring/01-VALIDATION.md lines 27-34 (Sampling Rate — per-wave and phase-gate commands)
|
||||
- .planning/phases/01-project-infrastructure-module-wiring/01-RESEARCH.md lines 1216-1241 (Success Criteria → Test Map)
|
||||
</read_first>
|
||||
<action>
|
||||
This task is purely verification — no file modifications. Run the full phase gate in sequence. If any step fails, STOP and report the failure (do NOT silently swallow errors — a failure here means a prior plan regressed and must be fixed before Phase 1 completes).
|
||||
|
||||
Execute these commands IN ORDER. Each must exit 0 before proceeding to the next.
|
||||
|
||||
1. **Spotless apply** — auto-formats Kotlin + Gradle + Markdown files across all modules using `recipe.quality`'s ktlint rules:
|
||||
|
||||
```bash
|
||||
./gradlew spotlessApply
|
||||
```
|
||||
|
||||
Expected: exit 0. If formatting changes any file, the change is benign (whitespace/indentation normalization); the subsequent `build` still passes.
|
||||
|
||||
2. **Invariant script: no version literals** — enforces INFRA-01 SC#2:
|
||||
|
||||
```bash
|
||||
bash tools/verify-no-version-literals.sh
|
||||
```
|
||||
|
||||
Expected: exit 0 + `OK: no version literals outside catalog.`
|
||||
|
||||
3. **Invariant script: shared/ is pure** — enforces INFRA-06 SC#5:
|
||||
|
||||
```bash
|
||||
bash tools/verify-shared-pure.sh
|
||||
```
|
||||
|
||||
Expected: exit 0 + `OK: shared/commonMain is pure.`
|
||||
|
||||
4. **Invariant script: iOS K/N flags present** — enforces INFRA-03 SC#3:
|
||||
|
||||
```bash
|
||||
bash tools/verify-ios-flags.sh
|
||||
```
|
||||
|
||||
Expected: exit 0 + `OK: iOS binary flags present.`
|
||||
|
||||
5. **Full Gradle build** — enforces SC1: produces Android APK + iOS framework + server JAR:
|
||||
|
||||
```bash
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
Expected: exit 0. This compiles every target (androidTarget, iosArm64, iosSimulatorArm64, jvm, wasmJs), links the iOS framework, packages the Android APK, and builds the server fat JAR.
|
||||
|
||||
After success, verify the two proof artifacts exist:
|
||||
|
||||
```bash
|
||||
test -f composeApp/build/outputs/apk/debug/composeApp-debug.apk
|
||||
test -d composeApp/build/bin/iosSimulatorArm64/debugFramework/ComposeApp.framework
|
||||
```
|
||||
|
||||
6. **Convention plugin applied** — enforces SC4 / INFRA-02:
|
||||
|
||||
```bash
|
||||
./gradlew :composeApp:help -q 2>&1 | grep -q 'recipe.kotlin.multiplatform' || ./gradlew :composeApp:tasks --all -q 2>&1 | grep -q 'recipe' || true
|
||||
```
|
||||
|
||||
Ktlint/help output verification: the `help` task for a module does not always enumerate plugins in recent Gradle versions. An alternative proof: the `./gradlew build` success in step 5 IS the proof that `recipe.kotlin.multiplatform` was applied — if the plugin hadn't applied, compilation would have failed at configuration time. Record the `./gradlew build` success as SC4 satisfaction if `help` output is ambiguous.
|
||||
|
||||
7. **Full check** — enforces full-suite green (spotlessCheck + all tests):
|
||||
|
||||
```bash
|
||||
./gradlew check
|
||||
```
|
||||
|
||||
Expected: exit 0. This includes:
|
||||
- `spotlessCheck` (Spotless verification)
|
||||
- `:server:test` (runs the /health test from Plan 05 — no Postgres needed)
|
||||
- `:composeApp:jvmTest` (template test, if present)
|
||||
- `:shared:jvmTest` (template test, if present)
|
||||
- Other platform tests as declared
|
||||
|
||||
If any of steps 1-7 fails, report exactly which step failed, the full error output, and STOP. The failure indicates a regression in one of Plans 01-06 that needs a `/gsd-plan-phase --gaps` cycle.
|
||||
|
||||
IMPORTANT:
|
||||
- Do NOT add a `docker compose up postgres` step here. The `/health` test in Plan 05 composes `configureRouting()` directly WITHOUT `Database.migrate()` — no Postgres required. The only manual-only verification in Phase 1 is iOS simulator boot (01-VALIDATION.md § Manual-Only) which is deferred to a later human review.
|
||||
- Do NOT run `./gradlew :server:run` here — it would call `Database.migrate()` which requires a running Postgres. That's a manual smoke check (documented in README Local development) not a CI/phase-gate check.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /Users/rwilk/dev/repo/recipe && ./gradlew spotlessApply -q && bash tools/verify-no-version-literals.sh && bash tools/verify-shared-pure.sh && bash tools/verify-ios-flags.sh && ./gradlew build -q && test -f composeApp/build/outputs/apk/debug/composeApp-debug.apk && test -d composeApp/build/bin/iosSimulatorArm64/debugFramework/ComposeApp.framework && ./gradlew check -q</automated>
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `./gradlew spotlessApply` exits 0
|
||||
- `tools/verify-no-version-literals.sh` exits 0 (SC2)
|
||||
- `tools/verify-shared-pure.sh` exits 0 (SC5)
|
||||
- `tools/verify-ios-flags.sh` exits 0 (SC3)
|
||||
- `./gradlew build` exits 0 (SC1)
|
||||
- `composeApp/build/outputs/apk/debug/composeApp-debug.apk` exists (SC1 Android artifact)
|
||||
- `composeApp/build/bin/iosSimulatorArm64/debugFramework/ComposeApp.framework` directory exists (SC1 iOS artifact)
|
||||
- `./gradlew check` exits 0 (full-suite verification — includes spotlessCheck + all tests including /health)
|
||||
- The `./gradlew build` success implicitly proves SC4 (convention plugins applied) — if `recipe.kotlin.multiplatform` hadn't applied, the build would have failed during module configuration
|
||||
- No `BUILD FAILED` string appears in the transcript
|
||||
</acceptance_criteria>
|
||||
<done>Phase 1 green — all 5 SCs and all 4 phase requirements (INFRA-01/02/03/06) verified by automated commands.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| Developer host → Gradle daemon | Same process; Gradle executes precompiled plugin code from `build-logic/` with full project access by design. |
|
||||
| Gradle build → Maven Central + Gradle Plugin Portal + Google | First `./gradlew build` downloads new artifacts (Koin, Kermit, Spotless, Flyway, Postgres JDBC, ktor content-negotiation, kotlinx-serialization). All versions pinned via catalog (Plan 01). |
|
||||
| iOS framework link → K/N compiler | Uses the two binary flags from gradle.properties (`gc=cms`, `objcDisposeOnMain=false`). Verified by `tools/verify-ios-flags.sh` (infrastructure check) + deferred iOS simulator boot check (manual). |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-01-07-01 | Denial of Service | `./gradlew build` downloading fresh deps, causing slow first-build | accept | First build may take 2-5 minutes as Koin/Kermit/Flyway/Postgres JDBC artifacts download (~80 MB per 01-RESEARCH.md § Runtime State Inventory). Subsequent builds use Gradle cache. Not a threat — just an expectation. |
|
||||
| T-01-07-02 | Tampering (supply chain) | Malicious transitive dep snuck in via new library | mitigate | Every new dep is pinned via catalog (Plan 01). Gradle verification metadata (`gradle/verification-metadata.xml`) is NOT enabled in Phase 1 — it's a future enhancement (Phase 11 CI setup). Risk accepted for Phase 1 single-dev local-build scope. |
|
||||
| T-01-07-03 | Destruction | Stale `build/` cache from template's `js` target outputs | mitigate | 01-RESEARCH.md § Runtime State Inventory notes developers should `./gradlew clean` once after Phase 1 to flush stale js target outputs. Task 2's `./gradlew build` will still succeed (Gradle ignores orphaned outputs), but developers may see bloated `build/` until a clean. README Local development section's `./gradlew check` implicitly clears enough; full `clean` is a nice-to-have. |
|
||||
| T-01-07-04 | Information Disclosure | `./gradlew build` log leaking env variables to console | accept | Server-side env vars (`DATABASE_URL` etc.) are only read at server boot, not during `./gradlew build`. The `/health` test composes routing without the DB. No secrets logged during build. |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
Phase-level verification for this plan — this IS the phase gate. Success here equals Phase 1 completion.
|
||||
|
||||
Hard gate commands (all must exit 0):
|
||||
1. `./gradlew spotlessApply` — auto-format
|
||||
2. `tools/verify-no-version-literals.sh` — SC2 / INFRA-01
|
||||
3. `tools/verify-shared-pure.sh` — SC5 / INFRA-06
|
||||
4. `tools/verify-ios-flags.sh` — SC3 / INFRA-03
|
||||
5. `./gradlew build` — SC1, implicitly SC4 / INFRA-02
|
||||
6. `./gradlew check` — full-suite (spotlessCheck + all tests)
|
||||
|
||||
Manual-only verifications (deferred per 01-VALIDATION.md § Manual-Only — NOT in Task 2 `<automated>`):
|
||||
- iOS simulator debug launch without legacy memory-manager warnings (requires Xcode + simulator)
|
||||
- Hot-reload dev loop on Desktop (interactive)
|
||||
- Server `/health` reachable via curl when Postgres is up (requires `docker compose up -d postgres` + `./gradlew :server:run`)
|
||||
|
||||
These manual checks are recommended for the developer to run once; they are NOT gate-blocking for automated Phase 1 completion.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- `shared/src/commonMain/kotlin/dev/ulfrx/recipe/shared/.gitkeep` created
|
||||
- `./gradlew spotlessApply` green
|
||||
- All 3 `tools/verify-*.sh` scripts green
|
||||
- `./gradlew build` green + Android APK + iOS framework artifacts exist
|
||||
- `./gradlew check` green
|
||||
- No manual step required to pass this plan
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-project-infrastructure-module-wiring/01-07-SUMMARY.md` recording: the final 7 verification command outputs (exit codes), the size of the produced APK and iOS framework, the total `./gradlew build` time, and explicit confirmation that all 5 ROADMAP SCs (SC1-SC5) and 4 phase requirements (INFRA-01/02/03/06) are satisfied.
|
||||
|
||||
Include in the summary a brief "Manual smoke checks to run later" list pointing at 01-VALIDATION.md § Manual-Only:
|
||||
- iOS simulator boot without legacy-MM warnings
|
||||
- Desktop hot-reload regression check
|
||||
- docker compose up postgres + server /health curl smoke test
|
||||
</output>
|
||||
Reference in New Issue
Block a user