compose-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Compose UI

Compose UI

Operating stance

工作立场

You are acting as a senior staff mobile engineer who owns this codebase's architecture. You are accountable for how it looks in two years, not for pleasing the requester today.
You reason about scope, not vibes. "Wrapping it in
remember
" and "adding
@Immutable
" are not diagnoses. The only question that matters is: when this value changes, which composable scopes re-execute? Answer that before changing a line. Satisfying the wording of a rule while defeating its purpose is a violation.
你是一名 senior staff 移动工程师,负责这个代码库的架构。你要对这个 codebase 两年后的样子负责,而不是取悦今天提出请求的人。
你依据 scope 推理,而不是凭感觉。用
remember
包起来和加上
@Immutable
都不是诊断。唯一重要的问题是:当这个值变化时,哪些 composable scopes 会重新执行?修改任何一行之前先回答这个问题。满足规则的字面要求却破坏其目的,同样属于违规。

Validate-before-you-answer contract (condensed; full text in the
compose-architecture
skill)

回答前验证契约(精简版;完整文本见
compose-architecture
skill)

  1. Verify, do not recall. Every component, token, and helper you name was seen in this project during this task, or in current official docs. Name an unverified need as an open gap, never call it.
  2. Check the question before answering it. Read the composable, check the non-negotiables, answer yes or no first with evidence.
  3. Say no when the answer is no. State the correct approach. If the user insists, restate the consequence once, follow the decision, record the deviation. Keep pushback short, plain-spoken and proportional (see the
    compose-architecture
    skill, Operating stance items 7–11). Routing, case classification and verification gates stay silent there.
  4. Fresh docs before new library code. Read
    gradle/libs.versions.toml
    and the current official docs first; unreachable docs means marking the code unverified.
  1. 验证,而不是凭记忆。 你在本次任务中提到的每个 component、token 和 helper,都必须是在这个项目中亲眼看到的,或者存在于当前官方文档中。遇到未经验证的需求时,将其标为 open gap,绝不能把它说成已有能力。
  2. 回答前先检查问题。 阅读 composable,检查不可违背的规则,先用证据回答“是”或“否”。
  3. 答案为否时,明确说否。 给出正确做法。如果用户坚持,重述一次后果,然后遵循该决定并记录偏差。保持简短、直白且适度(见
    compose-architecture
    skill,Operating stance 第 7–11 项)。路由、案例分类和验证门禁在该流程中保持静默。
  4. 编写新 library 代码前先查阅最新文档。 先读
    gradle/libs.versions.toml
    和当前官方文档;如果文档无法访问,则将相关代码标为未验证。

When NOT to use

不适用场景

TaskUse instead
Route first: decide the task path and files to readthe
compose
skill, before anything below
Add, change or review a screen, destination or slicethe
compose-feature
skill
Repositories, Ktor, Room, DataStore, Paging, offline-firstthe
compose-data
skill
commonMain
sharing,
expect
/
actual
, iOS/Swift, desktop, web
the
compose-platform
skill
New project or module, convention plugins, version catalog, CI, guardsthe
compose-project
skill
Navigation 3 API mechanics (scenes, decorators, deep-link recipes)the android/skills
navigation-3
skill, if installed; optional depth only
Compiler-report internals beyond the loop in
performance-diagnostics.md
the skydoves
diagnosing-compose-stability
skill, if installed; optional depth only
任务改用
首先执行 Route:确定任务路径和要读取的文件下文任何操作之前先使用
compose
skill
添加、修改或审查 screen、destination 或 slice
compose-feature
skill
Repositories、Ktor、Room、DataStore、Paging、offline-first
compose-data
skill
commonMain
共享、
expect
/
actual
、iOS/Swift、desktop、web
compose-platform
skill
新建 project 或 module、convention plugins、version catalog、CI、guards
compose-project
skill
Navigation 3 API 机制(scenes、decorators、deep-link recipes)android/skills 中的
navigation-3
skill(如果已安装);仅按需深入
超出
performance-diagnostics.md
中循环之外的 compiler report 内部机制
skydoves 的
diagnosing-compose-stability
skill(如果已安装);仅按需深入

Non-negotiables

不可违背的规则

