From 0d2a9df6fc4804cbbab0b72ed8d5aeeeadd94837 Mon Sep 17 00:00:00 2001 From: Ivan Morgillo Date: Tue, 7 Jul 2026 08:46:58 +0200 Subject: [PATCH 1/3] fix(audit): @NonSkippableComposable is not a lambda-memoization exception (4.3.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 4.3.1 sweep removed @NonSkippableComposable from every lambda-memoization exception except one caveat sentence in scoring.md — it read "opt-out path", so the string match skipped it. @NonSkippableComposable opts a *composable* out of skipping but does not disable *lambda memoization*; only @DontMemoize (or SSM-off) does. Now consistent across scoring.md. Both skills -> 4.3.2 (kept in lockstep). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016ysskXsKpwEbs1n9CX1ScY --- CHANGELOG.md | 7 +++++++ README.md | 8 ++++++-- skills/compose-agent/.claude-plugin/plugin.json | 2 +- skills/compose-agent/.cursor-plugin/plugin.json | 2 +- skills/compose-agent/SKILL.md | 2 +- skills/jetpack-compose-audit/.claude-plugin/plugin.json | 2 +- skills/jetpack-compose-audit/.cursor-plugin/plugin.json | 2 +- skills/jetpack-compose-audit/SKILL.md | 2 +- skills/jetpack-compose-audit/references/scoring.md | 2 +- 9 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 407a38f..553f132 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Full release history for the Compose Skill Suite. The newest release is summarised under **What's new** in the [README](./README.md). +### 4.3.2 — 2026-07-07 + +**Patch — one missed Strong Skipping caveat.** + +- **`jetpack-compose-audit/scoring.md`.** The 4.3.1 sweep removed `@NonSkippableComposable` from the lambda-memoization exceptions everywhere except one caveat sentence (it read "opt-out path", so the sweep's string match skipped it). Fixed: `@NonSkippableComposable` opts a *composable* out of skipping but does **not** disable lambda memoization — only `@DontMemoize` (or SSM-off) does. Now consistent across the file. +- **Versions.** `compose-agent` → `4.3.2`, `jetpack-compose-audit` → `4.3.2` (kept in lockstep). + ### 4.3.1 — 2026-07-06 **`compose-agent` authoring guidance for cross-phase back-writes + false leads, plus a suite-wide Strong Skipping correctness fix.** diff --git a/README.md b/README.md index 4146362..16c3b0b 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,9 @@ Claude Code plugin

