@ericrisco/rsc 0.1.50 → 0.1.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/manifest.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.50",
2
+ "version": "0.1.52",
3
3
  "counts": {
4
4
  "skills": 258
5
5
  },
@@ -1802,7 +1802,7 @@
1802
1802
  },
1803
1803
  {
1804
1804
  "id": "forecasting",
1805
- "description": "Use when you need to project sales, demand, units, revenue, signups or traffic forward from historical data and report a defensible number with an error band. Triggers: 'forecast next quarter's sales', 'how many units of SKU X next month', 'project revenue 12 months with a confidence band', 'is our forecast actually better than just repeating last quarter', lumpy/intermittent demand with lots of zero-sales weeks, 'prevé las ventas del próximo trimestre', 'prediu la demanda del proper mes per producte'. NOT building an assumption-driven P&L (that is financial-model), NOT sizing reorder points or safety stock (that is inventory).",
1805
+ "description": "Use when projecting history forward — sales, demand, units, revenue, signups, traffic — into a defensible number with an error band: method by data shape, rolling-origin backtest, MASE vs the naive baseline. NOT an assumption-driven P&L or runway model (that is `financial-model`), NOT sizing reorder points or safety stock (that is `inventory`).",
1806
1806
  "tags": [
1807
1807
  "forecasting",
1808
1808
  "demand-planning",
@@ -1869,7 +1869,7 @@
1869
1869
  },
1870
1870
  {
1871
1871
  "id": "game-storytelling",
1872
- "description": "Use when designing a game's STORY as an interactive system: premise, theme and narrative pillars; branching narrative and meaningful choice; dialogue trees with state and flags; quests, objectives and fail states; worldbuilding; environmental and systemic storytelling; and keeping story in harmony with play (avoiding ludonarrative dissonance). Engine-agnostic — it designs the narrative graph, variables and beats, then hands the wiring to the engine skill. Triggers: 'write my game's story/premise', 'branching narrative', 'dialogue system/tree', 'quest structure', 'worldbuilding', 'meaningful choices', 'illusion of choice', 'Ink/Yarn Spinner/Twine/articy narrative', 'story keeps fighting the gameplay'. NOT core mechanics, systems or balance (that's game-design); NOT spatial/level layout or encounter placement (that's level-design); NOT the actual dialogue-node code, save format or plugin wiring inside an engine (that's godot/unity/unreal).",
1872
+ "description": "Use when a game's story is the work: premise and pillars, branching topology, meaningful choice, dialogue state, quests, environmental storytelling, ludonarrative harmony. Author portable — engine wiring is `godot`/`unity`/`unreal`. NOT the mechanics and economy the story serves (that is `game-design`), NOT level layout (that is `level-design`).",
1873
1873
  "tags": [
1874
1874
  "game",
1875
1875
  "narrative",
@@ -1889,7 +1889,7 @@
1889
1889
  },
1890
1890
  {
1891
1891
  "id": "gamedev-multiplayer",
1892
- "description": "Use when adding multiplayer, netcode, or replication to a game — syncing players/state across a network, online co-op or PvP, client-server vs peer-to-peer, server-authoritative design, client-side prediction + server reconciliation, snapshot interpolation, lag compensation, tick/netrate, and per-engine wiring: Godot 4.x MultiplayerSpawner/MultiplayerSynchronizer/@rpc/ENetMultiplayerPeer/set_multiplayer_authority, Unity Netcode for GameObjects (NetworkObject/NetworkBehaviour/NetworkVariable/[Rpc]/ServerRpc/ClientRpc), Unreal Actor replication (Replicated/ReplicatedUsing, Server/Client/NetMulticast RPCs, relevancy). Triggers: 'how do I sync players', 'client and server desync', 'players rubber-band or teleport', 'who has authority', 'laggy movement', 'cheater set their own health'. NOT single-player gameplay, AI, or input (route to engine skill godot/unity/unreal), and NOT matchmaking, dedicated-server hosting, or backend infra (route to deployment).",
1892
+ "description": "Use when adding multiplayer or netcode to a game — client-server vs P2P, server authority and anti-cheat, state replication vs RPCs, prediction and reconciliation, lag compensation, plus Godot 4 / Unity NGO / Unreal wiring. NOT single-player gameplay (that is `godot`, `unity`, `unreal`), NOT matchmaking or server hosting (that is `deployment`).",
1893
1893
  "tags": [
1894
1894
  "multiplayer",
1895
1895
  "netcode",
@@ -1910,7 +1910,7 @@
1910
1910
  },
1911
1911
  {
1912
1912
  "id": "gamedev-pathing",
1913
- "description": "Use when implementing AI navigation or pathfinding in a game - moving enemies/NPCs/units toward goals, \\\"how do enemies navigate the level\\\", A*/Dijkstra/JPS/HPA* search, choosing grid vs waypoint-graph vs navmesh, baking a navmesh and tuning agent radius/height, off-mesh/nav links, dynamic obstacles and re-baking, steering (seek/flee/arrive/pursue/wander/path-following/flocking), local avoidance (RVO/ORCA, crowds), and flow fields for many agents to one goal. Per-engine: Godot 4.x (NavigationServer2D/3D, NavigationRegion, NavigationAgent, get_next_path_position), Unity (NavMeshAgent + NavMeshObstacle + AI Navigation baking), Unreal (RecastNavMesh + AIController + Behavior Trees/EQS). Triggers: \\\"my enemies get stuck\\\", \\\"units clump together\\\", \\\"navmesh not updating\\\", \\\"agentes se atascan\\\". NOT physics/rigidbody collision response or character-controller tuning (gamedev-physics), and NOT high-level enemy AI behaviour design like aggro/states/difficulty (game-design).",
1913
+ "description": "Use when making NPCs, enemies, or units navigate a level — grid vs waypoint vs navmesh, A*/JPS, navmesh baking and agent radius, off-mesh links, steering, RVO crowd avoidance, and flow fields in Godot 4.x, Unity, Unreal. NOT collision response or character controllers (that is gamedev-physics), NOT aggro or difficulty design (that is game-design).",
1914
1914
  "tags": [
1915
1915
  "pathfinding",
1916
1916
  "navmesh",
@@ -1970,7 +1970,7 @@
1970
1970
  },
1971
1971
  {
1972
1972
  "id": "gamedev-shipping",
1973
- "description": "Use when exporting, building, packaging, or publishing a game — per engine (Godot export templates, Unity Build Profiles, Unreal Shipping vs Development) and per platform: desktop (Windows/macOS/Linux; macOS codesign + notarytool notarization), web (the COOP same-origin + COEP require-corp headers threaded SharedArrayBuffer WebAssembly builds need, and that Godot's C#/.NET edition can't export to web), mobile (Android JDK 17 build template, AAB vs APK, release keystore; iOS provisioning). Also store prep (icons/splash, metadata, age ratings, AAB for Play, Mac App Store, Steamworks/SteamPipe, itch.io butler), headless-export CI/CD, build/version numbers, and ship-time size/startup optimization. Triggers: 'export my game', 'build for Steam', 'ship to web/mobile', 'publish to the Play Store', 'notarize my Mac build', 'itch.io upload', 'SharedArrayBuffer is not defined'. NOT for writing gameplay/runtime code (that's the engine skill — godot/unity/unreal) or hosting a normal web app/API/container (→ deployment).",
1973
+ "description": "Use when exporting, packaging, signing, or publishing a game — export presets per engine, macOS notarization, cross-origin isolation for threaded web builds, Android AAB/keystore, iOS provisioning, store submission (Steam, Play, App Store, itch.io), headless build CI. NOT gameplay code inside the artifact (that is `godot`, `unity`, `unreal`), NOT hosting a web app or container (that is `deployment`).",
1974
1974
  "tags": [
1975
1975
  "export",
1976
1976
  "build",
@@ -2103,7 +2103,7 @@
2103
2103
  },
2104
2104
  {
2105
2105
  "id": "godot",
2106
- "description": "Use when writing, reviewing, or debugging Godot 4.x games in GDScript (typed) or C# — nodes/scenes/custom Resources, autoload singletons and an EventBus, signals via Callable, @onready/@export/@tool, static typing, CharacterBody2D/3D + velocity + move_and_slide(), _process vs _physics_process, .tscn/.tres text formats, and headless GUT/gdUnit4 tests. Enforces Godot 4 APIs and rejects Godot 3 leftovers: yield→await, onready→@onready, .instance()→.instantiate(), KinematicBody→CharacterBody, Spatial→Node3D, string connect(\\\"sig\\\",obj,\\\"m\\\")→Callable. Triggers: 'write a Godot player controller', 'my move_and_slide does nothing', 'port this Godot 3 script to 4', 'connect a signal in Godot', 'GDScript won't type-check', 'CharacterBody2D won't move', 'add an autoload', 'escribe un script de Godot', 'por qué no se mueve mi personaje'. NOT Unity MonoBehaviour or Unreal (route to unity/unreal); NOT pure C++/CMake tooling unrelated to GDExtension (that is cpp); NOT shader code in .gdshader (that is gamedev-shaders).",
2106
+ "description": "Use when writing, reviewing, or debugging Godot 4.x games in GDScript or C# — scenes, nodes, custom Resources, autoload/EventBus signals, typed GDScript, CharacterBody2D/3D movement, GUT/gdUnit4 — or porting Godot 3 APIs to 4. NOT Unity/Unreal (that is `unity`/`unreal`), NOT `.gdshader` code (`gamedev-shaders`), NOT GDExtension C++ tooling (`cpp`).",
2107
2107
  "tags": [
2108
2108
  "godot",
2109
2109
  "gdscript",
@@ -2150,7 +2150,7 @@
2150
2150
  },
2151
2151
  {
2152
2152
  "id": "grants",
2153
- "description": "Use when the goal is non-dilutive public or foundation funding — money you neither repay nor give equity for — and you must find a fit call, decide go/no-go, register an eligible entity, or write the application a reviewer scores against a published rubric (needs statement, logic model, SMART objectives, impact narrative, budget justification, LOI). Symptoms: a call with an Excellence/Impact/Implementation grid, a 3/5-per-criterion threshold, an indirect-cost line, a SAM.gov/UEI or BDNS lookup, an LOI that filters you before the full proposal. Triggers: 'find grants we qualify for', 'write the impact section so it scores above threshold', 'should we even bother applying to this call', 'build the budget justification', 'write a Letter of Inquiry', 'buscar la convocatòria a la BDNS', 'redactar la solicitud de subvención'. NOT equity rounds or investor pitches (that is fundraising), NOT a paying-customer SOW (that is proposals).",
2153
+ "description": "Use when pursuing non-dilutive public or foundation funding — money you neither repay nor give equity for: finding a fit call, go/no-go, registration (UEI/PIC/BDNS), or writing the rubric-scored application, logic model, budget justification, or LOI. NOT an equity round (that is `fundraising`), NOT a paying-customer SOW (that is `proposals`).",
2154
2154
  "tags": [
2155
2155
  "grants",
2156
2156
  "subsidies",
@@ -2170,7 +2170,7 @@
2170
2170
  },
2171
2171
  {
2172
2172
  "id": "harness",
2173
- "description": "Use to control, govern or maintain a workspace's harness — software or non-code (a company, an ops desk, a knowledge vault). The harness is the control plane: the `01-TOOLS/` tooling layer, the `02-DOCS/` chaos→knowledge wiki, and the root Knowledge map. It audits, migrates legacy `XX-*` folders, scaffolds provider tooling, sweeps the inbox, and generates root CLAUDE.md/AGENTS.md. Brownfield-first. NOT the bootstrap front door (that is `init`, which hands off here).",
2173
+ "description": "Use when governing a workspace's control plane, code or not — the `01-TOOLS/` tooling layer, the `02-DOCS/` chaos→knowledge wiki, the root Knowledge map. Audits it, migrates legacy `XX-*` folders, scaffolds provider tooling, sweeps the inbox, writes root CLAUDE.md/AGENTS.md. NOT the bootstrap front door (that is `init`, which hands off here).",
2174
2174
  "tags": [
2175
2175
  "harness",
2176
2176
  "company",
@@ -2214,7 +2214,7 @@
2214
2214
  },
2215
2215
  {
2216
2216
  "id": "hiring",
2217
- "description": "Use when there's an open role and you need to write the job post, screen inbound candidates, structure the interview loop, or build a scorecard to reach a fair hire decision; symptoms: gut-feel ratings, every interviewer asking the same question, a bloated requirements list, no consistent screen. Triggers: 'write a job description', 'screen these CVs', 'build an interview scorecard', 'structure the interview panel', 'redacta la oferta de empleo', 'necesito una scorecard', plus the non-obvious 'four people interviewed and we still can't decide' and 'is our AI résumé filter legal'. NOT managing the person after they're hired — onboarding, payroll, performance (that is people-ops).",
2217
+ "description": "Use when a role is open and you must write the job post, screen inbound candidates, structure the interview loop, or score them to a defensible Hire / On-Hold / No-Hire — including whether an AI résumé filter is legal. NOT after the offer is accepted — onboarding, payroll, performance (that is `people-ops`), NOT offer terms (that is `contracts`).",
2218
2218
  "tags": [
2219
2219
  "hiring",
2220
2220
  "recruiting",
@@ -2315,7 +2315,7 @@
2315
2315
  },
2316
2316
  {
2317
2317
  "id": "instagram-api",
2318
- "description": "Use when wiring an agent into Instagram's Graph API to publish a Reel from a video URL, pull per-media insights (reach, views, watch-time, saves, shares, total_interactions), check the 24-hour publish cap, or ingest Reel performance into 02-DOCS/wiki/shortform. Triggers: 'publish this Reel via the API', 'pull reach and average watch time for these media IDs', 'why does /insights?metric=plays return an error', 'my container is stuck IN_PROGRESS', 'how many posts left in the 24h publish window', 'publica este Reel por la API', 'ingesta el rendimiento dels Reels al wiki'. NOT TikTok publishing (that is tiktok-api), NOT a posting calendar/cadence (that is social-publisher), NOT YouTube uploads/stats (that is youtube-api).",
2318
+ "description": "Use when wiring an agent into Instagram's Graph API: publishing a Reel through the create/poll/publish container dance, reading per-media insights, checking the 24h publish cap, or ingesting Reel metrics into 02-DOCS/wiki/shortform. NOT TikTok (that is `tiktok-api`), NOT YouTube (that is `youtube-api`), NOT cross-platform cadence (that is `social-publisher`).",
2319
2319
  "tags": [
2320
2320
  "instagram",
2321
2321
  "graph-api",
@@ -2740,7 +2740,7 @@
2740
2740
  },
2741
2741
  {
2742
2742
  "id": "machine-learning",
2743
- "description": "Use when the task is a classic/tabular machine-learning problem — predict a column from rows of features with trees and scikit-learn: fit a RandomForest / XGBoost / LightGBM classifier or regressor, build a leak-proof Pipeline + ColumnTransformer, choose a cross-validation scheme (stratified / k-fold / time-series / grouped), pick the right metric on imbalanced classes (precision/recall/F1/ROC-AUC/PR-AUC, not accuracy), or debug a model that aced CV then collapsed in production. Triggers: 'train a model to predict churn/fraud/price', 'my ROC-AUC is 0.99 — is that leakage', 'which metric for imbalanced classes', 'cross-validation without leaking', 'XGBoost vs LightGBM', 'add a DummyClassifier baseline', 'entrena un modelo de clasificación tabular con scikit-learn'. NOT neural-net / PyTorch training (that is deep-learning), NOT cleaning the raw dirty table first (that is data-cleaning), NOT BI dashboards or forecasting a dated series (that is analytics/forecasting), NOT text/token modeling (that is nlp).",
2743
+ "description": "Use when predicting a column from rows of tabular features with classic models — scikit-learn pipelines, RandomForest, XGBoost/LightGBM, leak-free cross-validation, metrics for imbalanced classes, or a model that aced CV then collapsed in production. NOT PyTorch neural nets (that is `deep-learning`), NOT cleaning the dirty table first (that is `data-cleaning`), NOT forecasting a dated series (that is `forecasting`), NOT text/token modeling (that is `nlp`).",
2744
2744
  "tags": [
2745
2745
  "machine-learning",
2746
2746
  "scikit-learn",
@@ -3196,7 +3196,7 @@
3196
3196
  },
3197
3197
  {
3198
3198
  "id": "observability",
3199
- "description": "Use when instrumenting a service from the inside so an incident can be explained from telemetry alone — wiring OpenTelemetry logs, metrics and traces, standing up a Collector, exporting via OTLP, and defining telemetry-driven alerts. Triggers: 'add OpenTelemetry to this service', 'we can't tell why requests are slow across services — add distributed tracing', 'replace our print/console.log with structured logs correlated to traces', 'stand up an OTel Collector and export to Grafana/Datadog/Honeycomb', 'instrument our LLM calls so each request is a span with token counts', 'define RED metrics and a burn-rate alert from the telemetry', 'instrumenta el servei amb OpenTelemetry i exporta a Grafana', 'añade trazas distribuidas y métricas'. NOT outside-in uptime probes, on-call rotation, or who-gets-paged (that is monitoring).",
3199
+ "description": "Use when instrumenting a service from the inside so an incident can be explained from telemetry alone — wiring OpenTelemetry logs, metrics and traces, standing up a Collector, exporting via OTLP, and defining telemetry-driven alerts. NOT outside-in uptime probes, on-call rotation, or who-gets-paged (that is `monitoring`).",
3200
3200
  "tags": [
3201
3201
  "observability",
3202
3202
  "opentelemetry",
@@ -3662,7 +3662,7 @@
3662
3662
  },
3663
3663
  {
3664
3664
  "id": "rag",
3665
- "description": "Use when building grounded Q&A over your own documents — handbook, support tickets, PDFs, policies — and the answers must come only from the corpus with citations; when retrieval surfaces the right document but the answer is still wrong; when the model invents facts that are not in the sources; when you need to measure whether retrieval is any good; when the right document is found but the wrong passage is used. Triggers: 'build a bot that answers from our docs with citations', 'my RAG returns the right document but the answer is wrong', 'how do I stop the model hallucinating facts not in the corpus', 'context recall vs context precision', 'add contextual retrieval / prepend chunk context before embedding', 'hybrid search plus rerank pipeline', 'respuestas con citas sobre nuestros documentos', 'el bot s'inventa coses que no surten als documents'. NOT operating the vector store itself — collection schema, HNSW ef_search, quantization (that is vector-db).",
3665
+ "description": "Use when building grounded Q&A over your own corpus — chunk, retrieve hybrid, rerank, ground, cite chunk ids, refuse when the sources fall short — or when the right document is retrieved but the answer is still wrong, invented, or unmeasured. NOT operating the store itself — collection schema, HNSW ef_search, quantization (that is `vector-db`).",
3666
3666
  "tags": [
3667
3667
  "rag",
3668
3668
  "retrieval-augmented-generation",
@@ -4175,7 +4175,7 @@
4175
4175
  },
4176
4176
  {
4177
4177
  "id": "security-scan",
4178
- "description": "Use when running automated security scanners over a repo or app and turning the raw output into a triaged, ranked, gate-able report: scan for vulnerabilities before shipping, audit dependencies/lockfiles for known CVEs, find secrets committed to the tree or git history, run SAST, or wire scanners into CI. Triggers: 'scan this repo for vulnerabilities', 'check my package-lock for CVEs', 'did anyone commit AWS keys', 'scan git history for leaked keys', 'my lockfile has a transitive CVE', 'is aquasecurity/trivy-action@latest safe', 'set up Semgrep/gitleaks to fail CI', 'escanea el repo en busca de vulnerabilidades', 'audita las dependencias', 'analitza les dependències'. NOT threat-modeling, OWASP design reasoning, or authoring the fix (that is secure-coding).",
4178
+ "description": "Use when automated scanners drive a security sweep of a repo or app — SAST, dependency/lockfile CVEs, secrets in the tree or git history, IaC misconfig — and the raw output has to become one deduped, exploitability-ranked report CI can gate on. NOT threat-modeling, OWASP design reasoning, or hand-authoring the fix (that is `secure-coding`).",
4179
4179
  "tags": [
4180
4180
  "security",
4181
4181
  "sast",
@@ -4664,7 +4664,7 @@
4664
4664
  },
4665
4665
  {
4666
4666
  "id": "tauri",
4667
- "description": "Use when building a lightweight cross-platform desktop (or v2 mobile) app with Tauri — a Rust core plus the OS-native WebView — wiring Rust commands and IPC, streaming data to the frontend, locking down the capabilities/permissions security model, or bundling and auto-updating tiny signed binaries. Triggers: 'build a Tauri app', 'expose a Rust command to my frontend', 'invoke from JS', 'tauri.conf.json', 'capabilities and permissions', 'stream download progress to the WebView', 'my command froze the UI', 'shrink my desktop binary vs Electron', 'set up the Tauri updater', 'crear una app d'escriptori lleugera amb Rust en lloc d'Electron', 'reducir el tamaño del binario de escritorio'. NOT a Chromium+Node desktop app that needs Node APIs in a main process (that is electron).",
4667
+ "description": "Use when building a lightweight cross-platform desktop (or v2 mobile) app with Tauri — a Rust core plus the OS-native WebView: Rust commands and IPC, streaming to the frontend, the default-deny capabilities/permissions ACL, bundling and signed auto-updates. NOT a Chromium+Node shell needing Node APIs in a main process (that is electron).",
4668
4668
  "tags": [
4669
4669
  "tauri",
4670
4670
  "desktop",
@@ -5140,7 +5140,7 @@
5140
5140
  },
5141
5141
  {
5142
5142
  "id": "webhooks",
5143
- "description": "Use when building the inbound side of a webhook — the HTTP endpoint that receives events a system pushes you, proves they are authentic, refuses to process the same one twice, and acks fast. Covers the mechanics every source shares: raw-body HMAC verification, ~5-min timestamp/replay window, idempotency on a stable event id, fast-ack-then-queue, retry/poison handling. Triggers: 'receive webhooks and process them safely', 'verify an incoming webhook signature', 'my signature verification fails even though the secret is correct', 'provider keeps retrying and we process the same event twice', 'handler times out under load, ack fast and queue', 'recibir webhooks entrantes', 'verificar la firma del webhook entrante', 'evitar procesar el mismo evento dos veces'. NOT the Stripe-Signature scheme (that is stripe), NOT email bounce/suppression hooks (that is email-connector), NOT outbound clients calling a third-party API (that is api-connector-builder), NOT what runs after the event lands (that is automation-flows).",
5143
+ "description": "Use when building the receiving end of a webhook — a provider-agnostic endpoint that proves pushed events are authentic and never processes one twice: raw-body HMAC, ~5-min replay window, idempotency on the event id, fast-ack-then-queue. NOT the Stripe-Signature scheme (that is stripe), NOT outbound clients you call (that is api-connector-builder).",
5144
5144
  "tags": [
5145
5145
  "webhooks",
5146
5146
  "inbound-webhooks",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ericrisco/rsc",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "description": "Eric Risco's agent-skills catalog as a granular, self-recommending CLI installer.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: forecasting
3
- description: "Use when you need to project sales, demand, units, revenue, signups or traffic forward from historical data and report a defensible number with an error band. Triggers: 'forecast next quarter's sales', 'how many units of SKU X next month', 'project revenue 12 months with a confidence band', 'is our forecast actually better than just repeating last quarter', lumpy/intermittent demand with lots of zero-sales weeks, 'prevé las ventas del próximo trimestre', 'prediu la demanda del proper mes per producte'. NOT building an assumption-driven P&L (that is financial-model), NOT sizing reorder points or safety stock (that is inventory)."
3
+ description: "Use when projecting history forward — sales, demand, units, revenue, signups, traffic — into a defensible number with an error band: method by data shape, rolling-origin backtest, MASE vs the naive baseline. NOT an assumption-driven P&L or runway model (that is `financial-model`), NOT sizing reorder points or safety stock (that is `inventory`)."
4
4
  tags: [forecasting, demand-planning, time-series, sales-forecast, statsforecast]
5
5
  recommends: [inventory, financial-model, unit-economics, data-cleaning, analyze, duckdb]
6
6
  origin: risco
@@ -51,13 +51,13 @@ When in doubt between two, fit both plus the baseline in one `StatsForecast` run
51
51
 
52
52
  The metrics are not decoration — they decide what you ship.
53
53
 
54
- - **WAPE, not MAPE.** MAPE divides by the actual, so it explodes and misleads whenever actuals approach zero (constant in SKU and intermittent data). WAPE = total absolute error / total actual volume — it weights error by volume and stays stable. Use WAPE as the default magnitude metric.
55
- - **Pair WAPE with bias.** WAPE tells you *how big* the error is; bias tells you the *direction* — whether you systematically over- or under-forecast. A 10% WAPE with +9% bias means you are almost always forecasting high; that is an actionable, different problem than random error.
56
- - **MASE < 1.0 is the pass/fail line.** MASE is scale-free and compares your error to the naive forecast's error. < 1.0 = you beat naive (good). ≥ 1.0 = the naive forecast was better — ship the naive one and stop pretending. This is the single most important number in the readout.
57
- - **Rolling-origin, never a single holdout.** Time-series CV repeats the train/test split across multiple cutoffs (expanding window), giving a far more reliable estimate than one lucky/unlucky split. Use `cross_validation(h=…, n_windows=…)`.
58
- - **Always emit an interval.** A point forecast cannot express uncertainty, and point metrics cannot evaluate a distribution. Report `level=[80]` or `[95]`. The interval is not optional polish — it is half the deliverable.
54
+ - **WAPE, not MAPE.** MAPE divides by the actual, so it explodes and misleads whenever actuals approach zero (constant in SKU and intermittent data). WAPE = total absolute error / total actual volume — volume-weighted and stable. It is the default magnitude metric.
55
+ - **Pair WAPE with bias.** WAPE is *how big* the error is; bias is the *direction* — whether you systematically over- or under-forecast. A 10% WAPE with +9% bias means you are almost always forecasting high, an actionable problem quite different from random error.
56
+ - **MASE < 1.0 is the pass/fail line.** MASE is scale-free: your error over the naive forecast's error. Below 1.0 you beat naive; at or above it, ship the naive forecast instead. The single most important number in the readout.
57
+ - **Rolling-origin, never a single holdout.** Time-series CV repeats the train/test split across multiple cutoffs (expanding window), a far more reliable estimate than one lucky/unlucky split. Use `cross_validation(h=…, n_windows=…)`.
58
+ - **Always emit an interval.** A point forecast cannot express uncertainty, and point metrics cannot evaluate a distribution. Report `level=[80]` or `[95]`. The interval is half the deliverable, not optional polish.
59
59
 
60
- Formulas (WAPE, MASE, bias, pinball, coverage), rolling-origin mechanics, and how to read a backtest table are in `references/accuracy-and-backtesting.md`. Per-method when-to-use and the exact statsforecast one-liner for each are in `references/methods-cheatsheet.md`.
60
+ Formulas (WAPE, MASE, bias, pinball, coverage), rolling-origin mechanics, and how to read a backtest table are in [`references/accuracy-and-backtesting.md`](references/accuracy-and-backtesting.md). Per-method when-to-use and the exact statsforecast one-liner for each are in [`references/methods-cheatsheet.md`](references/methods-cheatsheet.md).
61
61
 
62
62
  ## Minimal pipeline
63
63
 
@@ -116,24 +116,24 @@ out.to_csv("forecast.csv", index=False)
116
116
  - **Structural breaks.** A pricing change, a relaunch, a regime shift. Do not train across the break — train on the post-break segment, even if it is short, or the model averages two different worlds.
117
117
  - **Promotions and outliers.** A promo spike is not baseline demand. Mark promo periods and either model them as a regressor or exclude them from the level estimate; otherwise the forecast inherits a spike that will not recur.
118
118
  - **Granularity.** Forecast at the level you act on. If you must report higher, aggregate the forecasts — and check the aggregate is plausible (this often catches per-SKU nonsense).
119
- - **Hierarchy reconciliation.** When SKU forecasts must sum to a category total, reconcile (bottom-up or MinT). Brief note here; the mechanics belong in `references/methods-cheatsheet.md`.
119
+ - **Hierarchy reconciliation.** When SKU forecasts must sum to a category total, reconcile (bottom-up or MinT). Brief note here; the mechanics belong in [`references/methods-cheatsheet.md`](references/methods-cheatsheet.md).
120
120
 
121
121
  ## Anti-patterns
122
122
 
123
- | Bad | Good | Why |
123
+ | Anti-pattern | Why it bites | Do instead |
124
124
  |---|---|---|
125
- | Report a single point number | Report point + 80/95% interval | A point hides uncertainty the reader needs to plan around. |
126
- | Tune ARIMA orders before any baseline | Compute naive/seasonal-naive first | If you cannot beat the free baseline, the tuning was wasted. |
127
- | Score with MAPE on intermittent demand | Use WAPE + bias | MAPE explodes near zero actuals and lies about accuracy. |
128
- | Single train/test holdout | Rolling-origin CV (`n_windows≥3`) | One split is one sample; CV estimates real out-of-sample error. |
129
- | Fit a model on 8 months of monthly data | SeasonalNaive only under 2 cycles | Too few points; the model overfits and underreports its own error. |
130
- | "The model picked it, so it's right" | State method + MASE vs naive | A forecast you cannot defend is worse than no forecast. |
131
- | Trust SKU forecasts without checking the sum | Sanity-check vs the aggregate | Per-SKU errors compound; the total exposes nonsense fast. |
125
+ | Report a single point number | A point hides uncertainty the reader needs to plan around. | Report point + 80/95% interval |
126
+ | Tune ARIMA orders before any baseline | If you cannot beat the free baseline, the tuning was wasted. | Compute naive/seasonal-naive first |
127
+ | Score with MAPE on intermittent demand | MAPE explodes near zero actuals and lies about accuracy. | Use WAPE + bias |
128
+ | Single train/test holdout | One split is one sample; CV estimates real out-of-sample error. | Rolling-origin CV (`n_windows≥3`) |
129
+ | Fit a model on 8 months of monthly data | Too few points; the model overfits and underreports its own error. | SeasonalNaive only under 2 cycles |
130
+ | "The model picked it, so it's right" | A forecast you cannot defend is worse than no forecast. | State method + MASE vs naive |
131
+ | Trust SKU forecasts without checking the sum | Per-SKU errors compound; the total exposes nonsense fast. | Sanity-check vs the aggregate |
132
132
 
133
133
  ## Handoffs
134
134
 
135
135
  - **`../inventory/SKILL.md`** — feed it the demand number; it sizes reorder points and safety stock. Forecasting produces the demand; it does not size the stock.
136
136
  - **`../financial-model/SKILL.md`** — when the projection is driven by *assumptions and drivers* (pricing, hiring), not history, that is a model, not a forecast.
137
137
  - **`../unit-economics/SKILL.md`** — contribution margin, CAC/LTV, payback. No time series, route there.
138
- - **`data-cleaning`** — dirty input (dupes, missing rows, mixed units) goes here *before* you model.
138
+ - **`../data-cleaning/SKILL.md`** — dirty input (dupes, missing rows, mixed units) goes here *before* you model.
139
139
  - **`../analyze/SKILL.md`** — when the question is "why" or a backward-looking metric/aggregation rather than forward extrapolation.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: game-storytelling
3
- description: "Use when designing a game's STORY as an interactive system: premise, theme and narrative pillars; branching narrative and meaningful choice; dialogue trees with state and flags; quests, objectives and fail states; worldbuilding; environmental and systemic storytelling; and keeping story in harmony with play (avoiding ludonarrative dissonance). Engine-agnostic — it designs the narrative graph, variables and beats, then hands the wiring to the engine skill. Triggers: 'write my game's story/premise', 'branching narrative', 'dialogue system/tree', 'quest structure', 'worldbuilding', 'meaningful choices', 'illusion of choice', 'Ink/Yarn Spinner/Twine/articy narrative', 'story keeps fighting the gameplay'. NOT core mechanics, systems or balance (that's game-design); NOT spatial/level layout or encounter placement (that's level-design); NOT the actual dialogue-node code, save format or plugin wiring inside an engine (that's godot/unity/unreal)."
3
+ description: "Use when a game's story is the work: premise and pillars, branching topology, meaningful choice, dialogue state, quests, environmental storytelling, ludonarrative harmony. Author portable — engine wiring is `godot`/`unity`/`unreal`. NOT the mechanics and economy the story serves (that is `game-design`), NOT level layout (that is `level-design`)."
4
4
  tags: [game, narrative, story, dialogue, quest, branching, worldbuilding]
5
5
  recommends: [game-design, level-design]
6
6
  profiles: [full]
@@ -9,23 +9,11 @@ origin: risco
9
9
 
10
10
  # Game Storytelling — Narrative Design (engine-agnostic)
11
11
 
12
- *Design the story as a system the player operates, not a script they watch. This skill owns the narrative graph — premise, pillars, branches, choices, dialogue state, quests, and the storytelling embedded in the world — and hands the runtime wiring to the engine skill.*
12
+ *Design the story as a system the player operates, not a script they watch. This skill owns the narrative graph — premise, pillars, branches, choices, dialogue state, quests, and the storytelling embedded in the world.*
13
13
 
14
- You produce **design artifacts**: a premise/theme/pillars doc, a branch topology, a state/flag table, dialogue in a portable format (Ink/Yarn/Twee/articy), quest specs, and environmental beats. You do **not** write engine node code, save-serialization, or plugin glue — that is `godot`/`unity`/`unreal`. A mechanic question (what the player *does*, economy, balance) is `game-design`; where things sit in space is `level-design`.
14
+ You produce **design artifacts**: a premise/theme/pillars doc, a branch topology, a state/flag table, dialogue in a portable format (Ink/Yarn/Twee/articy), quest specs, and environmental beats. Story is a **system in service of play**; when you catch yourself designing a great scene the mechanics can't honor, reconcile it (see Ludonarrative harmony) rather than ship the dissonance.
15
15
 
16
- ## Fires on / When NOT
17
-
18
- Use when the request is about: a game's story or premise; branching or non-linear narrative; a dialogue system, tree, or conversation logic; quests, objectives, or mission structure; worldbuilding/lore for a game; meaningful choice vs. the illusion of choice; environmental or systemic storytelling; or story that "fights" the gameplay (ludonarrative dissonance).
19
-
20
- Do NOT use (delegate or decline):
21
-
22
- - Core loop, verbs, systems, progression, economy, difficulty, or balance → **game-design**.
23
- - Spatial layout, encounter placement, sightlines, blockout, pacing *of a space* → **level-design**.
24
- - Implementing the dialogue runner, save/serialize of story state, or wiring Ink/Yarn/articy into a build → the engine skill (**godot/unity/unreal**).
25
- - Prose fiction, a screenplay, or a novel with no interactive/branching structure → general writing.
26
- - Marketing copy, store page, or trailer script → **marketing**.
27
-
28
- Story is a **system in service of play**. When you catch yourself designing a great scene the mechanics can't honor, reconcile it (see Ludonarrative harmony) rather than ship the dissonance.
16
+ Boundaries: **game-design** owns what the player *does* — core loop, verbs, systems, progression, economy, difficulty, balance — and the story serves those verbs; call it when resolving dissonance needs a *mechanic* change, or when designing the conditions for systemic/emergent story. **level-design** owns spatial layout, encounter placement, sightlines, blockout and the pacing *of a space* — the space environmental storytelling lives inside; co-own the set-dressing. **godot / unity / unreal** implement the dialogue runner, quest state, save-serialization of story state, and the Ink/Yarn/articy plugin glue — author portable, they wire it. **marketing** owns the store page, premise pitch and trailer copy (external-facing, not in-game narrative). Prose fiction, a screenplay, or a novel with no interactive/branching structure is general writing, not this skill.
29
17
 
30
18
  ## Premise, theme, and pillars (do this first)
31
19
 
@@ -119,25 +107,18 @@ Deliver story *through the world* so the player assembles it and feels ownership
119
107
  - **VO considerations** *(design-side, not recording — that's audio/engine)* — write for the ear (contractions, short clauses); budget line counts early (VO is expensive and near-frozen once recorded); keep a **stable line ID** on every spoken line; don't splice recorded fragments across variables (gender/number/name concatenation breaks in most languages).
120
108
  - **Localization-readiness** *(so the loc pipeline can do its job)* — externalize all player-facing text to string tables keyed by stable id; **never concatenate** sentences or embed grammar in code (gender/plural/word-order differ per language — use full templated strings with ICU-style placeholders); allow +30–40% text expansion; keep variables as named tokens (`{playerName}`), not positional; leave translator notes per line.
121
109
 
122
- ## Anti-patterns / rationalizations → STOP
110
+ ## Anti-patterns
123
111
 
124
- | Rationalization | Reality / Fix |
112
+ | Anti-pattern | Do instead |
125
113
  | --- | --- |
126
- | "I'll just branch it, players love choices" | Pure trees explode (2^N). Use foldback + gates; reconverge on beats. |
127
- | "This choice feels huge" (but nothing reads it back) | If no later node reads the flag, the choice is noise. Show the consequence or cut it. |
128
- | "Both options lead to the same scene, that's fine" | Only if it's expression, not stakes. Never sell a fake choice as consequential. |
129
- | "The story explains why he's a mass murderer" | Words don't beat verbs. Fix the ludonarrative dissonance, don't narrate around it. |
130
- | "Add an audio log to explain the backstory" | Text-dump is the fallback. Try to *show* it environmentally first. |
131
- | "We'll localize later, just hardcode the strings" | Concatenation and hardcoded text break loc. Externalize to keyed string tables now. |
132
- | "The quest can't be failed, simpler that way" | Sometimes; but soft-locking the game on a missed step is a defect — leave an escape. |
133
- | "Let me wire this Ink file into Unity real quick" | Not this skill. Author portable narrative; hand wiring to the engine skill. |
134
-
135
- ## Related skills
136
-
137
- - **game-design** — the verbs, systems, economy, and balance the story must serve; call it when resolving dissonance needs a *mechanic* change, or when designing systemic/emergent story conditions.
138
- - **level-design** — the spatial layout and encounter flow environmental storytelling lives inside; co-own set-dressing narrative.
139
- - **godot / unity / unreal** — the engine that wires the dialogue runner, quest state, save/serialize, and Ink/Yarn/articy plugins. Author portable; they implement.
140
- - **marketing** — store page, premise pitch, trailer copy (external-facing, not in-game narrative).
114
+ | Branching everything because "players love choices" | Pure trees explode (2^N). Use foldback + gates; reconverge on beats. |
115
+ | A choice that feels huge but no later node reads it back | If no later node reads the flag, the choice is noise. Show the consequence or cut it. |
116
+ | Both options lead to the same scene, and it's sold as a big decision | Fine as expression, not as stakes. Never sell a fake choice as consequential. |
117
+ | Explaining in the story why he's a mass murderer | Words don't beat verbs. Fix the ludonarrative dissonance, don't narrate around it. |
118
+ | Adding an audio log to explain the backstory | Text-dump is the fallback. Try to *show* it environmentally first. |
119
+ | Hardcoding strings, "we'll localize later" | Concatenation and hardcoded text break loc. Externalize to keyed string tables now. |
120
+ | A quest that can't be failed because it's simpler that way | Sometimes right; but soft-locking the game on a missed step is a defect — leave an escape. |
121
+ | Wiring the Ink file into Unity here | Not this skill. Author portable narrative; hand wiring to the engine skill. |
141
122
 
142
123
  ## Checklist
143
124
 
@@ -151,9 +132,3 @@ Deliver story *through the world* so the player assembles it and feels ownership
151
132
  - [ ] Environmental/diegetic delivery preferred over text-dumps and non-diegetic narration where the world can carry it.
152
133
  - [ ] All player-facing text externalized to keyed string tables; no concatenation; variables are named tokens; +30–40% expansion allowed.
153
134
  - [ ] VO lines have stable IDs, are written for the ear, and the script is locked before recording is proposed.
154
-
155
- ## References
156
-
157
- - `references/branching-and-state.md` — topologies + diagrams, meaningful vs. illusory choice, state modeling, and the combinatorial-explosion containment kit.
158
- - `references/dialogue-tools.md` — Ink/Yarn/Twine/articy compared, the four primitives, a "pick one" guide, and the same conversation in three formats.
159
- - `references/environmental-storytelling.md` — show-don't-tell catalog, diegetic vs. non-diegetic delivery, systemic/emergent storytelling and the anecdote factory.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: gamedev-multiplayer
3
- description: "Use when adding multiplayer, netcode, or replication to a game — syncing players/state across a network, online co-op or PvP, client-server vs peer-to-peer, server-authoritative design, client-side prediction + server reconciliation, snapshot interpolation, lag compensation, tick/netrate, and per-engine wiring: Godot 4.x MultiplayerSpawner/MultiplayerSynchronizer/@rpc/ENetMultiplayerPeer/set_multiplayer_authority, Unity Netcode for GameObjects (NetworkObject/NetworkBehaviour/NetworkVariable/[Rpc]/ServerRpc/ClientRpc), Unreal Actor replication (Replicated/ReplicatedUsing, Server/Client/NetMulticast RPCs, relevancy). Triggers: 'how do I sync players', 'client and server desync', 'players rubber-band or teleport', 'who has authority', 'laggy movement', 'cheater set their own health'. NOT single-player gameplay, AI, or input (route to engine skill godot/unity/unreal), and NOT matchmaking, dedicated-server hosting, or backend infra (route to deployment)."
3
+ description: "Use when adding multiplayer or netcode to a game — client-server vs P2P, server authority and anti-cheat, state replication vs RPCs, prediction and reconciliation, lag compensation, plus Godot 4 / Unity NGO / Unreal wiring. NOT single-player gameplay (that is `godot`, `unity`, `unreal`), NOT matchmaking or server hosting (that is `deployment`)."
4
4
  tags: [multiplayer, netcode, replication, networking, prediction, authority]
5
5
  recommends: [godot, unity, unreal, gamedev-physics]
6
6
  profiles: [full]
@@ -14,6 +14,16 @@ topology, put authority in the right place, replicate the right state, and hide
14
14
  opening the door to cheaters. This skill owns the *networking* decisions; the engine skills own
15
15
  the local gameplay those decisions sit on top of.
16
16
 
17
+ Route elsewhere when the ask is not netcode:
18
+
19
+ | The ask | Route to | Why not here |
20
+ | --- | --- | --- |
21
+ | Single-player movement, AI, input, animation, save files | [`godot`](../godot/SKILL.md) / [`unity`](../unity/SKILL.md) / [`unreal`](../unreal/SKILL.md) | The engine skill owns local gameplay; no network dimension. |
22
+ | Physics determinism, collision, character controllers | [`gamedev-physics`](../gamedev-physics/SKILL.md) | Netcode *consumes* determinism; it does not own the physics fix. |
23
+ | Matchmaking, lobby backend, dedicated-server hosting, relays, DB, game-server CI | [`deployment`](../deployment/SKILL.md) | Running the fleet, not designing the in-game net layer. |
24
+ | Web realtime — chat, presence, a generic WebSocket app | [`webhooks`](../webhooks/SKILL.md) | Not a game world/simulation. |
25
+ | General threat modeling, authz review | [`secure-coding`](../secure-coding/SKILL.md) | This skill keeps only the game-specific anti-cheat controls. |
26
+
17
27
  ## Version contract — read first
18
28
 
19
29
  Target the current APIs. **Never emit these deprecated / removed APIs:**
@@ -30,19 +40,6 @@ community UNet-like fork), say so; this skill targets first-party NGO. In NGO 2.
30
40
  `[ServerRpc]` / `[ClientRpc]` still compile (and enforce `…ServerRpc` / `…ClientRpc` method-name
31
41
  suffixes) — cover them but prefer the unified form on new code.
32
42
 
33
- ## Fires on / When NOT
34
-
35
- **Fires on:** "how do I sync players", replication, netcode, RPCs, authority, online co-op or PvP,
36
- "client and server disagree", rubber-banding / teleporting players, prediction & reconciliation,
37
- lag compensation, tick rate / send rate, spawning networked objects, "the client can cheat".
38
-
39
- **When NOT (route away):**
40
-
41
- - Single-player movement, AI, input, animation, save files → the engine skill: `godot`, `unity`, `unreal`.
42
- - Physics determinism, collision, character controllers → `gamedev-physics` (netcode *consumes* it).
43
- - Matchmaking service, lobby backend, dedicated-server hosting/orchestration, relays, DB → `deployment`.
44
- - Web realtime (chat, presence, generic WebSocket app) that is not a game world → `webhooks` / a backend skill.
45
-
46
43
  ## Topologies & authority
47
44
 
48
45
  Pick the topology first; everything else follows from it.
@@ -61,7 +58,8 @@ requests), never results. **Never trust the client:** the client cannot set its
61
58
  score, currency, or hit results — it *asks*, the server *decides*, everyone else *observes*. A client
62
59
  that says "I moved to X / I did 40 damage / I have 999 gold" is either lagging or cheating; treat both
63
60
  the same. The one thing a client legitimately owns is its own input and, by convention, cosmetic-only
64
- state. See references/prediction-and-latency.md for how to keep this responsive.
61
+ state. See **[references/prediction-and-latency.md](references/prediction-and-latency.md)** for how to
62
+ keep this responsive.
65
63
 
66
64
  ## State replication vs RPCs
67
65
 
@@ -88,7 +86,7 @@ is the #1 cause of "it works for the host but not the client" bugs.
88
86
  ## The hard problems
89
87
 
90
88
  Latency (round-trip time, RTT) is the enemy; jitter and packet loss make it worse. Four techniques,
91
- covered in depth in **references/prediction-and-latency.md**:
89
+ covered in depth in **[references/prediction-and-latency.md](references/prediction-and-latency.md)**:
92
90
 
93
91
  1. **Client-side prediction** — the owning client applies its own input *immediately* instead of waiting a
94
92
  full RTT for the server, so local movement feels instant.
@@ -140,7 +138,8 @@ func request_fire(target: Vector3) -> void:
140
138
  - `MultiplayerSynchronizer` streams a chosen property list (position, etc.) from the authority to peers;
141
139
  set its replication interval and visibility (`set_visibility_for(peer, bool)`) to scope bandwidth.
142
140
  - `MultiplayerSpawner` replicates instancing of scenes under a path so late peers get existing objects.
143
- - Details, prediction wiring, and the full player-scene pattern: **references/godot-high-level-multiplayer.md**.
141
+ - Details, prediction wiring, and the full player-scene pattern:
142
+ **[references/godot-high-level-multiplayer.md](references/godot-high-level-multiplayer.md)**.
144
143
 
145
144
  ### Unity — Netcode for GameObjects
146
145
 
@@ -168,7 +167,8 @@ public class Player : NetworkBehaviour {
168
167
  - `NetworkVariable<T>(value, readPerm, writePerm)` — `NetworkVariableWritePermission.Server` (default) vs
169
168
  `.Owner`; subscribe via `OnValueChanged`. Use `NetworkTransform` for pos/rot sync.
170
169
  - Prefer the unified `[Rpc(SendTo.X)]`; legacy `[ServerRpc]`/`[ClientRpc]` still work but need the
171
- method-name suffixes. Full patterns: **references/unity-and-unreal-netcode.md**.
170
+ method-name suffixes. Full patterns:
171
+ **[references/unity-and-unreal-netcode.md](references/unity-and-unreal-netcode.md)**.
172
172
 
173
173
  ### Unreal — Actor replication
174
174
 
@@ -196,7 +196,8 @@ void AMyPawn::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const {
196
196
  - **Relevancy** keeps bandwidth sane: `NetCullDistanceSquared`, `bAlwaysRelevant`, `IsNetRelevantFor`, and
197
197
  dormancy (`SetNetDormancy`) stop replicating actors a client can't perceive. Movement replicates via
198
198
  `CharacterMovementComponent`, which already does prediction+reconciliation for you.
199
- - RepNotify vs Multicast, GAS/Network Prediction notes: **references/unity-and-unreal-netcode.md**.
199
+ - RepNotify vs Multicast, GAS/Network Prediction notes:
200
+ **[references/unity-and-unreal-netcode.md](references/unity-and-unreal-netcode.md)**.
200
201
 
201
202
  ## Security / anti-cheat basics
202
203
 
@@ -219,32 +220,18 @@ void AMyPawn::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const {
219
220
  - Always test **with simulated latency and packet loss**, not just on localhost — localhost hides every
220
221
  prediction/reconciliation bug. Test the client path, not only the host's.
221
222
 
222
- ## Guardrails / gotchas
223
-
224
- - Localhost is a liar: 0 ms RTT masks the exact desync/rubber-band bugs your players will hit. Inject lag.
225
- - Don't RPC state you need to stay consistent — replicate it (an unreliable event drop is permanent).
226
- - Don't tie simulation to render FPS; fixed timestep on the sim, interpolate on the render.
227
- - The listen-server host is a client too — guard authority-only logic behind an `is_server`/`HasAuthority`
228
- check or it double-executes on the host.
229
- - Wrong ownership = "works for host, breaks for client." Set authority/ownership explicitly on spawn.
230
- - Replicating everything, every tick, to everyone melts bandwidth — scope by relevancy/visibility and rate.
231
-
232
- ## Related skills
233
-
234
- - **`godot` / `unity` / `unreal`** — the engine your game runs in; owns local gameplay, input, scenes, build.
235
- - **`gamedev-physics`** — determinism, collision, character controllers; netcode replicates its results and
236
- needs its determinism for prediction/rollback.
237
- - **`deployment`** — dedicated-server hosting, matchmaking/lobby backend, relays, and CI for game servers.
238
- - **`secure-coding`** — general threat modeling; this skill keeps only the game-specific anti-cheat controls.
239
-
240
- ## Checklist
241
-
242
- - [ ] Topology chosen (dedicated / listen / P2P) and the *same code* runs on server and listen host.
243
- - [ ] Server-authoritative: clients send intent only; server validates and owns all gameplay state.
244
- - [ ] Each networked value is either replicated (state/nouns) or an RPC (events/verbs) — not the wrong one.
245
- - [ ] Ownership/authority set explicitly per object; authority-only logic guarded on the host.
246
- - [ ] Owning-client movement predicted + reconciled; remote entities snapshot-interpolated.
247
- - [ ] Hitscan uses server-side lag compensation; simulation on a fixed tick, decoupled from render FPS.
248
- - [ ] Only need-to-know state replicated per client (relevancy/visibility scoped); RPCs rate-limited.
249
- - [ ] Tested with simulated latency + packet loss across multiple instances, exercising the client path.
250
- - [ ] No banned APIs (UNet/HLAPI, Godot 3.x `master`/`puppet`/`rset`, `Tick`-polled Unreal replication).
223
+ ## Anti-patterns
224
+
225
+ | Anti-pattern | Why it bites | Do instead |
226
+ | --- | --- | --- |
227
+ | Writing net code before the topology is chosen | Authority and cost model change everything downstream | Pick dedicated / listen / P2P first, and make the *same code* run on server and listen host |
228
+ | Trusting a client-reported result (health, position, score, hit) | That is the cheat surface, and lag looks identical to cheating | Clients send intent only; the server validates and owns all gameplay state |
229
+ | RPCing state that must stay consistent | A dropped unreliable event desyncs that client permanently | Replicate nouns (state), RPC verbs (events) — replicated values self-correct |
230
+ | Ownership/authority left implicit | The #1 cause of "works for the host, breaks for the client" | Set authority/ownership explicitly on spawn |
231
+ | Forgetting the listen-server host is also a client | Authority-only logic double-executes on the host | Guard it behind `is_server()` / `HasAuthority()` |
232
+ | Making the owning client wait a full RTT for its own input | Movement feels sluggish and unresponsive | Predict locally + reconcile; snapshot-interpolate remote entities |
233
+ | Client-side hit detection for hitscan | Trivially spoofed, and unfair to the higher-ping shooter | Server-side lag compensation: rewind to the shooter's render time |
234
+ | Tying simulation to render FPS | Sim diverges between machines at different frame rates | Fixed timestep on the sim, interpolate on the render |
235
+ | Replicating everything, every tick, to everyone | Melts bandwidth and leaks wallhack fuel | Scope by relevancy/visibility and send rate; rate-limit RPCs |
236
+ | Testing only on localhost | 0 ms RTT masks the exact desync/rubber-band bugs players will hit | Inject latency + packet loss across instances, exercising the client path |
237
+ | Emitting UNet/HLAPI, Godot 3.x `master`/`puppet`/`rset`, or `Tick`-polled Unreal replication | Removed or legacy — it will not compile or will silently underperform | The current APIs in the version contract above |