skills/fp-skills/skills/fp-immutability/SKILL.md
Never mutate data — create new values instead. Covers immutable update patterns (spread, copy, freeze), nested updates without mutation, readonly enforcement, and performance trade-offs. Activate when: updating objects or arrays, working with state management (React, Redux), fixing bugs caused by unintended mutation, deeply nested data updates, or when the user mentions immutability, spread, readonly, frozen, copy-on-write, or structural sharing. Works in any language (TypeScript, Python, Go, Rust, Java).
npx skillsauth add olion500/skills fp-immutabilityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Never mutate. Always create new values. Eliminates shared state corruption, action-at-a-distance, and order-dependent bugs.
| Mutable (avoid) | Immutable (prefer) | Note |
|---|---|---|
| obj.x = y | { ...obj, x: y } | Shallow O(n) copy |
| arr.push(x) | [...arr, x] | Creates new array |
| arr.splice(i,1) | arr.filter((_,idx) => idx !== i) | Or arr.toSpliced(i,1) (ES2023) |
| arr.sort() | arr.toSorted() | ES2023; or [...arr].sort() |
| arr[i] = x | arr.with(i, x) | ES2023; or .map() |
| map.set(k,v) | new Map([...map, [k,v]]) | Clone first |
| dict[k] = v (Python) | {**dict, k: v} | Creates new dict |
Language-specific: Python @dataclass(frozen=True) + replace(). Go: value types are copied by default. Rust: immutable by default, mut opts in. Java: record types.
Deeply nested immutable updates are the #1 pain point. Three approaches:
const updated = {
...state,
user: { ...state.user, address: { ...state.user.address, city: "Seoul" } },
};
const setCity = (state: State, city: string): State => ({
...state,
user: { ...state.user, address: { ...state.user.address, city } },
});
import { produce } from "immer";
const updated = produce(state, draft => { draft.user.address.city = "Seoul"; });
Decision: 1-2 levels → manual spread. 3+ levels or many fields → Immer or helper functions.
// TypeScript: type-level enforcement
type Config = Readonly<{ api: string; scores: readonly number[] }>;
type DeepReadonly<T> = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K] };
const config = { api: "https://..." } as const;
Python: @dataclass(frozen=True). Java: record. Rust: default behavior.
| Operation | Cost | When it matters |
|---|---|---|
| { ...obj } shallow | O(keys) — fast for <100 keys | Almost never a bottleneck |
| [...arr] shallow | O(n) — fine for <10K items | Large arrays in tight loops |
| structuredClone deep | ~10x slower than spread | Avoid in hot paths |
| Immer produce | ~2-5x slower than manual spread | Fine for state management, not hot loops |
Rule of thumb: Immutability is free until profiling proves otherwise. Don't optimize prematurely.
Object.freeze() as a safety mechanism — it's shallow, has runtime cost, and silently fails in non-strict mode{ ...obj } only copies one level. Nested objects are still shared referencesstructuredClone for simple shallow copies — it's overkill and slowdevelopment
Search and query Elasticsearch/Kibana database models using curl API. Use for querying database models, searching Kibana indices, checking Elasticsearch data, investigating data in Kibana, finding records by ID, searching documents. Supports multiple environments (dev, qa, stage, production-us, production-au, production-eu).
development
Search and analyze Datadog logs and metrics using API for cupixworks-api and cupixworks-worker services. Use when debugging errors, investigating issues, searching logs, analyzing worker jobs, checking Sidekiq logs, querying metrics, or finding specific log entries by class/function names. Supports error/warn/info log levels with 14-day retention for logs.
tools
Create, update, search, transition, link, and read comments on Jira issues via CLI. MUST use this skill whenever the user pastes or mentions any atlassian.net URL (Jira issues, Confluence pages, focusedCommentId links, board links — anything from *.atlassian.net). Also use for: TSLA-* ticket references, JQL searches, issue status changes, reading comments, creating bugs, updating descriptions. This is the ONLY way to interact with Jira/Atlassian — there is no MCP Atlassian available.
development
Search Cupix Watch (Kibana/Elasticsearch) application logs at watch.cupix.com. Use when the user asks to search logs, find errors, debug processing issues, or investigate service behavior. Triggers on keywords like "log", "watch", "kibana", "error log", service names (skat, pano, api, worker, vista), or mentions of cupix processing pipelines.