-**`compose-agent` 4.3.1 · 2026-07-06** — Authoring guidance so the coding-agent skill *warns while you write*: **Never Back-Write Across Phases** (layout callbacks / snapshot-collection mutation feeding composition) and **Optimizations That Do Nothing** (the false leads). The 4.3.0 audit catches these after the fact; 4.3.1 stops you writing them. +**`compose-agent` 4.3.2 · 2026-07-07** — Authoring guidance so the coding-agent skill *warns while you write*: **Never Back-Write Across Phases** (layout callbacks / snapshot-collection mutation feeding composition) and **Optimizations That Do Nothing** (the false leads). The 4.3.0 audit catches these after the fact; 4.3.1 stops you writing them. -**`jetpack-compose-audit` 4.3.1 · 2026-07-06** — Cross-phase back-write detection (axis 3: layout callbacks writing state read in composition), a related composition-phase self-invalidation check (snapshot collections mutated in a composable body), and a **False Leads** scoring guard so the auditor stops crediting no-op "recomposition fixes." Adapted from [`chrisbanes/skills`](https://github.com/chrisbanes/skills) (Apache-2.0). +**`jetpack-compose-audit` 4.3.2 · 2026-07-07** — Cross-phase back-write detection (axis 3: layout callbacks writing state read in composition), a related composition-phase self-invalidation check (snapshot collections mutated in a composable body), and a **False Leads** scoring guard so the auditor stops crediting no-op "recomposition fixes." Adapted from [`chrisbanes/skills`](https://github.com/chrisbanes/skills) (Apache-2.0). **Version 4.2.0 · 2026-06-17** — Paging 3 in Compose: new `paging.md` reference (LLM guardrails, not API tour), audit hooks under existing Performance/State categories, planning doc at [`docs/paging-skill-plan.md`](./docs/paging-skill-plan.md). Validated through multi-agent cross-review. Both skills ship as `4.2.0`. @@ -31,6 +31,10 @@ Authored and cross-reviewed with every frontier model — Claude Opus 4.8, GPT-5 ## What's new +### 4.3.2 — 2026-07-07 + +**Patch.** Fixed one Strong Skipping caveat in `jetpack-compose-audit/scoring.md` that the 4.3.1 sweep missed (its "opt-out path" wording dodged the string match): `@NonSkippableComposable` opts a composable out of *skipping* but does not disable *lambda memoization* — only `@DontMemoize` / SSM-off does. Both skills → `4.3.2`. + ### 4.3.1 — 2026-07-06 **`compose-agent` — authoring guidance for cross-phase back-writes + false leads.** diff --git a/skills/compose-agent/.claude-plugin/plugin.json b/skills/compose-agent/.claude-plugin/plugin.json index 64c967d..96b4634 100644 --- a/skills/compose-agent/.claude-plugin/plugin.json +++ b/skills/compose-agent/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "compose-agent", - "version": "4.3.1", + "version": "4.3.2", "description": "Agent skill that helps AI coding assistants write modern Jetpack Compose: correct state, effects, performance-aware modifiers, Navigation 3, Paging 3 in Compose, coroutines on lifecycle, animations, UI tests, focus/keyboard navigation, Compose Multiplatform boundaries, Android launch resources, and idiomatic Kotlin. Targets the mistakes LLMs actually make in Compose code.", "author": { "name": "Ivan Morgillo" diff --git a/skills/compose-agent/.cursor-plugin/plugin.json b/skills/compose-agent/.cursor-plugin/plugin.json index 64c967d..96b4634 100644 --- a/skills/compose-agent/.cursor-plugin/plugin.json +++ b/skills/compose-agent/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "compose-agent", - "version": "4.3.1", + "version": "4.3.2", "description": "Agent skill that helps AI coding assistants write modern Jetpack Compose: correct state, effects, performance-aware modifiers, Navigation 3, Paging 3 in Compose, coroutines on lifecycle, animations, UI tests, focus/keyboard navigation, Compose Multiplatform boundaries, Android launch resources, and idiomatic Kotlin. Targets the mistakes LLMs actually make in Compose code.", "author": { "name": "Ivan Morgillo" diff --git a/skills/compose-agent/SKILL.md b/skills/compose-agent/SKILL.md index 1465538..8351f17 100644 --- a/skills/compose-agent/SKILL.md +++ b/skills/compose-agent/SKILL.md @@ -6,7 +6,7 @@ allowed-tools: Read, Glob, Grep, Edit, Write, Bash argument-hint: "[focus area, e.g. 'state', 'effects', 'navigation', 'paging', 'lifecycle', 'animation', 'testing', 'focus', 'kmp']" metadata: author: Ivan Morgillo - version: "4.3.1" + version: "4.3.2" --- # Compose Agent diff --git a/skills/jetpack-compose-audit/.claude-plugin/plugin.json b/skills/jetpack-compose-audit/.claude-plugin/plugin.json index a2f4c4b..2fdfaff 100644 --- a/skills/jetpack-compose-audit/.claude-plugin/plugin.json +++ b/skills/jetpack-compose-audit/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jetpack-compose-audit", - "version": "4.3.1", + "version": "4.3.2", "description": "Strict, evidence-based audit for Android Jetpack Compose repositories. Produces a 0-100 score, per-category 0-10 scores, a COMPOSE-AUDIT-REPORT.md with every deduction cited against developer.android.com, and coverage notes for animation performance, paging list correctness, UI tests, focus/keyboard, Compose Multiplatform, and Android launch UX surfaces.", "author": { "name": "Ivan Morgillo" diff --git a/skills/jetpack-compose-audit/.cursor-plugin/plugin.json b/skills/jetpack-compose-audit/.cursor-plugin/plugin.json index a2f4c4b..2fdfaff 100644 --- a/skills/jetpack-compose-audit/.cursor-plugin/plugin.json +++ b/skills/jetpack-compose-audit/.cursor-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jetpack-compose-audit", - "version": "4.3.1", + "version": "4.3.2", "description": "Strict, evidence-based audit for Android Jetpack Compose repositories. Produces a 0-100 score, per-category 0-10 scores, a COMPOSE-AUDIT-REPORT.md with every deduction cited against developer.android.com, and coverage notes for animation performance, paging list correctness, UI tests, focus/keyboard, Compose Multiplatform, and Android launch UX surfaces.", "author": { "name": "Ivan Morgillo" diff --git a/skills/jetpack-compose-audit/SKILL.md b/skills/jetpack-compose-audit/SKILL.md index 22f2425..b5e0a8c 100644 --- a/skills/jetpack-compose-audit/SKILL.md +++ b/skills/jetpack-compose-audit/SKILL.md @@ -9,7 +9,7 @@ argument-hint: "[repo path or module path]" This skill audits Android Jetpack Compose repositories with a strict, evidence-based report. -**Skill version:** 4.3.1 — released 2026-07-06. **Compose track:** Kotlin 2.0.20+ / Compose Compiler 1.5.4+ (Strong Skipping Mode default). See the README changelog for what changed. +**Skill version:** 4.3.2 — released 2026-07-07. **Compose track:** Kotlin 2.0.20+ / Compose Compiler 1.5.4+ (Strong Skipping Mode default). See the README changelog for what changed. It is intentionally focused on four categories: diff --git a/skills/jetpack-compose-audit/references/scoring.md b/skills/jetpack-compose-audit/references/scoring.md index 540c56d..18e5c29 100644 --- a/skills/jetpack-compose-audit/references/scoring.md +++ b/skills/jetpack-compose-audit/references/scoring.md @@ -194,7 +194,7 @@ Changes that *look* like recomposition fixes but do not reduce recomposition cou | Forcing `assertRecompositionCount(Exactly(1))` on **both** rows in a focus-move / selection test | One row often *correctly* recomposes 0 times; the assertion encodes a wrong expectation, not a fix | Assert the count each row should actually have; investigate only rows that exceed it | | Manually `remember`-ing callbacks **under Strong Skipping** (Kotlin 2.0.20+ default) to "stabilize" them | SSM auto-memoizes lambdas already — *including those with unstable captures*; wrapping them in `remember` adds bookkeeping for no skipping benefit | Nothing — SSM has it covered. Only matters SSM-**off** or on a `@DontMemoize` path: then hoist **and** stabilize, or pass a method reference | -**Strong Skipping caveat for the last row:** the "fresh lambda defeats skipping" reasoning only holds when SSM is **off**, or the lambda sits on a `@DontMemoize` / `@NonSkippableComposable` opt-out path. On the default SSM track, manual `remember` on the callback is itself the no-op — SSM memoizes lambdas *even with unstable captures*, so do not recommend it, and do not deduct for its absence. Decide which compiler track applies (see the Strong Skipping Mode Check) before scoring this one. +**Strong Skipping caveat for the last row:** the "fresh lambda defeats skipping" reasoning only holds when SSM is **off**, or the lambda sits on a `@DontMemoize` opt-out path. (`@NonSkippableComposable` opts the *composable* out of skipping but does **not** disable lambda memoization — do not list it here.) On the default SSM track, manual `remember` on the callback is itself the no-op — SSM memoizes lambdas *even with unstable captures*, so do not recommend it, and do not deduct for its absence. Decide which compiler track applies (see the Strong Skipping Mode Check) before scoring this one. Route: the cross-phase and stability *detectors* live in the search playbook; this false-lead guard lives here in scoring and gates what those detectors are allowed to recommend. Before crediting any "we optimized recomposition here" claim, confirm it is not one of the above — prefer runtime recomposition counts or compiler reports as proof over the presence of the pattern. From 54ae407b3387a6f58efd96b3ca9cef79906d0bbb Mon Sep 17 00:00:00 2001 From: Ivan Morgillo Date: Tue, 7 Jul 2026 08:53:20 +0200 Subject: [PATCH 2/3] review: correct release-notes-4.3.1 lambda-memo exception (was same bug) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cursor should-fix: docs/release-notes-4.3.1.md still paired @NonSkippableComposable with the lambda-memoization exception — the exact error this patch fixes. Corrected to @DontMemoize only, with a "corrected in 4.3.2" note. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016ysskXsKpwEbs1n9CX1ScY --- docs/release-notes-4.3.1.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/release-notes-4.3.1.md b/docs/release-notes-4.3.1.md index dc1beb8..dad5c86 100644 --- a/docs/release-notes-4.3.1.md +++ b/docs/release-notes-4.3.1.md @@ -20,9 +20,9 @@ Follow-up to 4.3.0. That release taught the **audit** to catch cross-phase back- ## `jetpack-compose-audit` — Strong Skipping correctness fix -The 4.3.0 false-lead guard said manual callback `remember` could still matter "when the lambda captures an unstable value." That contradicts the official [Strong Skipping docs](https://developer.android.com/develop/ui/compose/performance/stability/strongskipping): SSM memoizes lambdas **even with unstable captures**, so the carve-out could still bless the exact no-op the guard forbids. Removed from `scoring.md` in all four places; the only remaining exception is SSM-off or a `@DontMemoize` / `@NonSkippableComposable` path. +The 4.3.0 false-lead guard said manual callback `remember` could still matter "when the lambda captures an unstable value." That contradicts the official [Strong Skipping docs](https://developer.android.com/develop/ui/compose/performance/stability/strongskipping): SSM memoizes lambdas **even with unstable captures**, so the carve-out could still bless the exact no-op the guard forbids. Removed from `scoring.md`; the only remaining exception is SSM-off or a `@DontMemoize` path. (4.3.1 initially still paired `@NonSkippableComposable` here — **corrected in 4.3.2**: that annotation opts a composable out of skipping, not lambda memoization.) -The same correction lands in `compose-agent/performance.md`: the *Strong Skipping baseline*, *Lambdas In Composables*, and *Optimizations That Do Nothing* sections now agree. The old "lambdas passed across module boundaries to generic composables can miss memoization" bullet was dropped — under SSM, lambda memoization happens at the caller's compilation regardless of the callee's module/generics, so that case is obsolete; the real exceptions are SSM-off / `@DontMemoize` / `@NonSkippableComposable`. +The same correction lands in `compose-agent/performance.md`: the *Strong Skipping baseline*, *Lambdas In Composables*, and *Optimizations That Do Nothing* sections now agree. The old "lambdas passed across module boundaries to generic composables can miss memoization" bullet was dropped — under SSM, lambda memoization happens at the caller's compilation regardless of the callee's module/generics, so that case is obsolete; the real exceptions are SSM-off / `@DontMemoize`. ## Eval coverage From 39d44eda41c30c108edd64fe5644824538999f68 Mon Sep 17 00:00:00 2001 From: Ivan Morgillo Date: Tue, 7 Jul 2026 08:54:23 +0200 Subject: [PATCH 3/3] review: also correct the same pairing in release-notes-4.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release-notes-4.3.0.md line 27 still paired @NonSkippableComposable with the lambda-memoization exception (historical false-lead bullet). Corrected to @DontMemoize only, with a note. Completes the suite-wide sweep — no authoritative doc now lists @NonSkippableComposable as a lambda-memoization opt-out. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_016ysskXsKpwEbs1n9CX1ScY --- docs/release-notes-4.3.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes-4.3.0.md b/docs/release-notes-4.3.0.md index 2e63547..8739936 100644 --- a/docs/release-notes-4.3.0.md +++ b/docs/release-notes-4.3.0.md @@ -24,7 +24,7 @@ A guard table in `scoring.md` Performance: plausible "recomposition fixes" that - Identity/instance caches for read-only derived maps (use `remember(keys)`). - Layout modifiers on both the measured and the sibling row (the sibling still reads size in composition). - `assertRecompositionCount(Exactly(1))` forced on both rows when one correctly recomposes 0 times. -- Under **Strong Skipping**, manually `remember`-ing a callback the compiler already auto-memoizes — that lever only applies SSM-off or on `@NonSkippableComposable` / `@DontMemoize` paths. (Historical note: 4.3.0 also listed "or when the lambda captures an unstable value" — **corrected in 4.3.1**; SSM memoizes lambdas even with unstable captures.) +- Under **Strong Skipping**, manually `remember`-ing a callback the compiler already auto-memoizes — that lever only applies SSM-off or on a `@DontMemoize` path. (Historical note: 4.3.0 also listed "or when the lambda captures an unstable value" and `@NonSkippableComposable` here — **corrected in 4.3.1 / 4.3.2**; SSM memoizes lambdas even with unstable captures, and `@NonSkippableComposable` opts a composable out of skipping, not lambda memoization.) The guard verifies against runtime recomposition counts / compiler reports rather than the presence of a pattern.