diff --git a/.agents/skills/frontend-code-review/references/component-architecture.md b/.agents/skills/frontend-code-review/references/component-architecture.md index 752450f406e..3e49d368792 100644 --- a/.agents/skills/frontend-code-review/references/component-architecture.md +++ b/.agents/skills/frontend-code-review/references/component-architecture.md @@ -15,14 +15,13 @@ For a file-focused component review, use the named component as the root. For a 1. Build the locally owned rendered component tree from each root to every leaf. Follow imported feature components, conditional branches, lists, portals, dialogs, drawers, and popovers. Stop at third-party or Dify UI primitives and explicit stable public feature boundaries, but record the props passed across that final edge. 2. At every component, inventory state sources: React state/reducers, form state, URL state, context/store/Jotai reads and writes, queries, mutations, refs that hold workflow state, and custom-hook results. -3. For every state value, derived fact, and handler, identify all descendant branches that consume it. If only one branch consumes it, verify that it is declared in the lowest owner in that branch. If several siblings consume it, verify that the parent genuinely derives or coordinates one shared snapshot or lifecycle. +3. For every state value, derived fact, and handler, record its consuming branches and required lifetime, including persistence across descendant unmounts. Assess its placement against [Ownership] and [State], including their coordination and persistence exceptions. 4. Inspect every props edge. Mark values that are read by the child, forwarded unchanged, renamed, recomputed, mirrored into local state, or paired with lifecycle fields such as `data/pending/error/retry` and `open/onOpenChange`. -5. Treat a parent as a switchboard when it mainly destructures a workflow hook and redistributes fields without rendering or coordinating them. Flag moving single-branch state down; when sibling surfaces share the workflow, flag exposing focused feature facts and commands instead of routing the internal state machine through the parent. +5. Trace what each forwarding parent actually owns before reporting an unnecessary intermediary. Apply [Ownership] to distinguish required coordination or persistence from merely redistributing workflow fields, and [State] to determine whether a feature graph is warranted. 6. Remove unused or redundant props at their source. Do not accept replacing many props with a props bag, context, or hook result unless that abstraction becomes the real owner and gives consumers a narrower contract. Review the complete paths before concluding that a state or prop is necessary. When several edges share one ownership defect, report one finding at the highest incorrect owner and include a representative path such as `Root -> Section -> Leaf`; do not emit a duplicate finding for every child. - ## Apply Rules In Their Actual Scope Explicit team conventions are reviewable contracts, including module organization and public API boundaries. Check the documented exception before reporting a violation. Do not infer an exception solely because the code appears to work, or invent a user-facing failure for a convention finding. diff --git a/.agents/skills/how-to-write-component/SKILL.md b/.agents/skills/how-to-write-component/SKILL.md index 3526e8ca426..0c49899dad2 100644 --- a/.agents/skills/how-to-write-component/SKILL.md +++ b/.agents/skills/how-to-write-component/SKILL.md @@ -24,19 +24,6 @@ Choose the mode from the user's requested outcome: - **Implementation:** Establish the affected owner map, state graph, props edges, and reset boundaries before editing. Implement one coherent vertical slice at a time, then run the final audit in [`references/audit.md`][audit]. Read [`references/ownership.md`][ownership]. - **Bug or regression review:** Use the frontend code-review workflow unless the user explicitly requests this skill's architecture model as an additional lens. -## First Decisions - -| Question | Default | Choose differently when | -| --- | --- | --- | -| Where should code live? | In the product workflow, route, or feature owner. | Several verticals need the same stable contract. | -| Who owns state and handlers? | The lowest owner whose consumers and lifetime match the state. | Another owner coordinates it or it must survive the local owner's unmount. | -| Should React control a value? | Leave submit-only DOM fields uncontrolled. | The workflow needs the current value for rendering or coordination. | -| Should state enter Jotai? | Keep owner-local state local. Use feature-local Jotai after a value enters the feature state graph. | An existing stable graph/store already owns the contract. | -| Who owns URL state? | Next.js route APIs and `nuqs`. | Atoms need one route-identity bridge for shared queries or derivations. URL writes still stay with the URL owner. | -| Who owns remote state? | TanStack Query at the lowest complete consumer. | Atom state drives shared work, another graph node consumes the result, or a workflow command coordinates it. | -| Is a wrapper needed? | Use the primitive or direct code. | The wrapper owns behavior, validation, state, semantics, or necessary integration. | -| Is an Effect needed? | Derive during render or handle the user action. | A named external system must be synchronized. | - ## Topic Routing After selecting the operating mode, read only the topic references required by the change: diff --git a/.agents/skills/how-to-write-component/references/interactions.md b/.agents/skills/how-to-write-component/references/interactions.md index 822e4f44614..c3e635e1e05 100644 --- a/.agents/skills/how-to-write-component/references/interactions.md +++ b/.agents/skills/how-to-write-component/references/interactions.md @@ -25,9 +25,6 @@ Read this document when a change involves application hotkeys, focus, dialogs, m - Separate behavior ownership from placement ownership: the action may own trigger, open state, and menu content while the caller owns slots, offsets, and alignment. - Keep menu and dialog surfaces as siblings when a menu command opens a dialog. Mount the dialog outside popup content. - Treat an action surface as a state boundary when its input feeds several sibling menus, dialogs, default values, confirmation messages, or mutation parameters. Inject the smallest stable identity or snapshot once; keep the form draft local unless other owners must react to it. -- Keep overlay open-state ownership separate from content-session ownership. A controlled root does not require controlled fields or root-owned drafts. -- Match transient state to the primitive's content mount lifecycle. State below an unmounting content boundary gets a fresh instance after unmount; intentionally kept-mounted content needs an explicit persistence or reset policy. -- Keep a controlled overlay root at its coordination owner so the primitive can complete exit transitions, focus restoration, and detached-handle behavior. Do not conditionally remove the root to reset content state, and use keys only for stable semantic identity. - Use the [overlay contract] to determine content lifetime and preserve the Root's closing lifecycle. Follow [state ownership] for draft placement and semantic identity; portal placement alone does not locate the state owner. - Place query subscriptions and mutation observers at the owner whose lifetime matches when they should run. Mounted-session work may belong inside content; work that must start or stop exactly with `open` needs an explicit open-state condition. - Prefer primitive-owned open state unless another owner must observe or coordinate it. Analytics callbacks and local cleanup alone do not require a controlled root.