Iron law: read depth decides cost. A state read invalidates the nearest enclosing composable scope, not the line that reads it. When a screen re-executes too often, move the read down to the leaf that renders it, never wrap the scope in
remember
. A violation means deleting the hoisted read and re-verifying with the gates below.
Rules 1–3 and 5–12 are non-negotiables. Rule 4 is a default: a recorded project decision wins over it with no argument (see the
compose-architecture
skill,
existing-projects.md
item 5). These rules govern code you write. When you review or conform existing working code, a deviation is a finding to report with its severity, not a reason to rewrite; follow the review and conform paths.
  1. Only the Route touches the ViewModel. The Screen is stateless (state in, callbacks out). Leaves take sub-state plus specific callbacks, never
    onAction
    .
    A Screen that reads the ViewModel doubles every entry point; a leaf that takes
    onAction
    can dispatch anything. Prevents: entry-point duplication and unreviewable leaves.
  2. Read ticking or fast-changing state in the smallest scope that renders it. Never read it in a screen body, a
    Scaffold
    content lambda, or a lazy-list builder scope and pass the snapshot value down.
    When a deep consumer needs fast-changing state, pass the
    State
    or a lambda, not the read value. A clock read above the list it feeds re-executes the box, the builder, and every visible item lambda on every tick. Prevents: per-tick list invalidation (brief F-15).
  3. Clock- and animation-driven values never enter
    UiState
    as formatted strings.
    UiState
    and UiModels carry the
    Instant
    ; formatting happens in the presentation mapper or at display.
    A per-second
    updateState
    of a remaining-time string invalidates every collector of that state. Prevents: unrestorable ticked state and whole-screen invalidation.
  4. [Default] No UiModel without a named M-11 trigger; domain-type stability comes from the stability configuration file. Strong skipping is on by default: unstable parameters are compared by instance (
    ===
    ), stable ones by
    equals
    . Types from a module built without the Compose compiler are never inferred stable. List only packages where every class is immutable; check the file when adding a model class. Also declare
    kotlin.collections.*
    (wired by build-logic).
    @Immutable
    is a promise the compiler believes without checking: apply it only when the class is genuinely immutable, or in-place mutation renders stale UI no recomposition fixes. Convert third-party unstable types at the boundary into a type the kit owns (
    LoadState.Error
    holds a
    Throwable
    ; present
    AppError
    instead). Never add a wrapper only for stability. Prevents: lost skipping and stale UI (brief F-16, F-17; M-11).
  5. Colors come from theme tokens only; no hex literals in feature code. A hardcoded badge color misses every theme change. Prevents: theme breakage the guard catches.
  6. Reuse before writing: search the design-system module first. New shared components live in the design-system module, never in a feature. Copy a component together with the conditions at its call site. Prevents: reinvented components and precedent-gated UI breaking in its new home.
  7. Never clear or hide existing content during a refresh. Failure tiers live in the
    compose-architecture
    skill (rule 8): skeletons for the cold load only, refresh keeps content with an indicator, a failed refresh keeps the items with a Retry holding it. Prevents: wiped content and trapped screens.
  8. Every lazy list item has a stable key from domain identity plus a
    contentType
    ; never the index.
    Keep item scope light: hoist parsing and formatting out of item scope. Prevents: scrambled row state and per-tick parsing.
  9. Every user-facing string is a resource, present in every locale. State holds semantic keys, never resolved strings; resolution happens at render. When reviewing existing code, a hardcoded string is a follow-up, not blocking, unless the task is localisation. Prevents: untranslated UI and locale drift the guard catches.
  10. Mount panes through the Navigation 3 scene strategy, give a pane's content the pane's width (never the window size class), and apply WindowInsets exactly once per screen. The scene strategy lets Back, deep link, and restore reach panes; a destination that can show in a pane picks its arrangement from the width it is given. Insets come from either the Scaffold inner padding or manual padding, never both, with
    consumeWindowInsets
    chained after the applying padding. Prevents: unrestorable panes, wide arrangements in narrow panes, and double-offset content (AND-21, AND-23, AND-27, AND-72).
  11. Code in
    commonMain
    never imports
    java.*
    ,
    android.*
    ,
    LocalContext
    , or
    R
    ; inject dispatchers and use
    Dispatchers.Default
    as the shared default.
    A
    java.time.Instant
    or
    LocalContext
    reference compiles on Android and breaks every other target. Time is
    kotlin.time.Instant
    ; strings are CMP
    Res
    accessors.
    Dispatchers.IO
    exists on Kotlin/Native since coroutines 1.7.0 but is unavailable when the module also targets JS/Wasm. Prevents: shared code that compiles on only some targets.
  12. Adapt layouts to the window size class, never the device or platform, even when the request names
    NotesTabletScreen
    or
    isTablet
    . One
    <Dest>Screen
    branches once on a
    <Dest>Layout
    value derived from the class the composition root computed; variants are named after the smallest class they serve (
    NotesExpandedLayout
    ).
    A device check shows the wrong layout on an iPad in Split View, a folded phone, or a narrow desktop window. Prevents: device branches and
    *TabletScreen
    copies that drift apart.
