prr-kit 1.1.3 → 1.2.1
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/LICENSE +1 -1
- package/README.md +260 -235
- package/docs/assets/banner.svg +30 -248
- package/docs/assets/how-it-works.svg +87 -0
- package/package.json +60 -60
- package/src/core/agents/prr-master.agent.yaml +18 -7
- package/src/core/tasks/clear.md +140 -0
- package/src/core/tasks/help.md +15 -13
- package/src/core/workflows/clear/workflow.md +6 -0
- package/src/core/workflows/help/workflow.md +6 -0
- package/src/core/workflows/party-mode/steps/step-01-load-reviewers.md +35 -24
- package/src/core/workflows/party-mode/steps/step-02-discussion.md +45 -25
- package/src/core/workflows/party-mode/workflow.md +2 -2
- package/src/prr/agents/architecture-reviewer.agent.yaml +65 -45
- package/src/prr/agents/business-reviewer.agent.yaml +66 -0
- package/src/prr/agents/general-reviewer.agent.yaml +64 -48
- package/src/prr/agents/performance-reviewer.agent.yaml +65 -45
- package/src/prr/agents/security-reviewer.agent.yaml +67 -43
- package/src/prr/config-template.yaml +97 -0
- package/src/prr/data/stacks/actix.md +55 -0
- package/src/prr/data/stacks/alpine.md +47 -0
- package/src/prr/data/stacks/android.md +53 -0
- package/src/prr/data/stacks/angular.md +96 -0
- package/src/prr/data/stacks/ansible.md +55 -0
- package/src/prr/data/stacks/apollo.md +54 -0
- package/src/prr/data/stacks/astro.md +48 -0
- package/src/prr/data/stacks/aws-cdk.md +55 -0
- package/src/prr/data/stacks/axum.md +56 -0
- package/src/prr/data/stacks/babylonjs.md +55 -0
- package/src/prr/data/stacks/bash.md +53 -0
- package/src/prr/data/stacks/bevy.md +53 -0
- package/src/prr/data/stacks/bootstrap.md +52 -0
- package/src/prr/data/stacks/bun.md +55 -0
- package/src/prr/data/stacks/cpp.md +57 -0
- package/src/prr/data/stacks/csharp.md +95 -0
- package/src/prr/data/stacks/css.md +55 -0
- package/src/prr/data/stacks/cypress.md +53 -0
- package/src/prr/data/stacks/d3.md +53 -0
- package/src/prr/data/stacks/deno.md +49 -0
- package/src/prr/data/stacks/django.md +92 -0
- package/src/prr/data/stacks/docker.md +79 -0
- package/src/prr/data/stacks/drizzle.md +54 -0
- package/src/prr/data/stacks/dynamodb.md +55 -0
- package/src/prr/data/stacks/electron.md +44 -0
- package/src/prr/data/stacks/elixir.md +53 -0
- package/src/prr/data/stacks/expo.md +53 -0
- package/src/prr/data/stacks/expressjs.md +82 -0
- package/src/prr/data/stacks/fastapi.md +88 -0
- package/src/prr/data/stacks/fastify.md +60 -0
- package/src/prr/data/stacks/fiber.md +55 -0
- package/src/prr/data/stacks/firebase.md +43 -0
- package/src/prr/data/stacks/flask.md +46 -0
- package/src/prr/data/stacks/flutter.md +75 -0
- package/src/prr/data/stacks/gin.md +57 -0
- package/src/prr/data/stacks/github-actions.md +71 -0
- package/src/prr/data/stacks/go.md +88 -0
- package/src/prr/data/stacks/godot.md +56 -0
- package/src/prr/data/stacks/graphql.md +76 -0
- package/src/prr/data/stacks/grpc.md +56 -0
- package/src/prr/data/stacks/haskell.md +48 -0
- package/src/prr/data/stacks/helm.md +54 -0
- package/src/prr/data/stacks/hono.md +54 -0
- package/src/prr/data/stacks/htmx.md +38 -0
- package/src/prr/data/stacks/java.md +87 -0
- package/src/prr/data/stacks/jest-vitest.md +87 -0
- package/src/prr/data/stacks/jquery.md +50 -0
- package/src/prr/data/stacks/junit.md +53 -0
- package/src/prr/data/stacks/kotlin.md +89 -0
- package/src/prr/data/stacks/kubernetes.md +148 -0
- package/src/prr/data/stacks/langchain.md +56 -0
- package/src/prr/data/stacks/laravel.md +56 -0
- package/src/prr/data/stacks/libgdx.md +46 -0
- package/src/prr/data/stacks/lit.md +49 -0
- package/src/prr/data/stacks/love2d.md +51 -0
- package/src/prr/data/stacks/lua.md +51 -0
- package/src/prr/data/stacks/mobx.md +54 -0
- package/src/prr/data/stacks/mongodb.md +85 -0
- package/src/prr/data/stacks/monogame.md +51 -0
- package/src/prr/data/stacks/mysql.md +57 -0
- package/src/prr/data/stacks/nestjs.md +95 -0
- package/src/prr/data/stacks/nextjs.md +88 -0
- package/src/prr/data/stacks/nginx.md +55 -0
- package/src/prr/data/stacks/node.md +56 -0
- package/src/prr/data/stacks/nuxtjs.md +91 -0
- package/src/prr/data/stacks/openai-api.md +54 -0
- package/src/prr/data/stacks/opengl.md +54 -0
- package/src/prr/data/stacks/phaser.md +54 -0
- package/src/prr/data/stacks/phoenix.md +55 -0
- package/src/prr/data/stacks/php.md +56 -0
- package/src/prr/data/stacks/playwright.md +86 -0
- package/src/prr/data/stacks/postgresql.md +60 -0
- package/src/prr/data/stacks/prisma.md +81 -0
- package/src/prr/data/stacks/pygame.md +52 -0
- package/src/prr/data/stacks/pytest.md +53 -0
- package/src/prr/data/stacks/python.md +94 -0
- package/src/prr/data/stacks/pytorch.md +54 -0
- package/src/prr/data/stacks/qwik.md +50 -0
- package/src/prr/data/stacks/rails.md +48 -0
- package/src/prr/data/stacks/react-native.md +77 -0
- package/src/prr/data/stacks/react.md +104 -0
- package/src/prr/data/stacks/redis.md +76 -0
- package/src/prr/data/stacks/redux.md +107 -0
- package/src/prr/data/stacks/remix.md +51 -0
- package/src/prr/data/stacks/rust.md +88 -0
- package/src/prr/data/stacks/sass.md +51 -0
- package/src/prr/data/stacks/scala.md +50 -0
- package/src/prr/data/stacks/scikit-learn.md +53 -0
- package/src/prr/data/stacks/sequelize.md +54 -0
- package/src/prr/data/stacks/socket-io.md +54 -0
- package/src/prr/data/stacks/solidity.md +53 -0
- package/src/prr/data/stacks/solidjs.md +45 -0
- package/src/prr/data/stacks/spring-boot.md +92 -0
- package/src/prr/data/stacks/sql.md +85 -0
- package/src/prr/data/stacks/sqlite.md +55 -0
- package/src/prr/data/stacks/styled-components.md +51 -0
- package/src/prr/data/stacks/supabase.md +57 -0
- package/src/prr/data/stacks/svelte.md +77 -0
- package/src/prr/data/stacks/sveltekit.md +54 -0
- package/src/prr/data/stacks/swift.md +61 -0
- package/src/prr/data/stacks/tailwindcss.md +10 -0
- package/src/prr/data/stacks/tanstack-query.md +48 -0
- package/src/prr/data/stacks/tauri.md +52 -0
- package/src/prr/data/stacks/terraform.md +53 -0
- package/src/prr/data/stacks/three.md +53 -0
- package/src/prr/data/stacks/trpc.md +49 -0
- package/src/prr/data/stacks/typeorm.md +40 -0
- package/src/prr/data/stacks/typescript.md +83 -0
- package/src/prr/data/stacks/unity.md +61 -0
- package/src/prr/data/stacks/unreal.md +58 -0
- package/src/prr/data/stacks/vite.md +48 -0
- package/src/prr/data/stacks/vue3.md +95 -0
- package/src/prr/data/stacks/vulkan.md +53 -0
- package/src/prr/data/stacks/wasm.md +49 -0
- package/src/prr/data/stacks/webpack.md +48 -0
- package/src/prr/data/stacks/zig.md +51 -0
- package/src/prr/data/stacks/zustand.md +56 -0
- package/src/prr/workflows/1-discover/select-pr/steps/step-05-confirm.md +1 -0
- package/src/prr/workflows/1-discover/select-pr/workflow.md +1 -1
- package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-01-analyze-files.md +334 -0
- package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-02-collect-sources.md +451 -0
- package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-03-build-knowledge-base.md +337 -0
- package/src/prr/workflows/2-analyze/collect-pr-context/workflow.md +123 -0
- package/src/prr/workflows/2-analyze/describe-pr/steps/step-02-classify.md +12 -6
- package/src/prr/workflows/2-analyze/describe-pr/steps/step-03-walkthrough.md +59 -1
- package/src/prr/workflows/3-review/architecture-review/checklist.md +4 -0
- package/src/prr/workflows/3-review/architecture-review/instructions.xml +32 -4
- package/src/prr/workflows/3-review/architecture-review/workflow.yaml +17 -18
- package/src/prr/workflows/3-review/business-review/checklist.md +27 -0
- package/src/prr/workflows/3-review/business-review/instructions.xml +153 -0
- package/src/prr/workflows/3-review/business-review/workflow.yaml +17 -0
- package/src/prr/workflows/3-review/general-review/checklist.md +5 -1
- package/src/prr/workflows/3-review/general-review/instructions.xml +39 -8
- package/src/prr/workflows/3-review/general-review/workflow.yaml +17 -18
- package/src/prr/workflows/3-review/performance-review/checklist.md +3 -1
- package/src/prr/workflows/3-review/performance-review/instructions.xml +10 -3
- package/src/prr/workflows/3-review/performance-review/workflow.yaml +17 -18
- package/src/prr/workflows/3-review/security-review/checklist.md +2 -1
- package/src/prr/workflows/3-review/security-review/instructions.xml +8 -3
- package/src/prr/workflows/3-review/security-review/workflow.yaml +18 -19
- package/src/prr/workflows/4-improve/improve-code/workflow.yaml +17 -18
- package/src/prr/workflows/6-report/generate-report/steps/step-01-collect.md +9 -2
- package/src/prr/workflows/6-report/generate-report/steps/step-02-organize.md +28 -7
- package/src/prr/workflows/6-report/generate-report/steps/step-03-write.md +6 -4
- package/src/prr/workflows/6-report/generate-report/templates/review-report.template.md +124 -78
- package/src/prr/workflows/6-report/post-comments/steps/step-01-format.md +104 -13
- package/src/prr/workflows/6-report/post-comments/steps/step-02-post.md +92 -21
- package/src/prr/workflows/6-report/post-comments/workflow.md +6 -0
- package/src/prr/workflows/quick/workflow.md +138 -32
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-01-scan-configs.md +0 -106
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-02-extract-rules.md +0 -131
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-03-ask-context.md +0 -194
- package/src/prr/workflows/0-setup/collect-project-context/steps/step-04-save-context.md +0 -161
- package/src/prr/workflows/0-setup/collect-project-context/workflow.md +0 -58
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Kotlin — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.kt` files · `fun main()` · `import kotlin.` · `build.gradle.kts` · `@Composable` · `ViewModel` · `suspend fun` · `Flow` · `Coroutine`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
|
|
10
|
+
- **[CRITICAL]** SQL injection via string interpolation in Room queries: `@Query("SELECT * WHERE name = '$userInput'")` → use bound parameters `(:name)`.
|
|
11
|
+
- **[HIGH]** `WebView.settings.javaScriptEnabled = true` without overriding `WebViewClient.shouldOverrideUrlLoading()` → XSS from loaded content.
|
|
12
|
+
- **[HIGH]** `WebView.addJavascriptInterface()` with reflection access → native code callable from JS.
|
|
13
|
+
- **[HIGH]** Sensitive data (tokens, passwords) stored in `SharedPreferences` plaintext → use `EncryptedSharedPreferences`.
|
|
14
|
+
- **[HIGH]** Intent with user-controlled `action` or `data` without validation → intent injection from other apps.
|
|
15
|
+
- **[HIGH]** Exported `Activity`/`BroadcastReceiver` without permission in `AndroidManifest.xml` → any app can invoke.
|
|
16
|
+
- **[HIGH]** Hardcoded API keys in source code → extracted from APK with `apktool`.
|
|
17
|
+
- **[HIGH]** Certificate validation disabled via custom `TrustManager` → MITM.
|
|
18
|
+
- **[MEDIUM]** `Log.d` / `Log.v` logging sensitive data → visible in ADB LogCat.
|
|
19
|
+
- **[MEDIUM]** Missing `FLAG_SECURE` on Activity showing PINs, payment info → screenshots capture sensitive content.
|
|
20
|
+
- **[MEDIUM]** `Parcelable` deserialization of untrusted data → class loading attacks.
|
|
21
|
+
- **[LOW]** ProGuard/R8 not configured → class/method names readable in reverse-engineered APK.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Performance
|
|
26
|
+
|
|
27
|
+
- **[HIGH]** `runBlocking` on main thread → blocks UI thread, causes ANR if >5 seconds.
|
|
28
|
+
- **[HIGH]** `GlobalScope.launch` → coroutine not bound to lifecycle, continues after component destroyed → leak.
|
|
29
|
+
- **[HIGH]** `Dispatchers.IO` used for CPU-bound work → I/O thread pool exhausted. Use `Dispatchers.Default`.
|
|
30
|
+
- **[HIGH]** Jetpack Compose: heavy computation inside `@Composable` function body → runs on every recomposition.
|
|
31
|
+
- **[HIGH]** `remember { }` missing for expensive objects in Compose → recreated on every recomposition.
|
|
32
|
+
- **[HIGH]** `StateFlow` / `LiveData` collected without `repeatOnLifecycle(STARTED)` in Fragment → collects in background.
|
|
33
|
+
- **[HIGH]** Bitmap not recycled or sampled down for display size → OOM crash.
|
|
34
|
+
- **[HIGH]** Main thread network call (pre-Android 9 workarounds) → NetworkOnMainThreadException or ANR.
|
|
35
|
+
- **[MEDIUM]** `Flow` not collected with `flowOn(Dispatchers.IO)` for I/O-bound upstream → runs on collector's dispatcher.
|
|
36
|
+
- **[MEDIUM]** `viewModelScope.launch` inside `init {}` block → not cancelled if ViewModel immediately replaced.
|
|
37
|
+
- **[MEDIUM]** RecyclerView without `DiffUtil` → full list rebind on any data change.
|
|
38
|
+
- **[MEDIUM]** `suspend fun` doing CPU-heavy work on `Dispatchers.Main` → UI jank.
|
|
39
|
+
- **[LOW]** `withContext` wrapping already-correct-dispatcher suspend function → unnecessary context switch overhead.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Architecture
|
|
44
|
+
|
|
45
|
+
- **[HIGH]** `ViewModel` holding reference to `Activity` / `Fragment` Context → memory leak after rotation. Use `applicationContext`.
|
|
46
|
+
- **[HIGH]** `LiveData` / `StateFlow` observed in `onCreate` without `lifecycleScope.repeatOnLifecycle` → multiple observers accumulate on back-stack.
|
|
47
|
+
- **[HIGH]** Business logic in Activity / Fragment → violates MVVM; move to ViewModel + UseCase.
|
|
48
|
+
- **[HIGH]** Repository missing → ViewModel directly calls data source → not testable.
|
|
49
|
+
- **[HIGH]** Mutable `MutableStateFlow` / `MutableLiveData` exposed directly from ViewModel → external mutation bypasses state management.
|
|
50
|
+
- **[HIGH]** `StateFlow` vs `SharedFlow` wrong choice: `SharedFlow` for events (one-shot), `StateFlow` for UI state.
|
|
51
|
+
- **[HIGH]** Not using Hilt/Koin for DI → manual DI at scale becomes maintenance nightmare.
|
|
52
|
+
- **[MEDIUM]** `data class` with `var` fields used as ViewModel state → unintentional mutation bypasses reactive update.
|
|
53
|
+
- **[MEDIUM]** `CoroutineScope` created manually in Activity/Fragment instead of using `lifecycleScope`.
|
|
54
|
+
- **[MEDIUM]** Navigation Component not used → manual fragment transactions → back stack management bugs.
|
|
55
|
+
- **[MEDIUM]** `Event` wrapper pattern for `LiveData` one-shot events → use `Channel` or `SharedFlow` instead.
|
|
56
|
+
- **[LOW]** Not using `sealed class`/`sealed interface` for UI state → exhaustive `when` not enforced.
|
|
57
|
+
- **[LOW]** Not separating domain layer (Use Cases) from data layer.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Code Quality
|
|
62
|
+
|
|
63
|
+
- **[HIGH]** `!!` (non-null assertion) without preceding null check → `NullPointerException` at runtime. Use `?.`, `?:`, `requireNotNull()`.
|
|
64
|
+
- **[HIGH]** `async { }.await()` sequential pattern → defeats concurrency. Use `async { }` + deferred, await all at end.
|
|
65
|
+
- **[HIGH]** Missing `CoroutineExceptionHandler` on `launch` → unhandled exception silently swallowed.
|
|
66
|
+
- **[MEDIUM]** `object` (singleton) holding Android `Context` reference → leaked context. Use `WeakReference` or restructure.
|
|
67
|
+
- **[MEDIUM]** Extension function on `Any?` or too-broad type → pollutes autocomplete.
|
|
68
|
+
- **[MEDIUM]** Not using Kotlin's `sealed` result types for domain errors instead of exceptions.
|
|
69
|
+
- **[MEDIUM]** `apply` / `also` / `let` / `run` scope functions misused → confusion about `this` vs `it`.
|
|
70
|
+
- **[MEDIUM]** `data class` used for entities with identity (DB rows) → `equals`/`hashCode` on all fields, not just ID.
|
|
71
|
+
- **[MEDIUM]** Not using `by lazy` for expensive one-time property initialization.
|
|
72
|
+
- **[LOW]** Companion object holding non-constant data → shared across all instances.
|
|
73
|
+
- **[LOW]** Not using `typealias` for complex function types → unreadable parameter types.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Common Bugs & Pitfalls
|
|
78
|
+
|
|
79
|
+
- **[HIGH]** `viewLifecycleOwner` vs `this` in Fragment → using `this` causes multiple LiveData callbacks on back navigation.
|
|
80
|
+
- **[HIGH]** `launch` exception without handler → silently swallowed (unlike `async`). Add `CoroutineExceptionHandler`.
|
|
81
|
+
- **[HIGH]** `Flow.collect` in `lifecycleScope.launch {}` → collects in background when UI paused. Use `repeatOnLifecycle`.
|
|
82
|
+
- **[HIGH]** Coroutine cancelled by `CancellationException` caught with `catch (e: Exception)` → coroutine can't cancel.
|
|
83
|
+
- **[HIGH]** `Channel.send()` in one coroutine, `receive()` in another → deadlock if sender cancelled before receiver ready.
|
|
84
|
+
- **[MEDIUM]** `stateIn(scope, SharingStarted.Eagerly, ...)` → starts collecting even when no subscribers → wasted resources.
|
|
85
|
+
- **[MEDIUM]** `withContext(Dispatchers.IO)` wrapping a `suspend` function that already switches context → redundant overhead.
|
|
86
|
+
- **[MEDIUM]** `MutableList` shared between coroutines without synchronization → concurrent modification.
|
|
87
|
+
- **[MEDIUM]** `by viewModels()` delegate used in `Fragment` before `onAttach()` → crash.
|
|
88
|
+
- **[LOW]** `companion object` initialization order misunderstood → `const val` vs `val` differs.
|
|
89
|
+
- **[LOW]** `inline fun` with `reified T` used without understanding runtime overhead of inlining.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# Kubernetes Stack Rules
|
|
2
|
+
|
|
3
|
+
## Detection Signals
|
|
4
|
+
`*.yaml` with `apiVersion:` + `kind: Deployment/Service/Pod` · `kubectl` · `helm` charts · `kustomization.yaml` · `.k8s/` directory · `Dockerfile` + k8s manifests
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
|
|
10
|
+
**[CRITICAL]** Container running as root (`runAsUser: 0` or missing `securityContext`) → privilege escalation on container escape. Set `runAsNonRoot: true`, `runAsUser: 1000+` in pod securityContext.
|
|
11
|
+
|
|
12
|
+
**[CRITICAL]** `privileged: true` in container securityContext → equivalent to root on host node, full kernel access. Never use in production; remove the flag entirely.
|
|
13
|
+
|
|
14
|
+
**[CRITICAL]** `hostPID: true` / `hostNetwork: true` / `hostIPC: true` on pod → shares host namespaces, full host process/network visibility. Restrict to specific system workloads only.
|
|
15
|
+
|
|
16
|
+
**[HIGH]** Secrets stored in ConfigMap instead of Secret → ConfigMaps readable by anyone with namespace read access. Use Secret with encryption at rest via KMS provider.
|
|
17
|
+
|
|
18
|
+
**[HIGH]** Secrets passed as environment variables → visible in `kubectl describe pod`, `/proc/environ`, and crash dumps. Mount secrets as volumes with `secretKeyRef` instead.
|
|
19
|
+
|
|
20
|
+
**[HIGH]** Missing NetworkPolicy → all pods communicate freely by default, unrestricted east-west traffic. Define ingress/egress rules for least-privilege per workload.
|
|
21
|
+
|
|
22
|
+
**[HIGH]** RBAC ClusterRole with wildcard (`*`) verbs or resources → over-privileged service accounts that can read/write anything. Use minimal Role scoped to the specific namespace and resources needed.
|
|
23
|
+
|
|
24
|
+
**[HIGH]** `automountServiceAccountToken: true` (default) on pods not needing API access → service account token is a lateral movement vector. Set `automountServiceAccountToken: false` on the service account and pod spec.
|
|
25
|
+
|
|
26
|
+
**[HIGH]** `allowPrivilegeEscalation: true` (default) → child processes can gain more privileges than the parent. Set `allowPrivilegeEscalation: false` in container securityContext.
|
|
27
|
+
|
|
28
|
+
**[MEDIUM]** `readOnlyRootFilesystem: false` → malicious process can write to container filesystem and install tools. Set `readOnlyRootFilesystem: true` and use emptyDir volumes for writable paths.
|
|
29
|
+
|
|
30
|
+
**[MEDIUM]** Image pulled from public registry without digest pinning → image tag can be silently replaced (supply chain attack). Use `@sha256:` digest instead of mutable tags.
|
|
31
|
+
|
|
32
|
+
**[MEDIUM]** Ingress without TLS termination → traffic travels in plaintext from ingress controller to pod. Add cert-manager TLS annotation and configure HTTPS redirect.
|
|
33
|
+
|
|
34
|
+
**[LOW]** Namespaces without ResourceQuota → a single namespace can starve others of CPU/memory. Set CPU and memory quotas per namespace.
|
|
35
|
+
|
|
36
|
+
**[LOW]** Missing PodSecurityStandard policy (restricted/baseline) → pods can request dangerous capabilities without enforcement. Enable via namespace label pod-security.kubernetes.io/enforce: restricted.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Performance
|
|
41
|
+
|
|
42
|
+
**[CRITICAL]** Missing resource requests → scheduler cannot place pods optimally, nodes become oversubscribed and unstable. Always set `requests.cpu` and `requests.memory` for every container.
|
|
43
|
+
|
|
44
|
+
**[CRITICAL]** Missing resource limits → pod can consume all node memory causing OOM kills of neighbouring pods. Set `limits.memory` always; consider omitting CPU limit to avoid throttling.
|
|
45
|
+
|
|
46
|
+
**[HIGH]** Single replica (`replicas: 1`) for stateless service → rolling update causes downtime, node failure kills service entirely. Use at minimum 2 replicas for any production workload.
|
|
47
|
+
|
|
48
|
+
**[HIGH]** Missing PodDisruptionBudget → `kubectl drain` terminates all replicas simultaneously during node maintenance. Define `minAvailable` or `maxUnavailable` for every critical deployment.
|
|
49
|
+
|
|
50
|
+
**[HIGH]** HPA without VPA for right-sizing → pods scale horizontally but individual pod requests are too large or too small. Combine HPA for horizontal scaling with VPA recommendations for request tuning.
|
|
51
|
+
|
|
52
|
+
**[HIGH]** `imagePullPolicy: Always` on every pod start → extra registry latency on each restart, deployment fails if registry is unreachable. Use `IfNotPresent` with immutable tags or digest pins.
|
|
53
|
+
|
|
54
|
+
**[HIGH]** Missing preStop hook and insufficient `terminationGracePeriodSeconds` → in-flight requests dropped when pod receives SIGTERM during rolling update. Add a preStop sleep hook and increase grace period to cover longest request duration.
|
|
55
|
+
|
|
56
|
+
**[MEDIUM]** CPU limit set too low (CPU throttling) → container is throttled even when node has available CPU, causing latency spikes. Set CPU limit 2-4x the request, or remove CPU limit and rely on node-level fairness.
|
|
57
|
+
|
|
58
|
+
**[MEDIUM]** Not using Cluster Autoscaler or Karpenter → nodes are under- or over-provisioned regardless of pod demand. Enable node autoscaling based on pending pod scheduling pressure.
|
|
59
|
+
|
|
60
|
+
**[MEDIUM]** JVM or Node.js container without heap size flags → runtime uses host memory detection and exceeds container memory limit, causing OOMKill. Set -Xmx to approximately 75% of limits.memory for JVM; set --max-old-space-size for Node.js.
|
|
61
|
+
|
|
62
|
+
**[MEDIUM]** Liveness probe too aggressive (short timeout + low failureThreshold) → healthy pods restarted during GC pause or slow startup. Increase `initialDelaySeconds`, `timeoutSeconds`, and `failureThreshold`.
|
|
63
|
+
|
|
64
|
+
**[LOW]** Not using `topologySpreadConstraints` → all pods scheduled on same node or availability zone, single point of failure. Define spread constraints by topology.kubernetes.io/zone.
|
|
65
|
+
|
|
66
|
+
**[LOW]** Pods without `priorityClassName` → low-priority batch jobs not evicted first during resource pressure, starving critical services. Assign priority classes: critical, default, low.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Architecture
|
|
71
|
+
|
|
72
|
+
**[HIGH]** Stateful data written to pod local filesystem or emptyDir → data lost permanently when pod restarts or is rescheduled. Use PersistentVolumeClaim with appropriate StorageClass.
|
|
73
|
+
|
|
74
|
+
**[HIGH]** Image tag `:latest` → tag changes silently, deployments are non-reproducible, rollback is unreliable. Use semantic version tags or `@sha256:` digest pinning.
|
|
75
|
+
|
|
76
|
+
**[HIGH]** Missing readinessProbe → pod receives live traffic before the application finishes initialization, causing errors during startup. Define an HTTP or exec readinessProbe for every container.
|
|
77
|
+
|
|
78
|
+
**[HIGH]** Missing livenessProbe → Kubernetes cannot detect a deadlocked application and will never restart it automatically. Define a livenessProbe that checks only internal process health, not external dependencies.
|
|
79
|
+
|
|
80
|
+
**[HIGH]** ConfigMap or Secret not versioned or referenced by hash annotation → config changes do not trigger pod restart; app runs stale configuration. Use a checksum annotation or the Reloader operator to trigger rollouts on config change.
|
|
81
|
+
|
|
82
|
+
**[HIGH]** All microservices deployed to the default namespace → no RBAC or NetworkPolicy isolation between teams or environments. Use per-team or per-environment namespaces with dedicated service accounts.
|
|
83
|
+
|
|
84
|
+
**[MEDIUM]** Hardcoded registry URLs in manifests → migrating to a new registry requires mass find-and-replace across all manifests. Use Kustomize image transformers or Helm values for registry configuration.
|
|
85
|
+
|
|
86
|
+
**[MEDIUM]** Resources missing explicit `namespace` field → resources created in default namespace, mixing environments unpredictably. Always specify `metadata.namespace` in every manifest.
|
|
87
|
+
|
|
88
|
+
**[MEDIUM]** Direct Pod manifests instead of Deployments → bare pods are not rescheduled on node failure and cannot be rolled back. Always use Deployment, StatefulSet, or DaemonSet.
|
|
89
|
+
|
|
90
|
+
**[MEDIUM]** Helm chart values hardcoded in `values.yaml` without environment overrides → chart is not reusable across dev, staging, and production. Use environment-specific value files or Helmfile for per-environment configuration.
|
|
91
|
+
|
|
92
|
+
**[MEDIUM]** Not using Kustomize overlays for environment differences → manifests duplicated across environments, diverging over time. Use base + overlay structure with patches for per-environment differences.
|
|
93
|
+
|
|
94
|
+
**[LOW]** Missing Prometheus scrape annotations → metrics not collected by Prometheus Operator, no visibility into pod performance. Add prometheus.io/scrape and prometheus.io/port annotations or create a ServiceMonitor resource.
|
|
95
|
+
|
|
96
|
+
**[LOW]** Not using init containers for database migration → application starts before migration runs, causing schema mismatch errors at startup. Use an init container that runs migrations and exits before the main container starts.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Code Quality
|
|
101
|
+
|
|
102
|
+
**[HIGH]** `kubectl apply` with generated manifests not tracked in git → configuration drift, no audit trail, no reliable rollback. Use GitOps (ArgoCD or Flux) to reconcile cluster state from a git repository.
|
|
103
|
+
|
|
104
|
+
**[HIGH]** Missing `namespace` field in manifest → resources created in wrong namespace, label selectors do not match, hard to diagnose. Always specify `metadata.namespace` on every resource.
|
|
105
|
+
|
|
106
|
+
**[HIGH]** Service selector labels not matching Deployment pod template labels → zero pods selected, all connections refused with no obvious error message. Cross-check spec.selector.matchLabels against spec.template.metadata.labels.
|
|
107
|
+
|
|
108
|
+
**[HIGH]** Not running `helm lint` or `kubectl --dry-run=client` before applying → invalid manifests deployed, misconfigured fields silently ignored. Add lint and dry-run steps to the CI pipeline before every apply.
|
|
109
|
+
|
|
110
|
+
**[MEDIUM]** YAML indentation errors → Kubernetes silently ignores misconfigured fields rather than rejecting them. Enforce yamllint in CI and use a schema validator such as kubeconform.
|
|
111
|
+
|
|
112
|
+
**[MEDIUM]** Not using `kubectl rollout status` to verify deployment success → deployment assumed complete when only submitted to API server. Add `kubectl rollout status deployment/name --timeout=120s` after every apply.
|
|
113
|
+
|
|
114
|
+
**[MEDIUM]** ConfigMap keys containing periods → keys with periods cannot be used as environment variable names. Use underscores for keys intended to be consumed as env vars.
|
|
115
|
+
|
|
116
|
+
**[MEDIUM]** Resource names exceeding 63 characters → DNS label limit exceeded; Service and Ingress creation fails with cryptic errors. Keep all resource names under 63 characters.
|
|
117
|
+
|
|
118
|
+
**[MEDIUM]** Resources not tagged with standard labels (app, version, component) → hard to query, filter, and correlate resources across the cluster. Apply app.kubernetes.io/* labels consistently to all resources.
|
|
119
|
+
|
|
120
|
+
**[LOW]** Not using Strategic Merge Patch for Kustomize overlay values → Kustomize performs full replacement instead of merge for some fields. Use Strategic Merge Patch type for lists (containers, volumes) in patches.
|
|
121
|
+
|
|
122
|
+
**[LOW]** Missing owner references on child resources → orphaned resources not garbage collected when parent is deleted, accumulating over time. Set ownerReferences on dynamically created child resources.
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Common Bugs & Pitfalls
|
|
127
|
+
|
|
128
|
+
**[HIGH]** Service selector mismatch with Pod template labels → traffic routes to zero pods, connection refused with no helpful error message. Compare Service.spec.selector with Deployment.spec.template.metadata.labels character by character.
|
|
129
|
+
|
|
130
|
+
**[HIGH]** PersistentVolumeClaim with `ReadWriteOnce` on a multi-node Deployment → second pod stays permanently Pending because volume can only be mounted by one node at a time. Use `ReadWriteMany` (NFS, EFS) or `ReadWriteOncePod` for single-pod guarantee.
|
|
131
|
+
|
|
132
|
+
**[HIGH]** HPA `targetCPUUtilizationPercentage` misunderstood as percentage of limit → HPA calculates utilization against requests, not limits; HPA never fires if limit is much larger than request. Set requests accurately to reflect typical load.
|
|
133
|
+
|
|
134
|
+
**[HIGH]** Deployment with `maxSurge: 0` and `maxUnavailable: 0` → rolling update deadlocks immediately, never terminates old pods or creates new ones. Set at least one of these to a non-zero value.
|
|
135
|
+
|
|
136
|
+
**[MEDIUM]** `kubectl apply` on manifest using `generateName` → creates a new resource on every apply instead of updating the existing one. Use a fixed `name` field for resources managed declaratively.
|
|
137
|
+
|
|
138
|
+
**[MEDIUM]** Init container failure not visible in main container logs → kubectl logs shows only the main container; init failure is invisible. Use kubectl logs with the --container flag specifying the init container name.
|
|
139
|
+
|
|
140
|
+
**[MEDIUM]** Secret value not base64 encoded in YAML manifest → Kubernetes rejects the manifest with a decode error. Base64-encode all values under `data:`, or use `stringData:` which accepts plaintext and encodes automatically.
|
|
141
|
+
|
|
142
|
+
**[MEDIUM]** Liveness probe hitting an endpoint that queries the database → cascading pod restarts during database slowdown kills all replicas simultaneously. Liveness probe should check only internal process health with no external dependency calls.
|
|
143
|
+
|
|
144
|
+
**[MEDIUM]** Using `kubectl replace` without specifying resourceVersion → concurrent replace loses changes made between read and write. Use `kubectl apply` for idempotent declarative updates.
|
|
145
|
+
|
|
146
|
+
**[LOW]** NodePort service unintentionally exposing an internal service externally → port accessible from outside the cluster without authentication. Use ClusterIP for internal services; front external access with an Ingress or LoadBalancer Service.
|
|
147
|
+
|
|
148
|
+
**[LOW]** CronJob without `concurrencyPolicy: Forbid` → jobs pile up when a previous run has not finished, exhausting cluster resources. Set `concurrencyPolicy: Forbid` or `Replace` depending on the desired behaviour.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# LangChain — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `from 'langchain'`, `from '@langchain/`, `langchain`, `LLMChain`, `ChatOpenAI`, `PromptTemplate`, `AgentExecutor`, `VectorStore`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[CRITICAL]** User input inserted directly into a system prompt or template without sanitization → prompt injection allows the user to override system instructions or extract confidential prompt content. Treat all user input as untrusted data; use structured output parsers instead of raw string insertion.
|
|
10
|
+
- **[CRITICAL]** Agent configured with `PythonREPLTool`, `BashTool`, or other arbitrary code execution tools → a prompt injection attack causes the agent to execute malicious code on the server. Disable code-execution tools in production; use sandboxed environments with strict allowlists if required.
|
|
11
|
+
- **[HIGH]** LLM-generated output used directly in code execution paths, SQL queries, or shell commands without validation → second-order injection. Always validate and escape LLM output before using it in downstream operations.
|
|
12
|
+
- **[HIGH]** Vector store containing sensitive or multi-tenant data queried without per-user access control → user A retrieves user B's embedded documents. Partition vector stores by user/tenant or apply metadata filters on every retrieval query.
|
|
13
|
+
- **[HIGH]** LLM provider API keys stored in environment variables without rotation or access auditing → stolen key results in unbounded API cost. Use a secrets manager with automatic rotation; monitor API usage for anomalies.
|
|
14
|
+
- **[MEDIUM]** Conversation history persisted in a database with user PII and no encryption or retention policy → privacy regulation violation. Encrypt conversation records at rest and enforce a retention/deletion policy.
|
|
15
|
+
- **[MEDIUM]** Agent given a web search or HTTP request tool without restrictions → SSRF attack causes agent to probe internal network services. Restrict tool-accessible URLs to an allowlist and block private IP ranges.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Performance
|
|
20
|
+
- **[HIGH]** LLM responses not streamed for long-running generation → end-user sees a blank UI until the full response arrives. Use `stream: true` or `astream()` and emit tokens progressively to the client.
|
|
21
|
+
- **[HIGH]** Full conversation history sent to the LLM on every turn without summarisation → context window fills up, responses degrade, and costs scale linearly with conversation length. Apply `ConversationSummaryBufferMemory` or trim history to a rolling window.
|
|
22
|
+
- **[HIGH]** No caching configured for identical or similar prompts → every request hits the LLM API, inflating cost and latency. Enable `langchain.cache` with an in-memory, Redis, or SQLite backend for deterministic prompts.
|
|
23
|
+
- **[MEDIUM]** Sequential LLM calls that are independent of each other → total latency is the sum of all calls. Use `RunnableParallel` to execute independent chains concurrently.
|
|
24
|
+
- **[MEDIUM]** Entire large document embedded as a single chunk → exceeds context window limits and retrieval quality degrades. Use `RecursiveCharacterTextSplitter` with appropriate `chunk_size` and `chunk_overlap`.
|
|
25
|
+
- **[MEDIUM]** Synchronous LangChain APIs used inside an async application framework → event loop blocked during LLM calls. Use async chain methods (`ainvoke`, `astream`) throughout async code.
|
|
26
|
+
- **[LOW]** Embeddings recomputed for the same documents on every application restart → unnecessary API cost and startup latency. Persist embeddings to a vector store with disk or database backing.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Architecture
|
|
31
|
+
- **[HIGH]** Prompt text hardcoded as inline string literals → prompts not version controlled, reviewed, or A/B testable. Store prompts as `PromptTemplate` objects in dedicated files or manage them via LangChain Hub.
|
|
32
|
+
- **[HIGH]** Agent tools not explicitly scoped with descriptions and parameter schemas → agent misuses tools or attempts to call non-existent capabilities. Define each tool with a precise description and use `args_schema` with Pydantic models.
|
|
33
|
+
- **[MEDIUM]** LangSmith tracing not enabled in production → no observability into chain execution, token usage, or latency. Set `LANGCHAIN_TRACING_V2=true` and configure the LangSmith API key for all environments.
|
|
34
|
+
- **[MEDIUM]** Retrieval and generation tightly coupled in one chain → cannot optimise, test, or swap retrieval independently. Separate the retrieval step (query transformation, vector search, reranking) from the generation step.
|
|
35
|
+
- **[MEDIUM]** `ConversationChain` or `LLMChain` used instead of LCEL (LangChain Expression Language) → legacy API with limited composability. Migrate to `Runnable` pipes (`chain = prompt | llm | parser`) for maintainability.
|
|
36
|
+
- **[LOW]** Prompt versions not tracked in LangChain Hub or a version control system → impossible to roll back a prompt regression. Commit prompts to version control and tag releases.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Code Quality
|
|
41
|
+
- **[HIGH]** LLM response parsed with string splitting or regex instead of output parsers → brittle parsing breaks on minor format variation. Use `PydanticOutputParser`, `JsonOutputParser`, or `StructuredOutputParser` with format instructions in the prompt.
|
|
42
|
+
- **[HIGH]** No retry or fallback logic for LLM API rate limit or transient errors → single request failure surfaces directly to the user. Wrap chain invocations with `.with_retry()` or a try/except with exponential backoff, and configure `with_fallbacks()` for model failover.
|
|
43
|
+
- **[MEDIUM]** Chain not tested with adversarial or edge-case inputs → prompt injection and malformed output not caught before production. Write unit tests with mocked LLMs and integration tests with boundary inputs.
|
|
44
|
+
- **[MEDIUM]** Conversation history not managed with `RunnableWithMessageHistory` → manual history threading is error-prone and inconsistent. Use `RunnableWithMessageHistory` with a `BaseChatMessageHistory` backend.
|
|
45
|
+
- **[MEDIUM]** `AgentExecutor` `verbose=True` left on in production → internal chain reasoning and tool calls logged to stdout. Set `verbose=False` in production and route structured logs to an observability platform.
|
|
46
|
+
- **[LOW]** LangChain version pinned with a broad range (`>=0.1`) → breaking API changes introduced silently. Pin to an exact minor version and review the changelog before upgrading.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Common Bugs & Pitfalls
|
|
51
|
+
- **[HIGH]** `AgentExecutor` created without `max_iterations` or `max_execution_time` → agent enters an infinite reasoning loop, generating unbounded API costs. Always set `max_iterations` (e.g., 10) and `max_execution_time` as safeguards.
|
|
52
|
+
- **[HIGH]** Vector store not persisted to disk or a database → all embeddings lost on application restart and must be recomputed. Use a persistent backend (Chroma with `persist_directory`, Pinecone, pgvector) and load on startup.
|
|
53
|
+
- **[MEDIUM]** Token count not validated before sending to the LLM → request exceeds the model's context window and the API returns an error. Count tokens with the model's tokenizer before each request and truncate or summarise if needed.
|
|
54
|
+
- **[MEDIUM]** `ConversationBufferMemory` used without a maximum token or turn limit → memory grows without bound until the context window is exceeded. Replace with `ConversationBufferWindowMemory` or `ConversationSummaryBufferMemory`.
|
|
55
|
+
- **[MEDIUM]** Tool `description` is vague or overlaps with another tool → agent calls the wrong tool or oscillates between tools. Write unambiguous, action-oriented descriptions that clearly distinguish each tool's purpose.
|
|
56
|
+
- **[LOW]** Chain inputs not validated with Pydantic before invocation → malformed inputs produce confusing internal errors. Define input schemas with Pydantic and validate at the chain entry point.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Laravel — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.php` files, `artisan`, `Eloquent`, `routes/web.php`, `app/Http/Controllers`, `composer.json` with laravel/framework
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
|
|
10
|
+
- **[CRITICAL]** Raw DB query with user input: `DB::select("SELECT * WHERE id = $id")` → SQL injection. Use Eloquent or query builder with bindings.
|
|
11
|
+
- **[CRITICAL]** Missing CSRF token on POST/PUT/DELETE forms (`@csrf` blade directive) → CSRF attack.
|
|
12
|
+
- **[HIGH]** Missing `Auth::check()` / `auth()` middleware on protected routes → unauthenticated access.
|
|
13
|
+
- **[HIGH]** `{!! $variable !!}` in Blade with user-controlled content → XSS. Use `{{ }}` which auto-escapes.
|
|
14
|
+
- **[HIGH]** Mass assignment without `$fillable` or `$guarded` → attacker sets arbitrary model fields (e.g., `is_admin`).
|
|
15
|
+
- **[HIGH]** Secrets in `.env` committed or hardcoded in config → use `.env` + `.gitignore`.
|
|
16
|
+
- **[MEDIUM]** Authorization policy missing — `Gate::allows()` / Policy not checked before sensitive operation.
|
|
17
|
+
- **[MEDIUM]** `Storage::disk('public')` used for private files → files directly accessible via URL.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Performance
|
|
22
|
+
|
|
23
|
+
- **[HIGH]** N+1 Eloquent queries — accessing relationship in loop without eager loading (`with()`).
|
|
24
|
+
- **[HIGH]** `Model::all()` on large tables without pagination → loads entire table.
|
|
25
|
+
- **[MEDIUM]** Missing database indexes on columns used in `where()`, `orderBy()`, `join()`.
|
|
26
|
+
- **[MEDIUM]** `count()` on Eloquent collection (`$collection->count()`) after loading vs `Model::count()` DB query.
|
|
27
|
+
- **[MEDIUM]** Missing `chunk()` for large dataset operations → memory exhaustion.
|
|
28
|
+
- **[LOW]** No query result caching for expensive, stable reads (Laravel Cache).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Architecture
|
|
33
|
+
|
|
34
|
+
- **[HIGH]** Business logic in Controller → move to Service classes or Action classes.
|
|
35
|
+
- **[HIGH]** Direct Eloquent queries in Controller bypassing Repository/Service layer.
|
|
36
|
+
- **[MEDIUM]** Fat Eloquent models (>500 lines) violating SRP → extract traits or services.
|
|
37
|
+
- **[MEDIUM]** Event/Listener used for critical synchronous business logic → timing and error handling become opaque.
|
|
38
|
+
- **[LOW]** Missing Form Request classes for complex validation → validation logic inline in controller.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Code Quality
|
|
43
|
+
|
|
44
|
+
- **[HIGH]** Missing validation before using `$request->input()` → unvalidated data in business logic.
|
|
45
|
+
- **[MEDIUM]** `dd()` / `dump()` left in code → debugging output in production.
|
|
46
|
+
- **[MEDIUM]** Hardcoded strings for status/type values instead of Enums (PHP 8.1+) or constants.
|
|
47
|
+
- **[LOW]** Missing resource classes for API responses → inconsistent JSON structure.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Common Bugs & Pitfalls
|
|
52
|
+
|
|
53
|
+
- **[HIGH]** `firstOrCreate` / `updateOrCreate` not atomic → race condition in high-concurrency scenarios.
|
|
54
|
+
- **[HIGH]** Queue job not idempotent → retried jobs cause duplicate side effects.
|
|
55
|
+
- **[MEDIUM]** `Carbon` timezone not set → date comparison bugs in non-UTC deployments.
|
|
56
|
+
- **[MEDIUM]** Relationship `->get()` called instead of `->first()` → returns Collection when single model expected.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# LibGDX — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `com.badlogicgames`, `Gdx.`, `ApplicationAdapter`, `SpriteBatch`, `AssetManager`, `Box2D`, `*.gdx`, `libgdx`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[MEDIUM]** User-provided level or save files loaded and parsed without validation → malformed data causes crashes or exploits memory parsers. Validate all external data against a schema before processing; reject files that fail validation.
|
|
10
|
+
- **[MEDIUM]** Reflection-based serialization (`Json.fromJson()`) with untrusted input → arbitrary class instantiation or field injection. Restrict JSON deserialization to a known set of types using a whitelist or switch to a safer format (e.g., Protocol Buffers).
|
|
11
|
+
- **[LOW]** Server endpoints for online features hardcoded in the binary → man-in-the-middle or reverse-engineering of API endpoints. Fetch endpoints from a signed configuration loaded at startup; pin SSL certificates for sensitive requests.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Performance
|
|
16
|
+
- **[CRITICAL]** Object allocation (`new`, `ArrayList()`, etc.) inside `render()` → triggers Android GC, causing frame-rate spikes and jank. Pre-allocate all objects before game loop; use `com.badlogic.gdx.utils.Pool` for recycling frequently created/destroyed objects.
|
|
17
|
+
- **[HIGH]** Not using `AssetManager` → textures, sounds, and models loaded synchronously, blocking the render thread for seconds. Use `AssetManager.load()` with an async loading screen; check `AssetManager.isFinished()` each frame.
|
|
18
|
+
- **[HIGH]** Not using texture atlases (TexturePacker) → individual texture binds per sprite cause excessive GPU state changes and draw calls. Pack all sprites into atlases with `gdx-tools` TexturePacker; use `TextureAtlas` and `AtlasRegion` for lookups.
|
|
19
|
+
- **[HIGH]** Box2D physics step not using a fixed timestep → simulation becomes non-deterministic and unstable at varying frame rates. Accumulate delta time and step the world in fixed increments (`1/60f`); interpolate rendering between steps.
|
|
20
|
+
- **[MEDIUM]** `SpriteBatch.begin()`/`end()` called too frequently or interrupted by texture switches → extra flush calls reduce batching efficiency. Sort sprites by texture region; batch all draws for the same atlas region before flushing.
|
|
21
|
+
- **[LOW]** Not using `Pools` (`com.badlogic.gdx.utils.Pools`) for frequently created objects (e.g., `Vector2`, `Rectangle`) → unnecessary GC pressure from short-lived heap objects. Obtain from `Pools.obtain(Vector2.class)` and `Pools.free(v)` after use.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Architecture
|
|
26
|
+
- **[HIGH]** All game logic implemented directly inside `ApplicationAdapter` or `ApplicationListener` → untestable, unmaintainable as game grows. Use the `Game` + `Screen` pattern; separate update logic into domain classes that are independent of LibGDX lifecycle.
|
|
27
|
+
- **[HIGH]** Not using the `Game`/`Screen` interface for managing game states → ad hoc state flags proliferate in the main class. Implement `Screen` for each game state (menu, gameplay, pause, game-over) and use `Game.setScreen()` to transition.
|
|
28
|
+
- **[MEDIUM]** Rendering and game logic update not separated → logic tied to frame rate causes speed variations on slower devices. Call `update(delta)` before `render()` and cap or accumulate delta to decouple simulation from frame rate.
|
|
29
|
+
- **[LOW]** Platform-specific differences (desktop vs Android vs HTML5 vs iOS) not abstracted behind interfaces → platform-conditional code scattered through game logic. Define platform interfaces and inject the appropriate implementation via the LibGDX `ApplicationListener` factory pattern.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Code Quality
|
|
34
|
+
- **[HIGH]** `Texture`, `SpriteBatch`, `BitmapFont`, `AssetManager`, `Sound`, `Music`, or `ShaderProgram` not disposed when no longer needed → native OpenGL/OpenAL resources leak, causing OOM or driver instability. Implement `Disposable` on all resource-holding classes and call `dispose()` in `Screen.dispose()` and `ApplicationListener.dispose()`.
|
|
35
|
+
- **[MEDIUM]** Not using `gdx-tools` TexturePacker at build time → manually managed sprite sheets become out of sync with source art. Integrate TexturePacker into the build pipeline so atlases are regenerated on asset changes.
|
|
36
|
+
- **[MEDIUM]** `Gdx.app.log()` / `Gdx.app.error()` calls left unrestricted in production builds → log spam on end-user devices and potential information disclosure. Gate verbose logging behind a `BuildConfig.DEBUG` flag or a runtime log level setting.
|
|
37
|
+
- **[LOW]** GWT (HTML5) backend constraints not considered during development → classes not supported by GWT (reflection, some `java.util` features) cause HTML build failures. Test HTML5 target in CI; avoid GWT-incompatible APIs unless the HTML5 backend is explicitly excluded.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Common Bugs & Pitfalls
|
|
42
|
+
- **[HIGH]** Texture or OpenGL resource created on a background thread → OpenGL context is thread-local on Android/desktop; creating resources off the render thread causes `GLException`. Always create GL resources on the render thread; post work to the render thread with `Gdx.app.postRunnable()`.
|
|
43
|
+
- **[HIGH]** `AssetManager.finishLoading()` called on the render thread as a blocking wait → freezes the render loop for the full load duration. Use the async pattern: call `update()` each frame and check `isFinished()` to proceed.
|
|
44
|
+
- **[MEDIUM]** `Vector2.tmp` or `Vector3.tmp` static scratch fields used in nested or multi-threaded calls → the same temporary object overwritten mid-calculation. Create local `Vector2` instances or use `Pools`; never rely on static tmp fields across method boundaries.
|
|
45
|
+
- **[MEDIUM]** `BitmapFont` created directly from a TTF or not disposed → underlying `Texture` leaks native memory. Create fonts via `AssetManager` with `FreetypeFontLoader` and let the manager handle disposal.
|
|
46
|
+
- **[LOW]** Android back button not handled (`Gdx.input.setCatchKey(Input.Keys.BACK, true)` not set) → app exits abruptly without saving state or showing a confirmation dialog. Catch the back key explicitly and implement the intended behavior (pause menu, confirm quit, etc.).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Lit (Web Components) — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `from 'lit'`, `from 'lit/decorators'`, `LitElement`, `@customElement`, `` html` ``, `` css` ``, `*.ts` with `customElements.define`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[CRITICAL]** `unsafeHTML()` directive used with user-controlled content → XSS allowing arbitrary script injection into shadow DOM. Sanitize with DOMPurify before passing to `unsafeHTML()`, or use safe text interpolation `${userContent}`.
|
|
10
|
+
- **[HIGH]** `unsafeCSS()` used with user-supplied style strings → CSS injection enabling UI redressing or data exfiltration via CSS selectors. Only use `unsafeCSS()` with static developer-controlled strings; never with user input.
|
|
11
|
+
- **[HIGH]** Event listeners added to `window` or `document` in `connectedCallback` without removal in `disconnectedCallback` → memory leak and ghost event handlers after element removal. Always mirror `addEventListener` in `connectedCallback` with `removeEventListener` in `disconnectedCallback`.
|
|
12
|
+
- **[MEDIUM]** Sensitive data reflected to HTML attributes via `@property({ reflect: true })` → PII exposed in DOM and queryable by third-party scripts. Set `reflect: false` (the default) for sensitive properties; only reflect non-sensitive state needed for CSS selectors.
|
|
13
|
+
- **[MEDIUM]** Missing Content Security Policy allowing inline scripts in pages with custom elements → CSP bypass via attribute injection. Define a strict CSP and use nonce-based script allowlisting.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Performance
|
|
18
|
+
- **[HIGH]** Entire template re-rendered when only one property changes due to no `guard()` directive on expensive subtrees → unnecessary DOM diffing. Wrap expensive static subtrees with the `guard(deps, () => html\`...\`)` directive.
|
|
19
|
+
- **[MEDIUM]** `@state` not used for internal reactive properties; `@property` used instead → unnecessary attribute serialization and reflection on every change. Use `@state()` for properties that are internal implementation details not needed as attributes.
|
|
20
|
+
- **[MEDIUM]** Heavy DOM trees in `render()` without using `repeat()` directive for lists → full list re-render instead of efficient keyed updates. Use `repeat(items, item => item.id, item => html\`...\`)` for keyed list rendering.
|
|
21
|
+
- **[MEDIUM]** `willUpdate` / `updated` lifecycle hooks not used to avoid redundant computations triggered per property change → computed values recalculated on every render. Derive expensive computations in `willUpdate` only when relevant properties change.
|
|
22
|
+
- **[LOW]** Full `lit` package imported instead of specific entry points (`lit/html.js`, `lit/decorators.js`) → larger-than-necessary bundle. Import from specific Lit subpaths to enable tree-shaking.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Architecture
|
|
27
|
+
- **[HIGH]** Business logic (API calls, data transformation) placed directly inside `LitElement` class methods → components become fat controllers, untestable in isolation. Extract to service classes or plain functions; inject via constructor or properties.
|
|
28
|
+
- **[HIGH]** Deep shadow DOM nesting (custom elements inside custom elements, 4+ levels) makes CSS theming require many CSS custom properties → hard to maintain design tokens. Flatten component hierarchy where possible; define a comprehensive set of CSS custom properties at component boundaries.
|
|
29
|
+
- **[MEDIUM]** Content projection not used via `<slot>`; instead content is passed as properties → tight coupling between parent and child markup. Use named `<slot>` elements for flexible content composition.
|
|
30
|
+
- **[MEDIUM]** Custom events not typed with `CustomEvent<TDetail>` and not documented → consumers have no type safety for event payloads. Type all dispatched events and document them in the component's API surface.
|
|
31
|
+
- **[MEDIUM]** `@property({ reflect: true })` on boolean attributes not using the `type: Boolean` converter → `false` reflected as the string `"false"` which is truthy in CSS attribute selectors. Always include `type: Boolean` for boolean properties that reflect.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Code Quality
|
|
36
|
+
- **[HIGH]** Properties updated reactively without declaring them with `@property` or `@state` → Lit does not schedule re-render, UI goes stale. Every reactive property must be declared with `@property()` or `@state()`.
|
|
37
|
+
- **[MEDIUM]** `this.shadowRoot.querySelector(...)` used instead of `@query` decorator → verbose, non-typed DOM reference. Use `@query('#my-input') input!: HTMLInputElement` for typed, cached element references.
|
|
38
|
+
- **[MEDIUM]** `@customElement('my-el')` decorator and manual `customElements.define('my-el', MyEl)` both present → double registration error. Use only one registration method; prefer `@customElement` decorator.
|
|
39
|
+
- **[MEDIUM]** `:host` CSS incorrectly used for internal element styling instead of targeting internal selectors → styles leak or don't apply as expected. Use `:host` only for the host element itself; use internal class/element selectors for children.
|
|
40
|
+
- **[LOW]** `static styles` defined per instance using `css\`\`` inside a function → styles recreated every instantiation. Define `static styles` as a static class field evaluated once.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Common Bugs & Pitfalls
|
|
45
|
+
- **[HIGH]** DOM-dependent initialization code placed in `connectedCallback` before first render completes → element not yet in DOM, `this.shadowRoot` children may not exist. Use `firstUpdated()` for code that needs the rendered shadow DOM.
|
|
46
|
+
- **[HIGH]** `@property` type converter mismatch — string attribute `"false"` not converting to boolean `false` → attribute is truthy when component expects `false`. Declare `type: Boolean` and use presence/absence of attribute rather than its value.
|
|
47
|
+
- **[HIGH]** Custom events not dispatched with `composed: true` → events don't cross shadow DOM boundaries and parent listeners never fire. Dispatch cross-boundary events with `new CustomEvent('name', { bubbles: true, composed: true })`.
|
|
48
|
+
- **[MEDIUM]** Shadow DOM breaking third-party CSS libraries (Bootstrap, Tailwind) that style by global class → styles not applied inside shadow root. Use CSS custom properties for theming or `adoptedStyleSheets` to share styles; document the limitation.
|
|
49
|
+
- **[MEDIUM]** Lit template caching with keyed `repeat()` using non-stable keys (array index) → DOM nodes reused incorrectly on list reorder. Always use stable, unique identifiers (IDs) as keys in `repeat()`.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# LÖVE 2D — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `main.lua` with `love.`, `love.load`, `love.update`, `love.draw`, `love.graphics`, `love.keypressed`, `*.love`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[HIGH]** `love.filesystem.load()` called with a path derived from user input → executes arbitrary Lua code from the loaded file; never load and execute files from untrusted paths, and restrict file loading to the game's save directory or fused archive.
|
|
10
|
+
- **[MEDIUM]** Sensitive data (auth tokens, player credentials, purchase state) written with `love.filesystem.write()` in plaintext → readable by any process with filesystem access; encrypt sensitive data before writing, or store server-side.
|
|
11
|
+
- **[MEDIUM]** Network multiplayer receiving game action messages without server-side authority → cheating via crafted UDP/TCP packets; treat all received client inputs as untrusted and validate legality on the server.
|
|
12
|
+
- **[LOW]** Third-party Lua libraries loaded from user-writable directories → malicious library substitution; load libraries only from the fused game archive and verify file integrity where possible.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Performance
|
|
17
|
+
- **[HIGH]** New Lua tables, strings, or closures created inside `love.draw()` every frame → triggers the Lua garbage collector during rendering, causing periodic hitches; pre-allocate tables and strings before the game loop and reuse them.
|
|
18
|
+
- **[HIGH]** Large, uncompressed PNG images loaded without enabling GPU-side compression → excessive VRAM usage and slower texture sampling; use `love.graphics.newImage(path, {compress = true})` or pre-convert to compressed formats (DXT, ETC).
|
|
19
|
+
- **[HIGH]** `love.graphics.draw()` called individually for hundreds of identical images → one draw call per image; use `love.graphics.newSpriteBatch()` to batch all instances of the same image into a single draw call.
|
|
20
|
+
- **[MEDIUM]** Physics world `world:update(dt)` using variable `dt` directly → non-deterministic simulation that diverges between clients in multiplayer; use a fixed timestep accumulator: accumulate `dt` and step with a fixed interval until the accumulator is exhausted.
|
|
21
|
+
- **[MEDIUM]** Off-screen rendering results (UI panels, static backgrounds) redrawn from scratch every frame → wasted GPU work; render static or infrequently changing content to a `love.graphics.newCanvas()` and redraw the canvas only when the content changes.
|
|
22
|
+
- **[LOW]** `love.graphics.setFont()` called every frame when the font does not change → redundant state change; set the font once in `love.load()` and only call `setFont()` when switching between different fonts.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Architecture
|
|
27
|
+
- **[HIGH]** All game code (input, physics, rendering, AI, UI) in a single `main.lua` → monolithic and unmaintainable; split into Lua modules using `require()`: `src/player.lua`, `src/world.lua`, `src/ui.lua`, with clear interfaces between them.
|
|
28
|
+
- **[MEDIUM]** Lua `require()` module system not used → global functions and tables defined in `main.lua` polluting the global namespace; organize code into module files that return a table of functions and use `local M = {}; return M` pattern.
|
|
29
|
+
- **[MEDIUM]** All game state stored in global Lua variables → implicit dependencies and namespace collisions; use module-local state or pass state explicitly through function arguments.
|
|
30
|
+
- **[MEDIUM]** No state management for game screens (main menu, gameplay, pause, game over) → ad-hoc `if currentState == "menu"` branches throughout `love.update` and `love.draw`; implement a `GameState` module with `enter()`, `update(dt)`, `draw()`, and `exit()` callbacks.
|
|
31
|
+
- **[LOW]** Third-party state/scene libraries (hump.gamestate, knife.system) not considered for complex games → reinventing patterns already solved by the LÖVE ecosystem; evaluate established libraries before writing a custom state manager.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Code Quality
|
|
36
|
+
- **[HIGH]** `love.update(dt)` received but `dt` not used for movement, animation, or timer updates → frame-rate-dependent behavior that runs differently at 30 FPS vs 144 FPS; always multiply all per-frame changes by `dt` to produce time-based values.
|
|
37
|
+
- **[MEDIUM]** Magic numbers for entity positions, sprite dimensions, tile sizes, and speed constants scattered throughout update and draw functions → changing one value requires a global search; extract all tuning constants into a top-level `conf` or `constants` module.
|
|
38
|
+
- **[MEDIUM]** `love.keyboard.isDown()` used for discrete single-press actions (pause, jump, menu select) instead of `love.keypressed()` callback → `isDown` returns true every frame the key is held; use the `love.keypressed(key)` callback for one-shot actions and `isDown` only for continuous held input.
|
|
39
|
+
- **[MEDIUM]** `love.graphics.print()` called with concatenated strings every frame → string allocation GC pressure; pre-format strings and cache them, updating only when the displayed value changes.
|
|
40
|
+
- **[LOW]** `love.resize(w, h)` callback not implemented for resizable windows → layout and camera coordinates not updated on window resize; implement `love.resize` and update any coordinate systems that depend on window dimensions.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Common Bugs & Pitfalls
|
|
45
|
+
- **[HIGH]** `love.graphics.*` functions called outside of `love.draw()` (e.g., in `love.update()` or `love.load()`) → LÖVE requires all drawing to happen in `love.draw()`; calling graphics functions elsewhere raises an error; restrict all draw calls to the `love.draw()` callback.
|
|
46
|
+
- **[HIGH]** `love.load()` not releasing resources (canvases, images, physics worlds) before a game restart → memory leak on repeated restarts; explicitly set resource variables to `nil` and call `:release()` on LÖVE objects before reinitializing.
|
|
47
|
+
- **[MEDIUM]** Lua `#table` operator used on non-sequence tables (tables with nil holes or non-integer keys) → `#` returns undefined length for non-sequences; use an explicit `count` field or `table.maxn()` for sparse tables, and only use `#` on pure sequence tables.
|
|
48
|
+
- **[MEDIUM]** Box2D physics body not destroyed with `body:destroy()` when the associated game object is removed → the physics body remains in the world, consuming memory and participating in collisions invisibly; always call `body:destroy()` when removing a physics-enabled entity.
|
|
49
|
+
- **[MEDIUM]** `love.audio.newSource()` called inside `love.update()` or a frequently called function → each call loads and decodes the audio file; call `newSource()` once in `love.load()` and reuse the source, calling `source:seek(0); source:play()` to replay.
|
|
50
|
+
- **[LOW]** `love.filesystem` save directory not accessible on all platforms in the same way as the game directory → attempting to load from the source directory on a fused build fails; use `love.filesystem.getSourceBaseDirectory()` and `love.filesystem.getSaveDirectory()` and understand which is appropriate for each file type.
|
|
51
|
+
- **[LOW]** Floating-point `dt` accumulated over many frames in timers without resetting → floating-point drift causes timers to fire slightly off-schedule over long sessions; use integer millisecond counters or reset accumulators after each trigger.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Lua — Stack-Specific Review Rules
|
|
2
|
+
|
|
3
|
+
> Applies to: GR · SR · PR · AR · BR
|
|
4
|
+
> Detection signals: `*.lua`, `require(`, `local function`, `love.`, `--[[`, `ngx.`, `redis.call(`, `luarocks`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Security
|
|
9
|
+
- **[CRITICAL]** `load()` / `loadstring()` with user input → arbitrary Lua code execution. Never pass user-controlled strings to `load()`; validate and whitelist all dynamic code paths.
|
|
10
|
+
- **[CRITICAL]** `os.execute()` with user-controlled strings → command injection. Use a whitelist of allowed commands or avoid `os.execute()` entirely for user input.
|
|
11
|
+
- **[HIGH]** `io.open()` with user-controlled paths → path traversal. Canonicalize and validate paths against an allowed root before opening.
|
|
12
|
+
- **[HIGH]** `require()` with user-controlled module names → arbitrary module loading. Never construct module names from user input; use a static allowlist.
|
|
13
|
+
- **[MEDIUM]** Lua metatables manipulated to bypass access control → sandbox escape. Lock metatables with `__newindex` guards and freeze sensitive tables.
|
|
14
|
+
- **[MEDIUM]** Globals not sandboxed in embedded Lua environments → host process exposure. Set a restricted `_ENV` sandbox for all user-provided scripts.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Performance
|
|
19
|
+
- **[HIGH]** String concatenation with `..` in loops → O(n²) garbage collection pressure. Collect strings in a table and use `table.concat()` at the end.
|
|
20
|
+
- **[HIGH]** Global variable access in hot loops → globals are ~30% slower than locals due to hash lookups. Cache globals as locals at function top (`local sin = math.sin`).
|
|
21
|
+
- **[HIGH]** Not caching table field lookups in hot loops → repeated hash traversal. Assign frequently accessed fields to locals before the loop.
|
|
22
|
+
- **[MEDIUM]** Creating tables or closures inside inner loops → excessive GC pressure. Pre-allocate and reuse tables; move closure creation outside the loop.
|
|
23
|
+
- **[MEDIUM]** Recursive functions without tail call optimization → stack growth. Rewrite as `return f()` (true tail call) or convert to iterative form.
|
|
24
|
+
- **[LOW]** Not using LuaJIT for performance-critical applications → leaving significant JIT speedups on the table. Evaluate LuaJIT compatibility for the deployment target.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Architecture
|
|
29
|
+
- **[HIGH]** Module pattern not used → global namespace pollution and load-order dependencies. Wrap every module in `local M = {} … return M` and `require()` it explicitly.
|
|
30
|
+
- **[HIGH]** Metatables used for OOP without a consistent class pattern → fragile inheritance chains. Adopt one pattern (e.g., `__index`-based prototype) and enforce it across the codebase.
|
|
31
|
+
- **[MEDIUM]** Circular `require()` dependencies → partially-initialized module tables at require time. Refactor shared state into a third module or use lazy loading.
|
|
32
|
+
- **[MEDIUM]** Error handling not using `pcall`/`xpcall` → unhandled errors crash the running coroutine silently. Wrap all external calls and IO in `pcall`; use `xpcall` with a traceback handler for top-level boundaries.
|
|
33
|
+
- **[LOW]** Coroutines not used for cooperative multitasking where appropriate → blocking code in event-driven hosts (e.g., OpenResty). Yield at IO boundaries using coroutine-based async patterns.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Code Quality
|
|
38
|
+
- **[HIGH]** `local` not used for variables → accidental globals silently pollute `_G` and persist across calls. Declare every variable `local`; use `luacheck` to catch globals.
|
|
39
|
+
- **[HIGH]** Missing `pcall` around risky operations (file IO, network, `require`) → unhandled errors propagate and crash callers. Wrap with `pcall`/`xpcall` and return structured error values.
|
|
40
|
+
- **[MEDIUM]** Magic numbers instead of named constants → intent unclear and values duplicated. Lua has no `const`; define constants as module-level locals with UPPER_SNAKE naming.
|
|
41
|
+
- **[MEDIUM]** Tables used as arrays with mixed integer/string keys → the `#` length operator only counts the integer sequence and gives undefined results for sparse or mixed tables. Use purely integer-keyed tables for arrays and track length explicitly if needed.
|
|
42
|
+
- **[LOW]** Inconsistent use of `:` vs `.` for method calls → runtime errors when `self` is missing or an extra argument is passed. Establish a convention and enforce it in code review.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Common Bugs & Pitfalls
|
|
47
|
+
- **[HIGH]** Array indexing starts at 1, not 0 → off-by-one errors when porting algorithms or interfacing with C. Audit all index arithmetic and document the convention explicitly.
|
|
48
|
+
- **[HIGH]** `nil` in an array breaks the `#` length operator → iterating with `ipairs` stops early; `#` returns an unpredictable value. Track array length in a separate field or avoid `nil` holes.
|
|
49
|
+
- **[MEDIUM]** `and`/`or` used as a ternary expression → `false or default` evaluates to `default` even when the intended value is `false`. Use an explicit `if` expression or helper function.
|
|
50
|
+
- **[MEDIUM]** `==` on tables compares references, not content → two structurally identical tables are never equal. Implement a deep-equality function for value comparison.
|
|
51
|
+
- **[LOW]** Multiple return values silently truncated when assigned to a single variable → data loss with no error. Capture all return values explicitly or use `select('#', ...)` to verify count.
|