Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ buildscript {
```

Your kotlin android library (role-specific — prefer `androidUtil` / `uiLibrary` /
`impl` over deprecated `androidLibrary`)
`impl`; generic `androidLibrary` was removed in F-063)

``` gradle
// Single method, type-safe creation of your target
Expand Down Expand Up @@ -147,7 +147,6 @@ project-dep type checks + content layout rules from live validators
|:----------------------:|:-----------:|:-------:|:----------:|
| `androidBinary` | ✅ | Generate single APK | name + no `res/`; composition-root project-dep list |
| `androidApp` | ✅ | Application / root Android library | name + no `res/`; composition-root project-dep list |
| `androidLibrary` | ⚠️ deprecated | Generic Android lib escape hatch — **do not use** | see [`docs/ANDROID-LIBRARY-DEPRECATION.md`](docs/ANDROID-LIBRARY-DEPRECATION.md) |
| `uiLibrary` | ✅ | Shared UI library for impl/widget | project-dep list |
| `widget` | ✅ | Custom View / UI component | project-dep list |
| `composeWidget` | ✅ | Compose UI component | always Compose + project-dep list |
Expand All @@ -157,7 +156,7 @@ project-dep type checks + content layout rules from live validators
| `androidUtil` | ✅ | Android library extensions | no `res/` + project-dep list |
| `testUtil` | ✅ | Shared code for unit tests | no `res/` + project-dep list |
| `util` | ✅ | JVM library extensions | no `res/` + project-dep list |
| `library` | ✅ | JVM library | project-dep list (shares `library` suffix with `androidLibrary`) |
| `library` | ✅ | JVM library | project-dep list (only owner of `library` suffix after F-063) |
| `api` | ✅ | Feature external APIs | no `res/` + project-dep list |
| `impl` | ✅ | Feature implementation | project-dep list (**no** other `impl`) |
| `androidNative` | ✅ | NDK / native | no `res/`; no project-dep validation yet |
Expand All @@ -174,7 +173,6 @@ That document is generated from each target’s
| `api` | `api`, `library` |
| `impl` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget`, `compose-widget` |
| `library` (JVM) | `util`, `test-util` |
| `androidLibrary` (deprecated) | `library`, `util`, `android-util`, `test-util`, `res`, `api` |
| `uiLibrary` | `widget`, `compose-widget`, `util`, `android-util`, `res` |
| `util` | `util`, `library` |
| `androidUtil` | `android-util`, `test-util`, `res`, `library` |
Expand Down
2 changes: 1 addition & 1 deletion TICKETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ encourages dumping mixed concerns into one bucket. Prefer specific targets.
| F-060 | done | Deprecate `androidLibrary` + document flat-structure policy | `@Deprecated` on DSL; VISION + `docs/ANDROID-LIBRARY-DEPRECATION.md`; matrix/README |
| F-061 | done | Migrate `application/` sample off `androidLibrary` | di→`androidUtil`, mvvm→`uiLibrary`, navigation→`androidRes`; path renames |
| F-062 | done | Reimplement progressive examples / skills without `androidLibrary` | `examples/android/04` + agent skills + README curriculum |
| F-063 | todo | Hard-remove `androidLibrary` target (after consumers migrated) | Drop registry type / docs row once no in-repo callers |
| F-063 | done | Hard-remove `androidLibrary` target (after consumers migrated) | DSL + `android.library` type/registry/restrictions removed; JVM `library` + AGP feature helper kept; matrix/docs updated |

## Backlog (lower priority / historical GitHub)

Expand Down
57 changes: 26 additions & 31 deletions docs/ANDROID-LIBRARY-DEPRECATION.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
# Deprecating `androidLibrary` (F-060+)
# `androidLibrary` removed (F-063)

## Why
`androidLibrary` (the generic AGP library DSL target with type id `android.library`
and `library` suffix) has been **hard-removed** in F-063.

`androidLibrary` is a **generic AGP library** target. It was a temporary way to
host “shared Android code that isn’t a feature `impl`.” That works against
Forma’s goal: **keep structure flat and role-typed**.
It was a temporary escape hatch that worked against Forma’s core principle:
**keep the dependency graph flat and role-typed**.

Problems:
## Why it existed and why it is gone

1. **Suffix collision** with JVM `library` (`library` name suffix / historical
`LibraryTargetTemplate`) — validators resolve deps by suffix and cannot tell
JVM vs Android library modules apart reliably.
2. **Mixed concerns** — sample historically stuffed DI scopes, MVVM/UI bases, and
navigation XML into the same target kind.
3. **Weak teaching signal** — newcomers reach for `androidLibrary` instead of the
target that matches the module’s job.
- Shared the `library` suffix with JVM `library()` (validator collision).
- Encouraged dumping unrelated concerns into one bucket.
- Weak teaching signal — people reached for the generic target instead of the
role that matched the module.

## Replacement map
## Replacements (use these)

| If the module is… | Use instead | Suffix |
|-------------------|-------------|--------|
| If the module is… | Use | Suffix |
|-------------------|-----|--------|
| Pure JVM shared code | `library` | `library` |
| Small Android helpers, **no** `res/` | `androidUtil` | `android-util` |
| Shared UI bases for `impl` / `widget` | `uiLibrary` | `ui-library` |
Expand All @@ -30,30 +27,28 @@ Problems:
| Feature implementation | `impl` | `impl` |
| Feature contracts | `api` | `api` |

## Sample migration (F-061)
## Historical migrations (F-061 / F-062)

| Old path | Old DSL | New path | New DSL |
|----------|---------|----------|---------|
| `core/di/library` | `androidLibrary` | `core/di/android-util` | `androidUtil` |
| `core/mvvm/library` | `androidLibrary` | `core/mvvm/ui-library` | `uiLibrary` |
| `core/navigation/library` | `androidLibrary` | `core/navigation/res` | `androidRes` |

Kotlin **packages** may keep historical `.library` segments to limit churn;
**project path / suffix** is what Forma validates.

## Matrix tweaks paired with migration

- `viewBinding` may depend on `ui-library` (shared UI bases without generic library).
- `androidUtil` may depend on JVM `library` (Android helpers wrapping pure JVM code).
Kotlin packages may retain historical `.library` segments; the **project name suffix**
is what the validators enforce.

## Lifecycle

| Ticket | Intent |
| Ticket | Status |
|--------|--------|
| **F-060** | `@Deprecated` on DSL + docs/vision |
| **F-061** | `application/` sample migrated |
| **F-062** | Progressive examples + agent skills teach replacements |
| **F-063** | Hard-remove target type / registry entry when nothing in-repo calls it |
| F-060 | Deprecated DSL + docs |
| F-061 | Migrated `application/` sample |
| F-062 | Migrated examples + agent skills |
| F-063 | Hard-removed DSL entry, type registration, restriction rules, and docs |

**`androidLibrary { }` no longer exists.** Use the role-specific targets above.
The internal `androidLibraryFeatureDefinition` helper (AGP `com.android.library`
wiring) remains for use by `impl`, `uiLibrary`, etc. — it is not a public DSL target.

Until F-063, `androidLibrary { }` still configures modules but should not appear
in new code or tutorials.
See also [`DEPENDENCY-MATRIX.md`](DEPENDENCY-MATRIX.md) (collision note updated).
7 changes: 3 additions & 4 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Defined in `plugins/android/.../AndroidTargets.kt`:
|--------|--------|---------------------|
| `BinaryTargetTemplate` | `binary` | `androidBinary` |
| `ApplicationTargetTemplate` | `app` | `androidApp` |
| `LibraryTargetTemplate` | `library` | `library` (JVM); deprecated `androidLibrary` shares suffix |
| `LibraryTargetTemplate` | `library` | `library` (JVM only after F-063) |
| `UiLibraryTargetTemplate` | `ui-library` | `uiLibrary` |
| `NativeTarget` | `native` | `androidNative` |
| `UtilTargetTemplate` | `util` | `util` |
Expand All @@ -158,7 +158,6 @@ when validators change.
| `api` | `api`, `library` | no `res/` under `src/main` |
| `impl` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget`, `compose-widget` | — |
| `library` (JVM) | `util`, `test-util` | — |
| `androidLibrary` (deprecated) | `library`, `util`, `android-util`, `test-util`, `res`, `api` | — |
| `uiLibrary` | `widget`, `compose-widget`, `util`, `android-util`, `res` | — |
| `util` | `util`, `library` | no `res/` |
| `androidUtil` | `android-util`, `test-util`, `res`, `library` | no `res/` |
Expand All @@ -176,7 +175,7 @@ Notes for later tickets:

- `impl` cannot depend on other `impl` (Dagger-friendly) — enforced; F-011.
- `androidApp` / `androidBinary` use restricted composition-root lists — F-011 done.
- `androidLibrary` **deprecated** (F-060+); JVM `library` keeps the `library` suffix — see [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md).
- `androidLibrary` **removed** (F-063); only JVM `library` uses the `library` suffix — see [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md).

### 2.3 Feature stack (Android module)

Expand Down Expand Up @@ -350,7 +349,7 @@ Suggested extraction order (tickets F-020…F-024):
| Item | Ticket |
|------|--------|
| ~~README dependency matrix ≠ live validators~~ → [`docs/DEPENDENCY-MATRIX.md`](DEPENDENCY-MATRIX.md) | F-010 done |
| ~~`EmptyValidator` on app/binary/androidLibrary~~ (composition-root + library allowlists) | F-011 done |
| ~~`EmptyValidator` on app/binary/(historical androidLibrary)~~ (composition-root + library allowlists) | F-011 done; androidLibrary removed F-063 |
| ~~AGP 7.4.2 compile vs 8.1.2 runtime~~ (aligned 8.1.2) | F-003 done |
| ~~CI missing SDK + Java on some jobs~~ (GHA green on PR #153) | F-004 done |
| ~~Compose flag in settings, limited target support~~ → per-target flags + `composeWidget` | F-013 done |
Expand Down
2 changes: 1 addition & 1 deletion docs/COMPOSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ androidProjectConfiguration(

| Setting | Role |
|---------|------|
| `compose` | Default value for per-target `compose = …` parameters on `impl`, `androidUtil`, `androidApp`, `uiLibrary`, `androidBinary` (deprecated `androidLibrary` still accepts it). |
| `compose` | Default value for per-target `compose = …` parameters on `impl`, `androidUtil`, `androidApp`, `uiLibrary`, `androidBinary`. |
| `composeCompilerVersion` | Written to AGP `composeOptions.kotlinCompilerExtensionVersion` when Compose is enabled. |

`composeWidget` modules **always** enable Compose; they ignore the project default
Expand Down
2 changes: 1 addition & 1 deletion docs/CONFIGURATION-PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ definitions, skip empty repo blocks), not as a claim of a fixed wall-clock %.

## What costs configuration time in Forma

1. **Per-target work** — every `api` / `impl` / `androidLibrary` / … call:
1. **Per-target work** — every `api` / `impl` / `androidUtil` / … call:
- suffix validation for self + each project dependency
- AGP / Kotlin plugin apply + extension configuration
- dependency registration (`applyDependencies`)
Expand Down
24 changes: 9 additions & 15 deletions docs/DEPENDENCY-MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Source of truth for **F-010**. Every rule below is taken from the live
When validators change, update **this file first**, then the README summary
matrix. Do not invent rules from aspirational docs.

Last verified: **2026-07-16** against `v2` + F-060 androidLibrary deprecation migration.
Last verified: **2026-07-17** against `v2` + F-063 hard-remove of `androidLibrary`.

---

Expand Down Expand Up @@ -41,7 +41,6 @@ From `plugins/android/.../AndroidTargets.kt`:
|----------------|-----------------|-------------|
| `androidBinary` | `BinaryTargetTemplate` | `binary` |
| `androidApp` | `ApplicationTargetTemplate` | `app` |
| `androidLibrary` (**deprecated**) | `LibraryTargetTemplate` | `library` |
| `library` (JVM) | `LibraryTargetTemplate` | `library` |
| `uiLibrary` | `UiLibraryTargetTemplate` | `ui-library` |
| `androidNative` | `NativeTarget` | `native` |
Expand All @@ -56,11 +55,12 @@ From `plugins/android/.../AndroidTargets.kt`:
| `widget` | `WidgetTargetTemplate` | `widget` |
| `composeWidget` | `ComposeWidgetTargetTemplate` | `compose-widget` |

**Collision note:** JVM `library` and Android `androidLibrary` share the same
suffix `library` / `LibraryTargetTemplate`. The DSL functions differ (Kotlin
JVM features vs AGP library features), but project-name validation cannot
tell them apart. **Design (F-020):** unique `TargetType.id` with shared
suffix allowed for Gradle names — see [`forma-core-api.md`](forma-core-api.md) §7.
**Collision note:** Only JVM `library` uses the `library` suffix (F-063).
Historical `androidLibrary` (also using `library` suffix via `LibraryTargetTemplate`)
was removed after F-060–F-062 migration to role-specific targets (`androidUtil`,
`uiLibrary`, `androidRes`, `viewBinding`, `impl`). Validators still match by
suffix, so `*-library` JVM modules are accepted where `library` is allowed.
See [`forma-core-api.md`](forma-core-api.md) §7 for the engine design.

README historically said `androidWidget` / `androidUtils` / `testUtils` /
`utils` / `androidTestUtils` — the **code** entrypoints are `widget`,
Expand All @@ -78,7 +78,6 @@ these suffixes (or are unrestricted if `EmptyValidator`).
| `api` | `api.kt` | `validator(api, library)` | `api`, `library` |
| `impl` | `impl.kt` | `validator(api, android-util, test-util, util, library, ui-library, res, viewbinding, widget, compose-widget)` | `api`, `android-util`, `test-util`, `util`, `library`, `ui-library`, `res`, `viewbinding`, `widget`, `compose-widget` |
| `library` (JVM) | `library.kt` | `validator(util, test-util)` | `util`, `test-util` |
| `androidLibrary` (**deprecated**) | `androidLibrary.kt` | `validator(library, util, android-util, test-util, res, api)` | `library`, `util`, `android-util`, `test-util`, `res`, `api` |
| `uiLibrary` | `uiLibrary.kt` | `validator(widget, compose-widget, util, android-util, res)` | `widget`, `compose-widget`, `util`, `android-util`, `res` |
| `util` | `util.kt` | `validator(util, library)` | `util`, `library` |
| `androidUtil` | `androidUtil.kt` | `validator(android-util, test-util, res, library)` | `android-util`, `test-util`, `res`, `library` |
Expand All @@ -103,9 +102,6 @@ These follow from the table (not from separate deny-lists):
- **`library` (JVM) cannot depend on `api` / `impl`** — comment in code:
“Can't depend on api\impl”.
- **`util` cannot depend on `api` / `impl`** — same intent as library.
- **`androidLibrary` cannot depend on `impl` / widgets / viewbinding** —
shared libs may use `api` contracts only (F-011).
- **`androidLibrary` is deprecated (F-060)** — temporary generic escape hatch; prefer `androidUtil` / `uiLibrary` / `androidRes` / `viewBinding` / `impl` / JVM `library`. See [`ANDROID-LIBRARY-DEPRECATION.md`](ANDROID-LIBRARY-DEPRECATION.md).
- **`viewBinding` may depend on `ui-library`** — shared UI bases without generic library (F-061).
- **`androidUtil` may depend on JVM `library`** — Android helpers wrapping pure JVM code (F-061).
- **`androidApp` / `androidBinary` cannot depend on other `binary`** —
Expand All @@ -117,7 +113,7 @@ These follow from the table (not from separate deny-lists):

### Compose flags (not project-dep rules)

Separate from suffix validation: `impl`, `androidLibrary`, `androidUtil`,
Separate from suffix validation: `impl`, `androidUtil`,
`androidApp`, `uiLibrary`, and `androidBinary` accept `compose: Boolean`
(default = project `androidProjectConfiguration(compose=…)`).
`composeWidget` **always** enables Compose. See [`COMPOSE.md`](COMPOSE.md).
Expand Down Expand Up @@ -160,7 +156,6 @@ Rows = **consumer**. Columns = **dependency type (suffix)**.
| **api** | Y | — | Y | — | — | — | — | — | — | — | — | — | — | — | — |
| **impl** | Y | — | Y | Y | Y | Y | Y | — | Y | Y | Y | Y | — | — | — |
| **library** (JVM) | — | — | — | — | Y | Y | — | — | — | — | — | — | — | — | — |
| **androidLibrary** | Y | — | Y | — | Y | Y | Y | — | Y | — | — | — | — | — | — |
| **uiLibrary** | — | — | — | — | Y | — | Y | — | Y | — | Y | Y | — | — | — |
| **util** | — | — | Y | — | Y | — | — | — | — | — | — | — | — | — | — |
| **androidUtil** | — | — | Y | — | — | Y | Y | — | Y | — | — | — | — | — | — |
Expand All @@ -184,13 +179,12 @@ allowed list (e.g. `api`→`api` **Y**, `impl`→`impl` **—**, `widget`→`wid

The historical README table used columns as *consumers* and rows as
*dependencies*, mixed aspirational edges, and omitted several types
(`uiLibrary`, `viewBinding`, `library` JVM vs `androidLibrary`, `native`).
(`uiLibrary`, `viewBinding`, `library` JVM, `native`).

Notable mismatches fixed by treating **this document** as truth:

| Topic | Old README implication | Live code |
|-------|------------------------|-----------|
| `androidLibrary` project deps | selective ✅/❌ grid | **restricted** (no `impl`/widget/viewbinding) after F-011 |
| `androidApp` / `androidBinary` project deps | selective grid | **restricted** composition-root lists after F-011 |
| `impl` → `impl` | ❌ (agrees) | not in allowed list |
| `api` → `library` | not clearly shown | **allowed** |
Expand Down
4 changes: 2 additions & 2 deletions docs/GETTING-STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ dependency**, and the allowed set — fix the edge, don’t weaken the graph.
| `viewBinding` | `viewbinding` | Layout XML (+ light binding-facing types) |
| `widget` | `widget` | Custom Views |
| `composeWidget` | `compose-widget` | Compose UI components (always Compose) |
| ~~`androidLibrary`~~ | `library` | **Deprecated** — use role-specific targets ([deprecation guide](ANDROID-LIBRARY-DEPRECATION.md)) |
| ~~`androidLibrary`~~ | | **Removed (F-063)** — use role-specific targets ([guide](ANDROID-LIBRARY-DEPRECATION.md)) |
| `library` | `library` | Shared pure JVM library |
| `uiLibrary` | `ui-library` | Shared UI building blocks for widgets |
| `util` / `androidUtil` / `testUtil` | `util` / `android-util` / `test-util` | Small helpers |
Expand Down Expand Up @@ -339,7 +339,7 @@ validator intent (F-011).

1. **`impl` → `impl` is forbidden.** Cross-feature collaboration goes through
`api` (or shared `core` libraries).
2. **Do not use deprecated `androidLibrary`.** Prefer `androidUtil` / `uiLibrary` /
2. **`androidLibrary` is gone (F-063).** Prefer `androidUtil` / `uiLibrary` /
`androidRes` / `viewBinding` so the graph stays flat and role-typed
([ANDROID-LIBRARY-DEPRECATION.md](ANDROID-LIBRARY-DEPRECATION.md)).
3. **`api` cannot contain `res/`.** Put resources in `androidRes` / `viewBinding`.
Expand Down
19 changes: 19 additions & 0 deletions docs/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

Newest entries first.

## 2026-07-17 — F-063: hard-remove `androidLibrary`

- **Ticket:** F-063 → `done` (P6 flat-structure complete)
- **Branch:** `forma/F-063-hard-remove-androidLibrary` from `origin/v2` @ `773d061`
- **Skills/modes:** Grok Build `--mode full` (design + implement hit max-turns with tree on disk); Hermes finish path: remaining docs, TICKETS/PROGRESS, verify, PR
- **Code:**
- Deleted `plugins/android/src/main/java/androidLibrary.kt` (public DSL)
- Removed `AndroidTargetTypes.library` (`android.library`)
- Dropped registry consumer registration + restriction-graph consumer rules
- Rewrote allow-lists (`api`/`impl`/`util`/`androidUtil`/`viewBinding`/`app`/`binary`) to depend on `jvmLibrary` (same `library` suffix)
- Kept `androidLibraryFeatureDefinition` (AGP wiring for impl/uiLibrary/etc.) + JVM `library()`
- Core unit tests still use synthetic `android.library` types for suffix-collision engine docs
- **Docs:** DEPENDENCY-MATRIX (first), ANDROID-LIBRARY-DEPRECATION lifecycle, README, ARCHITECTURE, VISION, GETTING-STARTED, COMPOSE, CONFIGURATION-PERFORMANCE, progressive examples + agent skills, plugins/android README
- **Verify (real host, OpenJDK via `scripts/env-mac.sh`):**
- `plugins/ ./gradlew build` → **BUILD SUCCESSFUL** (78 tasks)
- `application/ ./gradlew build` → **BUILD SUCCESSFUL** (2157 tasks)
- **Blockers:** none
- **Next:** prioritized queue empty again unless user adds F-xxx or promotes backlog (e.g. #110, #97, #88, #82, Portal #133)

## 2026-07-16 — F-060/061/062: deprecate androidLibrary, flatten sample + examples

- **Tickets:** F-060, F-061, F-062 → `done`; F-063 hard-remove remains `todo`
Expand Down
Loading
Loading