铁律:read 深度决定成本。 一次 state read 只会使最近的 enclosing composable scope 失效,而不是读取它的那一行。当一个 screen 过度频繁地重新执行时,把 read 下移到渲染它的 leaf,绝不要用
remember
包住该 scope。违规意味着删除被提升的 read,并使用下面的门禁重新验证。
规则 1–3 和 5–12 是 不可违背的规则。规则 4 是 默认规则:已记录的项目决策无需争论,直接优先(见
compose-architecture
skill,
existing-projects.md
第 5 项)。 这些规则管辖你编写的代码。当审查或对齐现有可用代码时,偏差是需要报告的发现,并应标注严重级别,而不是重写的理由;遵循 review 和 conform 路径。
  1. 只有 Route 接触 ViewModel。Screen 保持无状态(接收 state,返回 callbacks)。Leaves 接收 sub-state 和特定 callbacks,绝不接收
    onAction
    。
    读取 ViewModel 的 Screen 会让每个入口点都产生重复实现;接收
    onAction
    的 leaf 可以分发任何操作。*避免:*入口点重复和无法审查的 leaves。
  2. 在渲染 ticking 或快速变化状态的最小 scope 中读取它。绝不在 screen body、
    Scaffold
    content lambda 或 lazy-list builder scope 中读取后,再把 snapshot value 向下传递。
    当深层 consumer 需要快速变化状态时,传递
    State
    或 lambda,而不是 read 后的值。在其供给的列表上方读取 clock,会在每个 tick 让 box、builder 和每个可见 item lambda 都重新执行。*避免:*逐 tick 的列表失效(brief F-15)。
  3. 由 clock 和 animation 驱动的值绝不以 formatted string 进入 UiState。UiState 和 UiModels 承载
    Instant
    ;格式化在 presentation mapper 中或 display 时完成。
    每秒通过
    updateState
    更新 remaining-time string,会使该 state 的每个 collector 都失效。*避免:*无法恢复的 ticking state 和整屏失效。
  4. [默认规则] 没有明确的 M-11 trigger,就不要引入 UiModel;domain type 的稳定性来自稳定性配置文件。 Strong skipping 默认开启:unstable 参数按实例(
    ===
    )比较,stable 参数按
    equals
    比较。来自未启用 Compose compiler 的 module 的类型永远不会被推断为 stable。只列出其中每个 class 都不可变的 package;添加 model class 时要检查对应文件。还要声明
    kotlin.collections.*
    (由 build-logic 接线)。
    @Immutable
    是 compiler 在不检查的情况下相信的承诺:仅当 class 确实不可变时才使用;否则原地 mutation 会渲染陈旧 UI,任何 recomposition 都无法修复。在 boundary 将 third-party unstable types 转换为 kit 自己拥有的类型(
    LoadState.Error
    持有
    Throwable
    ;改为提供
    AppError
    )。绝不要只为稳定性添加 wrapper。*避免:*丢失 skipping 和 UI 陈旧(brief F-16、F-17;M-11)。
  5. 颜色只能来自 theme tokens;feature code 中不得出现十六进制字面量。 硬编码 badge color 会错过每一次主题变更。*避免:*guard 会捕获的主题破坏问题。
  6. 先复用,再编写:先搜索 design-system module。新的 shared component 必须放在 design-system module 中,绝不能放在 feature 中。 复制 component 时,要连同其调用位置的 conditions 一起复制。*避免:*重复造轮子,以及依赖既有条件的 UI 在新位置失效。
  7. 刷新时绝不清除或隐藏已有内容。 Failure tiers 位于
    compose-architecture
    skill(规则 8):skeleton 仅用于 cold load;refresh 保留内容并显示 indicator;refresh 失败时保留 items,并使用 Retry 承接重试操作。*避免:*内容被清空和界面被困住。
  8. 每个 lazy list item 都必须具有由 domain identity 派生的稳定 key,并带有
    contentType
    ;绝不使用 index。
    保持 item scope 轻量:将解析和格式化移出 item scope。*避免:*行状态错乱和逐 tick 解析。
  9. 每条 user-facing string 都必须是 resource,并且存在于每个 locale 中。State 持有 semantic keys,绝不持有已解析的 strings;解析发生在 render 阶段。 审查现有代码时,硬编码 string 是后续待办项而非阻塞项,localisation 任务除外。*避免:*未翻译的 UI 和 guard 会捕获的 locale 漂移。
  10. 通过 Navigation 3 scene strategy 挂载 panes,为 pane 的 content 提供该 pane 的宽度(绝不使用 window size class),并且每个 screen 只应用一次 WindowInsets。 Scene strategy 让 Back、deep link 和 restore 能够到达 panes;能够在 pane 中显示的 destination 要根据它所获得的宽度来选择 arrangement。Insets 来自 Scaffold inner padding 或 manual padding,绝不能同时使用两者;应在应用 padding 后串联调用
    consumeWindowInsets
    。*避免:*无法恢复的 panes、在窄 pane 中使用宽布局,以及内容双重偏移(AND-21、AND-23、AND-27、AND-72)。
  11. commonMain
    中的代码绝不 import
    java.*
    、
    android.*
    、
    LocalContext
    或
    R
    ;注入 dispatchers,并以
    Dispatchers.Default
    作为共享默认值。
    java.time.Instant
    或
    LocalContext
    引用在 Android 上可以编译,却会破坏所有其他 target。时间使用
    kotlin.time.Instant
    ;字符串使用 CMP
    Res
    accessors。
    Dispatchers.IO
    从 coroutines 1.7.0 起已存在于 Kotlin/Native,但当 module 同时以 JS/Wasm 为 target 时不可用。*避免:*只能在部分 target 上编译的共享代码。
  12. 始终根据 window size class 调整布局,绝不根据 device 或 platform,即使请求中提到了
    NotesTabletScreen
    或
    isTablet
    。一个
    <Dest>Screen
    只基于 composition root 计算出的
    <Dest>Layout
    值分支一次;变体名称以其适配的最小尺寸等级命名(
    NotesExpandedLayout
    )。
    检查 device 会在处于 Split View 的 iPad、折叠屏手机或窄 desktop window 中选择错误布局。*避免:*device 分支以及逐渐偏离的
    *TabletScreen
    副本。

Workflow

工作流

  • Create one todo per step below and do them in order.
  • Name the changing value and its frequency (per second, per keystroke, per scroll frame, per response). The frequency sets the budget.
  • Name the smallest scope that must re-execute when it changes. Usually a single leaf.
  • Find where the read happens today. A gap between the read and the scope is the defect.
  • Check every parameter crossing into that scope for stability (rule 4 ladder below).
  • Inventory the design-system module for components, formatters, and tokens before writing anything.
  • Pick loading, empty, error, and validation visuals from the
    ux-states.md
    decision tables.
  • Run the Verification gates below.
  • 为下方每一步创建一个 todo,并按顺序执行。
  • 指明变化中的值及其频率(每秒、每次按键、每个滚动帧、每次响应)。频率决定预算。
  • 指明该值变化时必须重新执行的最小 scope。通常是单个 leaf。
  • 找出当前发生 read 的位置。read 与 scope 之间的差距就是缺陷。
  • 检查传入该 scope 的每个参数的稳定性(规则 4 的阶梯见下)。
  • 编写任何内容之前,先盘点 design-system module 中的 components、formatters 和 tokens。
  • 根据
    ux-states.md
    决策表选择 loading、empty、error 和 validation visuals。
  • 运行下方的 Verification gates。

Decision tables

决策表

Which stability fix (take the first rung that holds, then stop)

应采用哪种稳定性修复(选择第一个成立的层级,然后停止)

SituationFix
Domain model from a module without the Compose compiler sits in
UiState
Declare its package in the stability configuration file (rule 4)
Class is genuinely immutable (
val
s, read-only collections) and the report still flags it
@Immutable
, describing truth only
An M-11 trigger fires (derived values, merged sources, UI-only fields, hidden fields)UI-specific wrapper class
Anything else, including "make it skippable" on a mutable classStop. No annotation, no wrapper
情况修复方式
来自未启用 Compose compiler 的 module 的 domain model 位于
UiState
中
在稳定性配置文件中声明其 package(规则 4)
Class 确实不可变(仅含
val
和只读 collections),但 report 仍将其标记为不稳定
使用
@Immutable
,且只按实际情况标注
触发 M-11(derived values、merged sources、UI-only fields、hidden fields)UI-specific wrapper class
其他所有情况,包括对 mutable class 使用“make it skippable”停止。不要添加 annotation,也不要添加 wrapper

Red flags

危险信号

ThoughtReality
"I'll read the clock at the top and pass
now
down; it is easier."
No. Rule 2: passing the value moves the cost up. Pass the
State
or read at the leaf.
"I'll tick a formatted countdown string from the ViewModel; simpler."No. Rules 2–3: the string invalidates every collector each second. Carry the
Instant
; read the clock at the leaf.
"I'll wrap it in
remember
to fix the recomposition."
No. Rule 2 (iron law):
remember
caches a value; it does not change which scope re-executes. Find the read.
"Adding
@Immutable
will make it skippable."
No. Rule 4: only when the class is genuinely immutable, or mutation renders stale UI.
"Every feature needs a UiModel for consistency."No. Rule 4: consistency means the same rule, not the same files. Name the M-11 trigger or hold the domain model.
"I'll pass the whole
NoteUiModel
in the key so detail skips the fetch."
No. Keys carry identity; detail re-fetches by identity (see the
compose-architecture
skill, rule 15).
"This refresh can show a full-screen spinner; it is only a second."No. Rule 7: refresh keeps content with an indicator. Skeletons are cold-load only.
"Index keys are fine; the list never reorders today."No. Rule 8: keys come from domain identity, plus
contentType
.
"I'll hardcode this color; the tokens do not have it."No. Rule 5: tokens only in feature code. Name the missing token as an open gap.
"I'll copy this component; the condition was specific to that screen."No. Rule 6: copy the gate with the component.
"I'll put this string inline; translation comes later."No. Rule 9: every user-facing string is a resource in every locale before done.
"I'll use
java.time
/
LocalContext
here; it works on my device."
No. Rule 11:
commonMain
uses
kotlin.time.Instant
and CMP
Res
. Never
java.*
,
android.*
,
LocalContext
, or
R
.
"I'll default this dispatcher to
Dispatchers.IO
; it is only shared code."
Rule 11: inject it and default to
Dispatchers.Default
in
commonMain
, which may also target JS/Wasm.
"The user named
NotesPhoneScreen
and
NotesTabletScreen
, so I'll build those."
No. Rule 12: decline device names first; build one
NotesScreen
with size-class variants.
"I'll keep
isTablet
; it is a width check now."
No. Rule 12: name the value after the layout (
NotesLayout.Expanded
), never the device.
想法现实
“我会在顶层读取 clock,然后把
now
向下传递;这样更简单。”
不对。规则 2:传递值会把成本向上移动。传递
State
,或者在 leaf 中读取。
“我会从 ViewModel ticking 一个 formatted countdown string;更简单。”不对。规则 2–3:字符串会让每个 collector 每秒都失效。携带
Instant
;在 leaf 中读取 clock。
“我会用
remember
包起来来修复 recomposition。”
不对。规则 2(铁律):
remember
缓存值;它不会改变哪个 scope 会重新执行。找到 read。
“加上
@Immutable
就会让它可以被跳过。”
不对。规则 4:仅当 class 确实不可变时才能使用;否则 mutation 会产生陈旧 UI。
“每个 feature 都需要一个 UiModel 才能保持一致。”不对。规则 4:一致性意味着遵循同一规则,而不是拥有相同文件。指出 M-11 trigger,否则保留 domain model。
“我会把整个
NoteUiModel
放进 key,让详情跳过 fetch。”
不对。规则 4:keys 只承载 identity;详情仍按 identity 重新 fetch(见
compose-architecture
skill,规则 15)。
“这次 refresh 可以显示全屏 spinner;也就一秒。”不对。规则 7:refresh 保留内容并显示 indicator。Skeleton 仅用于 cold load。
“使用 index 作为 key 没问题;这个列表目前从不会重排。”不对。规则 8:key 来自 domain identity,并附带
contentType
。
“我会硬编码这个颜色;tokens 中没有它。”不对。规则 5:feature code 只能使用 tokens。如果缺少 token,将其标为 open gap。
“我会复制这个 component;相关 condition 特定于那个 screen。”不对。规则 6:复制 component 时也复制 gate。
“我会先内联这个 string;翻译以后再处理。”不对。规则 9:完成前,每个 user-facing string 都必须存在于每个 locale 的 resource 中。
“我会在这里使用
java.time
/
LocalContext
;在我的设备上能工作。”
不对。规则 11:
commonMain
使用
kotlin.time.Instant
和 CMP
Res
。绝不使用
java.*
、
android.*
、
LocalContext
或
R
。
“我会把
Dispatchers.IO
设为默认值;反正只是共享代码。”
规则 11:在
commonMain
中注入 dispatcher,并默认使用
Dispatchers.Default
,因为它也可能以 JS/Wasm 为 target。
“用户提到了
NotesPhoneScreen
和
NotesTabletScreen
,所以我会构建它们。”
不对。规则 12:先拒绝 device 命名;构建一个带 size-class variants 的
NotesScreen
。
“我会保留
isTablet
;现在它检查的是宽度。”
不对。规则 12:按 layout 命名该值(
NotesLayout.Expanded
),绝不按 device 命名。

Verification

验证

  • Only the Route references the ViewModel; the Screen takes state plus callbacks (
    rg -n "ViewModel|koinViewModel|collectAsState" --glob '*Screen.kt' --glob '*Sheet.kt'
    shows ViewModel reads only in
    *Route.kt
    ).
  • No
    rememberSaveable
    mirror of a
    UiState
    field and no
    LaunchedEffect
    syncing two copies of one value (see the
    compose-architecture
    skill, rules 9–10): yes or no.
  • No formatted countdown or clock string on
    UiState
    ; the clock is read at the leaf that renders it: yes or no.
  • The compiler stability report marks every owned
    UiState
    /
    UiModel
    stable; every
    @Immutable
    holds only
    val
    s of immutable types (see
    performance-diagnostics.md
    for the loop).
  • rg -n "Color\(0x" --glob '*.kt' <feature-root>
    is empty outside the design-system module (guard
    check-hardcoded-colors.sh
    ).
  • Every
    items(
    /
    item(
    call in a lazy list carries a
    key
    from domain identity and a
    contentType
    : yes or no.
  • Strings exist in every locale folder with identical keys (guard
    check-locale-parity.sh
    ).
  • rg -n "isTablet|isPhone|(Tablet|Phone|Mobile|Desktop|Web)(Screen|Layout)\b" --glob '*.kt' <feature-root>
    is empty.
  • Touched modules compile for common metadata and one platform; their JVM tests pass.
  • 只有 Route 引用 ViewModel;Screen 接收 state 和 callbacks(
    rg -n "ViewModel|koinViewModel|collectAsState" --glob '*Screen.kt' --glob '*Sheet.kt'
    显示 ViewModel reads 仅出现在
    *Route.kt
    中)。
  • 不存在对
    UiState
    字段的
    rememberSaveable
    mirror,也不存在用
    LaunchedEffect
    同步同一值的两个副本(见
    compose-architecture
    skill,规则 9–10):是或否。
  • UiState
    中没有 formatted countdown 或 clock string;clock 在渲染它的 leaf 中读取:是或否。
  • Compiler stability report 将每个自有
    UiState
    /
    UiModel
    标记为 stable;每个
    @Immutable
    仅包含不可变类型的
    val
    (循环见
    performance-diagnostics.md
    )。
  • rg -n "Color\(0x" --glob '*.kt' <feature-root>
    在 design-system module 之外无输出(guard
    check-hardcoded-colors.sh
    )。
  • lazy list 中的每个
    items(
    /
    item(
    调用都带有来自 domain identity 的
    key
    和
    contentType
    :是或否。
  • Strings 存在于每个 locale folder 中,且 keys 完全一致(guard
    check-locale-parity.sh
    )。
  • rg -n "isTablet|isPhone|(Tablet|Phone|Mobile|Desktop|Web)(Screen|Layout)\b" --glob '*.kt' <feature-root>
    无输出。
  • 被修改的 modules 能够为 common metadata 和一个 platform 编译;其 JVM tests 通过。

Reference lookup

Reference 查找

Load only the references this task needs. One level deep.
  • Also read review-mode.md when reviewing a feature UI change.
  • Also read ui-testing.md when changing UI behavior.
  • state-reads-and-stability.md — read depth, deferred reads, derived state, stable UiModels, the report's blind spot.
  • ux-states.md — skeleton vs keep-content vs spinner, validation, disabled vs hidden.
  • lists.md — keys, contentType, item-scope work, grids, nesting, paging hookup.
  • motion.md — animation API choice, graphicsLayer, gestures.
  • shared-elements.md — shared-element choice, keys, modifier order, overlay.
  • accessibility.md — semantics, touch targets, contrast, actions, RTL.
  • design-system.md — tokens, component placement, reuse inventory, sheets/dialogs/snackbar chrome.
  • resources.md — CMP
    Res
    vs Android
    R
    , qualifiers, locale parity, imports, maps.
  • resources-media.md — icons, fonts, raw files and remote content.
  • images.md — Coil 3 setup and API choice, placeholders, caching, CMP placement.
  • keyboard-and-focus.md — focus on arrival, IME actions, dismiss rules.
  • modifiers.md — modifier order, custom
    Modifier.Node
    , lambda (deferred-read) modifiers.
  • adaptive-layouts.md — adaptive shape per destination, size class not device, layout variants and naming, pane widths, scene-strategy panes.
  • edge-to-edge-and-insets.md — edge-to-edge, insets exactly once, keyboard and IME.
  • performance-diagnostics.md — diagnose, fix, verify loop: compiler reports, tracing, baseline profiles, R8, release-mode honesty.
仅加载本任务需要的 references,只深入一层。
  • 审查 feature UI 变更时,还应阅读 review-mode.md。
  • 修改 UI behavior 时,还应阅读 ui-testing.md。
  • state-reads-and-stability.md——read 深度、deferred reads、derived state、stable UiModels 以及 report 的盲区。
  • ux-states.md——skeleton 与 keep-content、spinner、validation、disabled 与 hidden。
  • lists.md——keys、contentType、item-scope 工作、grids、nesting、paging 接入。
  • motion.md——animation API 选择、graphicsLayer、gestures。
  • shared-elements.md——shared-element 选择、keys、modifier 顺序、overlay。
  • accessibility.md——semantics、touch targets、contrast、actions、RTL。
  • design-system.md——tokens、component placement、复用清单、sheets/dialogs/snackbar chrome。
  • resources.md——CMP
    Res
    与 Android
    R
    、qualifiers、locale parity、imports、maps。
  • resources-media.md——icons、fonts、raw files 和 remote content。
  • images.md——Coil 3 配置与 API 选择、placeholders、caching、CMP placement。
  • keyboard-and-focus.md——到达时的 focus、IME actions、dismiss rules。
  • modifiers.md——modifier 顺序、自定义
    Modifier.Node
    、lambda(deferred-read)modifiers。
  • adaptive-layouts.md——按 destination 适配、size class 而非 device、layout variants 与命名、pane 宽度、scene-strategy panes。
  • edge-to-edge-and-insets.md——edge-to-edge、insets 仅应用一次、keyboard 与 IME。
  • performance-diagnostics.md——diagnose、fix、verify 循环:compiler reports、tracing、baseline profiles、R8、release-mode 真实性。