Trees and rocks on the terrain: terrain.scatter by layer and slope (ENG-F79) #131

Merged
kompas-review merged 2 commits from khyretos/claude/foliage-2 into main 2026-10-26 16:07:24 +01:00 AGit
Owner

Requested by Kees · project thread

Rebased onto main after #130 (day/night clock), which it builds on. All 1317 tests pass locally.

What (ENG-F79: trees, rocks and bushes)

  • Terrain::scatter(rule) puts one point per cell of a jittered grid, so things never pile up or line up in rows, and the same seed gives the same places on every machine. A point is kept only if the rule allows it: on a painted layer above minWeight (thinning towards the layer's edge), under maxSlope, between minHeight and maxHeight, inside an optional circle, and outside every keepClear circle. Each kept thing gets a random turn and size and stands straight or leans with the ground (Placement::transform()).
  • Lua terrain.scatter{model, density, layer, minWeight, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max} returns the group and a count. It spawns ordinary ModelModule instances, which are already drawn instanced and frustum-culled. solid = r adds a static capsule trunk up the model's height, so the player bumps into trees. Also terrain.unscatter(group) and terrain.scattered(). There's a limit of 50,000 per game. Sculpting moves scattered things and their trunks along with the ground.
  • Cookbook: a new recipe, valley.lua (algorithms.md "A valley with the engine's terrain"). It makes a seeded valley round the starter level with a flattened pad, a painted path and a hill, runs a day in a minute, and N makes a new valley. It runs in CI with the other recipes, so the terrain and the clock get a real-GPU check on every push. The screenshot was made with run_recipes.py --shots.
  • Docs: TERRAIN.md "Trees, rocks and bushes" (with a table, and a "Not yet" for GPU grass and wind sway), the SCRIPTING.md row, GAPS F79 🟡.

Tests

  • Terrain.ScatterFollowsTheRulesAndIsTheSameEveryTime: the same seed gives the same points; the count is about density × allowed area; nothing lands on a 63° bank under maxSlope 30; points sit on the ground; a layer, a circle and a clear circle are all respected; max caps the count; leaning things point along the ground's normal (through the transform).
  • The Lua test checks that scatter without a models module gives a clear error.
  • Full kke_tests: 1317 passed after the rebase, no warnings; mkdocs --strict is clean; run_recipes.py passes for valley.lua and terrain.lua.
  • In starter_game on the terrain, with a 2-cone low-poly test tree (an OBJ made on the spot, not committed): density = 3, maxSlope = 25 placed 949 trees with the start kept clear, plus 61 small ones only on the painted dirt path. The screenshot shows a forest on the gentle ground, none on the rock faces, and the clearing round the player.

🤖 Generated with Claude Code

https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7

<!-- claude-projects-attribution: {"github_login":"Khyretos"} --> _Requested by **Kees** · [project thread](https://claude.ai/code/project/chan_01Ds4PKvSLCNCCKr5TJxrV2A?thread=cmsg_01Ds4PKvSLCNCCKr5TJxrV2ABb2WaYyLkc7eUMNFVK1p2Z)_ Rebased onto main after #130 (day/night clock), which it builds on. All 1317 tests pass locally. ## What (ENG-F79: trees, rocks and bushes) - `Terrain::scatter(rule)` puts one point per cell of a jittered grid, so things never pile up or line up in rows, and the same seed gives the same places on every machine. A point is kept only if the rule allows it: on a painted layer above `minWeight` (thinning towards the layer's edge), under `maxSlope`, between `minHeight` and `maxHeight`, inside an optional circle, and outside every `keepClear` circle. Each kept thing gets a random turn and size and stands straight or leans with the ground (`Placement::transform()`). - Lua `terrain.scatter{model, density, layer, minWeight, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max}` returns the group and a count. It spawns ordinary ModelModule instances, which are already drawn instanced and frustum-culled. `solid = r` adds a static capsule trunk up the model's height, so the player bumps into trees. Also `terrain.unscatter(group)` and `terrain.scattered()`. There's a limit of 50,000 per game. Sculpting moves scattered things and their trunks along with the ground. - Cookbook: a new recipe, `valley.lua` (algorithms.md "A valley with the engine's terrain"). It makes a seeded valley round the starter level with a flattened pad, a painted path and a hill, runs a day in a minute, and N makes a new valley. It runs in CI with the other recipes, so the terrain and the clock get a real-GPU check on every push. The screenshot was made with `run_recipes.py --shots`. - Docs: TERRAIN.md "Trees, rocks and bushes" (with a table, and a "Not yet" for GPU grass and wind sway), the SCRIPTING.md row, GAPS F79 🟡. ## Tests - `Terrain.ScatterFollowsTheRulesAndIsTheSameEveryTime`: the same seed gives the same points; the count is about density × allowed area; nothing lands on a 63° bank under maxSlope 30; points sit on the ground; a layer, a circle and a clear circle are all respected; `max` caps the count; leaning things point along the ground's normal (through the transform). - The Lua test checks that scatter without a models module gives a clear error. - Full `kke_tests`: 1317 passed after the rebase, no warnings; `mkdocs --strict` is clean; `run_recipes.py` passes for valley.lua and terrain.lua. - In starter_game on the terrain, with a 2-cone low-poly test tree (an OBJ made on the spot, not committed): `density = 3, maxSlope = 25` placed 949 trees with the start kept clear, plus 61 small ones only on the painted dirt path. The screenshot shows a forest on the gentle ground, none on the rock faces, and the clearing round the player. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
Terrain::scatter places points on a jittered grid (one per cell, the
same for the same seed everywhere), kept where the rule allows: a
painted layer (thinning at its edge), a slope limit, a height band, a
circle, and circles kept clear. Placements lean with the ground or
stand straight, with a random turn and size.

Lua terrain.scatter{model, density, layer, maxSlope, minHeight,
maxHeight, scale, align, pos, radius, clear, solid, seed, max} spawns
model instances (instanced and culled by ModelModule), optionally with
static capsule trunks; unscatter(group) and scattered(). Sculpting
moves scattered things and their trunks with the ground. At most 50,000
per game.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
Cookbook: a valley with the engine's terrain and a day in a minute
All checks were successful
CI / dependencies (pull_request) Successful in 5s
CI / std-includes (pull_request) Successful in 12s
review / pr-agent PR-Agent reviewed this commit
Benchmarks / benchmarks (pull_request) Successful in 4m46s
CI / android (pull_request) Successful in 5m32s
Docs site / site (pull_request) Successful in 10s
lint / megalinter (pull_request) Successful in 58s
CI / shipping-build (pull_request) Successful in 15m56s
Windows (native) / build (pull_request) Successful in 9m50s
Windows (native) / test (pull_request) Successful in 6m25s
CI / release-build (pull_request) Successful in 43m7s
Windows (native) / publish (pull_request) Has been skipped
CI / build-test-and-coverage (pull_request) Successful in 1h53m26s
kk / all-checks All 13 checks passed
cdbe85bda5
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
kompas-review scheduled this pull request to auto merge when all checks succeed 2026-10-26 14:12:17 +01:00
Collaborator

/review

/review
Collaborator

Title

Trees and rocks on the terrain: terrain.scatter by layer and slope (ENG-F79)


User description

Requested by Kees · project thread

Rebased onto main after #130 (day/night clock), which it builds on. All 1317 tests pass locally.

What (ENG-F79: trees, rocks and bushes)

  • Terrain::scatter(rule) puts one point per cell of a jittered grid, so things never pile up or line up in rows, and the same seed gives the same places on every machine. A point is kept only if the rule allows it: on a painted layer above minWeight (thinning towards the layer's edge), under maxSlope, between minHeight and maxHeight, inside an optional circle, and outside every keepClear circle. Each kept thing gets a random turn and size and stands straight or leans with the ground (Placement::transform()).
  • Lua terrain.scatter{model, density, layer, minWeight, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max} returns the group and a count. It spawns ordinary ModelModule instances, which are already drawn instanced and frustum-culled. solid = r adds a static capsule trunk up the model's height, so the player bumps into trees. Also terrain.unscatter(group) and terrain.scattered(). There's a limit of 50,000 per game. Sculpting moves scattered things and their trunks along with the ground.
  • Cookbook: a new recipe, valley.lua (algorithms.md "A valley with the engine's terrain"). It makes a seeded valley round the starter level with a flattened pad, a painted path and a hill, runs a day in a minute, and N makes a new valley. It runs in CI with the other recipes, so the terrain and the clock get a real-GPU check on every push. The screenshot was made with run_recipes.py --shots.
  • Docs: TERRAIN.md "Trees, rocks and bushes" (with a table, and a "Not yet" for GPU grass and wind sway), the SCRIPTING.md row, GAPS F79 🟡.

Tests

  • Terrain.ScatterFollowsTheRulesAndIsTheSameEveryTime: the same seed gives the same points; the count is about density × allowed area; nothing lands on a 63° bank under maxSlope 30; points sit on the ground; a layer, a circle and a clear circle are all respected; max caps the count; leaning things point along the ground's normal (through the transform).
  • The Lua test checks that scatter without a models module gives a clear error.
  • Full kke_tests: 1317 passed after the rebase, no warnings; mkdocs --strict is clean; run_recipes.py passes for valley.lua and terrain.lua.
  • In starter_game on the terrain, with a 2-cone low-poly test tree (an OBJ made on the spot, not committed): density = 3, maxSlope = 25 placed 949 trees with the start kept clear, plus 61 small ones only on the painted dirt path. The screenshot shows a forest on the gentle ground, none on the rock faces, and the clearing round the player.

🤖 Generated with Claude Code

https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7


PR Type

Enhancement


Description

  • Adds terrain.scatter to place trees and rocks by rule

  • Supports layer, slope, height, circles, and solid trunks

  • Scattered items move with sculpted terrain and support unscatter


Diagram Walkthrough

flowchart LR
  A["Lua script"] -->|"terrain.scatter"| B["ScatterRule"]
  B -->|"density/layer/slope"| C["Terrain::scatter"]
  C -->|"placements"| D["ModelModule instances"]
  C -->|"solid"| E["RigidWorld bodies"]
  F["Sculpt terrain"] -.->|"reground"| G["Update positions & rotation"]
  D & E -->|"move with"| G

File Walkthrough

Relevant files
Enhancement
4 files
Terrain.h
Adds scatter rule and placement transform methods               
+26/-0   
Terrain.cpp
Implements jittered grid scattering with rules                     
+54/-0   
ScriptTerrain.h
Adds model storage and group tracking structures                 
+21/-0   
ScriptTerrain.cpp
Registers scatter/unscatter Lua functions and logic           
+154/-0 
Configuration changes
2 files
ScriptModule.cpp
Connects ScriptTerrain to ModelModule instance                     
+1/-0     
run_recipes.py
Adds camera config for valley recipe                                         
+1/-0     
Tests
1 files
test_terrain.cpp
Tests scatter rules and deterministic placement                   
+58/-0   
Documentation
5 files
valley.lua
New recipe showing valley with day cycle                                 
+34/-0   
TERRAIN.md
Documents scatter API and usage examples                                 
+43/-2   
SCRIPTING.md
Updates terrain function list with scatter                             
+1/-1     
GAPS.md
Marks foliage task as done with details                                   
+1/-1     
algorithms.md
References new valley recipe in algorithms                             
+26/-1   
Additional files
1 files
ScriptModule.h +2/-1     

## Title Trees and rocks on the terrain: terrain.scatter by layer and slope (ENG-F79) ___ ### **User description** <!-- claude-projects-attribution: {"github_login":"Khyretos"} --> _Requested by **Kees** · [project thread](https://claude.ai/code/project/chan_01Ds4PKvSLCNCCKr5TJxrV2A?thread=cmsg_01Ds4PKvSLCNCCKr5TJxrV2ABb2WaYyLkc7eUMNFVK1p2Z)_ Rebased onto main after #130 (day/night clock), which it builds on. All 1317 tests pass locally. ## What (ENG-F79: trees, rocks and bushes) - `Terrain::scatter(rule)` puts one point per cell of a jittered grid, so things never pile up or line up in rows, and the same seed gives the same places on every machine. A point is kept only if the rule allows it: on a painted layer above `minWeight` (thinning towards the layer's edge), under `maxSlope`, between `minHeight` and `maxHeight`, inside an optional circle, and outside every `keepClear` circle. Each kept thing gets a random turn and size and stands straight or leans with the ground (`Placement::transform()`). - Lua `terrain.scatter{model, density, layer, minWeight, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max}` returns the group and a count. It spawns ordinary ModelModule instances, which are already drawn instanced and frustum-culled. `solid = r` adds a static capsule trunk up the model's height, so the player bumps into trees. Also `terrain.unscatter(group)` and `terrain.scattered()`. There's a limit of 50,000 per game. Sculpting moves scattered things and their trunks along with the ground. - Cookbook: a new recipe, `valley.lua` (algorithms.md "A valley with the engine's terrain"). It makes a seeded valley round the starter level with a flattened pad, a painted path and a hill, runs a day in a minute, and N makes a new valley. It runs in CI with the other recipes, so the terrain and the clock get a real-GPU check on every push. The screenshot was made with `run_recipes.py --shots`. - Docs: TERRAIN.md "Trees, rocks and bushes" (with a table, and a "Not yet" for GPU grass and wind sway), the SCRIPTING.md row, GAPS F79 🟡. ## Tests - `Terrain.ScatterFollowsTheRulesAndIsTheSameEveryTime`: the same seed gives the same points; the count is about density × allowed area; nothing lands on a 63° bank under maxSlope 30; points sit on the ground; a layer, a circle and a clear circle are all respected; `max` caps the count; leaning things point along the ground's normal (through the transform). - The Lua test checks that scatter without a models module gives a clear error. - Full `kke_tests`: 1317 passed after the rebase, no warnings; `mkdocs --strict` is clean; `run_recipes.py` passes for valley.lua and terrain.lua. - In starter_game on the terrain, with a 2-cone low-poly test tree (an OBJ made on the spot, not committed): `density = 3, maxSlope = 25` placed 949 trees with the start kept clear, plus 61 small ones only on the painted dirt path. The screenshot shows a forest on the gentle ground, none on the rock faces, and the clearing round the player. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7 ___ ### **PR Type** Enhancement ___ ### **Description** - Adds `terrain.scatter` to place trees and rocks by rule - Supports layer, slope, height, circles, and solid trunks - Scattered items move with sculpted terrain and support unscatter ___ ### Diagram Walkthrough ```mermaid flowchart LR A["Lua script"] -->|"terrain.scatter"| B["ScatterRule"] B -->|"density/layer/slope"| C["Terrain::scatter"] C -->|"placements"| D["ModelModule instances"] C -->|"solid"| E["RigidWorld bodies"] F["Sculpt terrain"] -.->|"reground"| G["Update positions & rotation"] D & E -->|"move with"| G ``` <details> <summary><h3> File Walkthrough</h3></summary> <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Enhancement</strong></td><td><details><summary>4 files</summary><table> <tr> <td><strong>Terrain.h</strong><dd><code>Adds scatter rule and placement transform methods</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/engine/include/kke/Terrain.h">+26/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>Terrain.cpp</strong><dd><code>Implements jittered grid scattering with rules</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/engine/src/Terrain.cpp">+54/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>ScriptTerrain.h</strong><dd><code>Adds model storage and group tracking structures</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/engine/include/kke/ScriptTerrain.h">+21/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>ScriptTerrain.cpp</strong><dd><code>Registers scatter/unscatter Lua functions and logic</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/engine/src/ScriptTerrain.cpp">+154/-0</a>&nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Configuration changes</strong></td><td><details><summary>2 files</summary><table> <tr> <td><strong>ScriptModule.cpp</strong><dd><code>Connects ScriptTerrain to ModelModule instance</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/engine/src/modules/ScriptModule.cpp">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>run_recipes.py</strong><dd><code>Adds camera config for valley recipe</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/tools/docs_site/run_recipes.py">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Tests</strong></td><td><details><summary>1 files</summary><table> <tr> <td><strong>test_terrain.cpp</strong><dd><code>Tests scatter rules and deterministic placement</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/tests/test_terrain.cpp">+58/-0</a>&nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>5 files</summary><table> <tr> <td><strong>valley.lua</strong><dd><code>New recipe showing valley with day cycle</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/docs/cookbook/recipes/valley.lua">+34/-0</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>TERRAIN.md</strong><dd><code>Documents scatter API and usage examples</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/docs/TERRAIN.md">+43/-2</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>SCRIPTING.md</strong><dd><code>Updates terrain function list with scatter</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/docs/SCRIPTING.md">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>GAPS.md</strong><dd><code>Marks foliage task as done with details</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/docs/GAPS.md">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>algorithms.md</strong><dd><code>References new valley recipe in algorithms</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/docs/cookbook/algorithms.md">+26/-1</a>&nbsp; &nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Additional files</strong></td><td><details><summary>1 files</summary><table> <tr> <td><strong>ScriptModule.h</strong></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/131/head/engine/include/kke/modules/ScriptModule.h">+2/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr></tr></tbody></table> </details> ___
Collaborator

PR Reviewer Guide 🔍

(Review updated until commit cdbe85bda5)

📋 Focus areas: 🔴 2 open · ✅ 0 handled. Every push re-checks them; a handled area moves to Resolved findings at the bottom.

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected
## PR Reviewer Guide 🔍 <!-- pr-agent:review:full --> #### (Review updated until commit https://git.kreative-kompas.com/khyretos/kk-engine/commit/cdbe85bda51252d56e2e2aba62eae0086b337260) 📋 **Focus areas:** 🔴 2 open · ✅ 0 handled. Every push re-checks them; a handled area moves to *Resolved findings* at the bottom. <table> <tr><td>⏱️&nbsp;<strong>Estimated effort to review</strong>: 2 🔵🔵⚪⚪⚪</td></tr> <tr><td>🧪&nbsp;<strong>PR contains tests</strong></td></tr> <tr><td>🔒&nbsp;<strong>No security concerns identified</strong></td></tr> <tr><td>⚡&nbsp;<strong>No major issues detected</strong></td></tr> </table> <!-- pr-agent-review-state:v1 {"findings":[{"body":"**Potential Integer Overflow in Scatter Group Count**\n\nIn the `scatter` Lua binding, the `maxCount` field is calculated based on `maxScattered` and `scatteredCount()`. While `maxScattered` is capped at 50,000, the calculation `maxScattered - scatteredCount()` could theoretically result in a large number if `scatteredCount()` is very small and `maxScattered` is large, but more importantly, the `rule.maxCount` is clamped to `rule.maxCount` which defaults to 5000. However, the `rule.maxCount` is derived from `ScriptVM::fieldNumber(L, 1, \"max\", 5000.0f)`. If a user passes a very large number for `max`, it might exceed the intended limit of 50,000 total scattered objects. The code does `std::min(room, size_t(std::max(0.0f, ScriptVM::fieldNumber(L, 1, \"max\", 5000.0f))));`. If `room` is large (because `scatteredCount()` is small), and `max` is huge, `rule.maxCount` could be set to a value much larger than 50,000, potentially causing performance issues or memory exhaustion if many groups are created. The global limit `maxScattered` is checked per group creation (`room = maxScattered > scatteredCount() ? ...`), but if `max` is set to a very high value, it might allow creating a group that exceeds reasonable limits before hitting the global cap.","finding_id":"9bdf65c8d1e4","first_seen":"2026-10-26T13:13:30.502866Z","last_seen":"2026-10-26T13:13:30.502866Z","last_seen_head_sha":"cdbe85bda51252d56e2e2aba62eae0086b337260","line_end":446,"line_start":446,"path":"engine/src/ScriptTerrain.cpp","state":"ACTIVE"},{"body":"**Missing Error Handling for Invalid Layer Index**\n\nIn the `scatter` function, when a layer index is provided in the rule, it is used directly to access the `weights` array without validation. If an invalid layer index (e.g., negative or >= kLayers) is passed, this will cause an out-of-bounds memory access. The code attempts to handle this by defaulting to -1 if the index is out of range, but the check `rule.layer >= 0 && rule.layer < kLayers` happens before the loop, so the invalid index is never actually used in the loop logic. However, if the user explicitly passes an invalid layer index, the code should either clamp it or return an error rather than silently ignoring it or potentially accessing invalid memory depending on how `weights` is accessed later. Wait, looking closer at line 390-394: `if (layer >= 0 && layer < kLayers ? rule.layer : -1)` is not present. Instead, line 373 sets `const int layer = ...`. If `rule.layer` is out of bounds, `weights(sx, sz)[size_t(layer)]` on line 392 will crash. The check `if (layer >= 0 && layer < kLayers ? rule.layer : -1)` is NOT there. The code just uses `rule.layer` directly. This is a potential crash if an invalid layer index is passed.","finding_id":"ab4170009421","first_seen":"2026-10-26T13:13:30.502866Z","last_seen":"2026-10-26T13:13:30.502866Z","last_seen_head_sha":"cdbe85bda51252d56e2e2aba62eae0086b337260","line_end":373,"line_start":373,"path":"engine/src/Terrain.cpp","state":"ACTIVE"}],"last_run":{"complete":true,"excluded_files":[],"head_sha":"cdbe85bda51252d56e2e2aba62eae0086b337260","kind":"full","run_id":"https://git.kreative-kompas.com/khyretos/kk-engine/commit/cdbe85bda51252d56e2e2aba62eae0086b337260"},"schema_version":1} -->
Collaborator

PR Code Suggestions ✨

No code suggestions found for the PR.

## PR Code Suggestions ✨ <!-- pr-agent:improve:no-suggestions --> No code suggestions found for the PR.

🧹 Lint report · ❌ 38 problems in 6 checks · 🧹 3 formatting checks to tidy

Nothing here blocks the merge (report only).

Check Errors Warnings Files
❌ MARKDOWN · markdownlint 24 0 253
❌ CPP · cppcheck 9 0 935
❌ YAML · yamllint 2 0 57
❌ BASH · shellcheck 1 0 11
❌ DOCKERFILE · hadolint 1 0 9
❌ REPOSITORY · trivy 1 0 –
MARKDOWN · markdownlint: first lines of the output
See documentation on https://megalinter.io/9.4.0/descriptors/markdown_markdownlint/
-----------------------------------------------
❌ [ERROR] for workspace /workspace/khyretos/kk-engine
Linter raw log:
docs/ANDROID.md:87 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/ANDROID.md:128 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/ANDROID.md:136 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/ANDROID.md:149 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/ANDROID.md:163 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/ANDROID.md:186 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/ASSETS.md:155 error MD046/code-block-style Code block style [Expected: fenced; Actual: indented]
docs/HISTORY.md:21 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: " Kreative Kompas Engine (KKE)"]
docs/HISTORY.md:520 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/HISTORY.md:727 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/HISTORY.md:734 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/HISTORY.md:2031 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/HISTORY.md:2090 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/MODDING.md:13 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/NETWORKING.md:114 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/PLATFORMS.md:48 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/PROCEDURAL_ANIMATION.md:36 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/PROCEDURAL_ANIMATION.md:284 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
games/racing/README.md:34 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
games/racing/README.md:76:91 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data]
games/racing/README.md:77:89 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data]
…
CPP · cppcheck: first lines of the output
See documentation on https://megalinter.io/9.4.0/descriptors/cpp_cppcheck/
-----------------------------------------------
✅ [SUCCESS] benchmarks/kke_bench/main.cpp
✅ [SUCCESS] benchmarks/kke_benchmark/main.cpp
✅ [SUCCESS] engine/include/engine/Buffer.h
✅ [SUCCESS] engine/include/engine/Mesh.h
✅ [SUCCESS] engine/include/engine/Pipeline.h
✅ [SUCCESS] engine/include/engine/Renderer.h
✅ [SUCCESS] engine/include/engine/SwapChain.h
✅ [SUCCESS] engine/include/engine/VulkanCheck.h
✅ [SUCCESS] engine/include/engine/VulkanDevice.h
✅ [SUCCESS] engine/include/engine/Window.h
✅ [SUCCESS] engine/include/kke/AnimEvents.h
✅ [SUCCESS] engine/include/kke/AnimRig.h
✅ [SUCCESS] engine/include/kke/Animator.h
✅ [SUCCESS] engine/include/kke/Application.h
✅ [SUCCESS] engine/include/kke/AssetCatalog.h
✅ [SUCCESS] engine/include/kke/AudioMixer.h
✅ [SUCCESS] engine/include/kke/AutoRig.h
✅ [SUCCESS] engine/include/kke/BenchRecorder.h
✅ [SUCCESS] engine/include/kke/BenchmarkReport.h
✅ [SUCCESS] engine/include/kke/Bloom.h
✅ [SUCCESS] engine/include/kke/BodyShape.h
✅ [SUCCESS] engine/include/kke/BreakGraph.h
✅ [SUCCESS] engine/include/kke/Breakables.h
…
YAML · yamllint: first lines of the output
See documentation on https://megalinter.io/9.4.0/descriptors/yaml_yamllint/
-----------------------------------------------
❌ [ERROR] for workspace /workspace/khyretos/kk-engine
Linter raw log:
games/goblin_horde/data/heroes.yml
  53:11     error    too many spaces after colon  (colons)
  63:11     error    too many spaces after colon  (colons)
BASH · shellcheck: first lines of the output
See documentation on https://megalinter.io/9.4.0/descriptors/bash_shellcheck/
-----------------------------------------------
❌ [ERROR] for workspace /workspace/khyretos/kk-engine
Linter raw log:
In tools/packaging/package.sh line 130:
	done < <(find "$stage" "$stage/benchmark" -maxdepth 1 -type f \( -name "*$exe" -o -name '*.dll' \) $([ -z "$exe" ] && echo "-perm -u+x") -print0)
                                                                                                           ^-- SC2046 (warning): Quote this to prevent word splitting.
For more information:
  https://www.shellcheck.net/wiki/SC2046 -- Quote this to prevent word splitt...
DOCKERFILE · hadolint: first lines of the output
See documentation on https://megalinter.io/9.4.0/descriptors/dockerfile_hadolint/
-----------------------------------------------
❌ [ERROR] for workspace /workspace/khyretos/kk-engine
Linter raw log:
docker/android.Dockerfile:19 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
docker/appimage.Dockerfile:38 SC2016 info: Expressions don't expand in single quotes, use double quotes for that.
docker/appimage.Dockerfile:51 DL3003 warning: Use WORKDIR to switch to a directory
docker/appimage.Dockerfile:57 DL3003 warning: Use WORKDIR to switch to a directory
docker/appimage.Dockerfile:63 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
docker/appimage.Dockerfile:63 DL3003 warning: Use WORKDIR to switch to a directory
docker/appimage.Dockerfile:73 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
docker/appimage.Dockerfile:73 DL3003 warning: Use WORKDIR to switch to a directory
docker/ci.Dockerfile:42 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
docker/ci.Dockerfile:56 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
docker/server/Dockerfile:22 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
docker/vm.Dockerfile:22 SC2086 info: Double quote to prevent globbing and word splitting.
docker/vm.Dockerfile:29 DL3003 warning: Use WORKDIR to switch to a directory
docker/vm.Dockerfile:29 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
website/Dockerfile:9 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check
REPOSITORY · trivy: first lines of the output
See documentation on https://megalinter.io/9.4.0/descriptors/repository_trivy/
-----------------------------------------------
❌ [ERROR] for workspace /workspace/khyretos/kk-engine
Linter raw log:
2026-10-26T13:22:53Z	INFO	[vulndb] Need to update DB
2026-10-26T13:22:53Z	INFO	[vulndb] Downloading vulnerability DB...
2026-10-26T13:22:53Z	INFO	[vulndb] Downloading artifact...	repo="mirror.gcr.io/aquasec/trivy-db:2"
18.99 MiB / 129.73 MiB [-------->___________________________________________________] 14.64% ? p/s ?31.57 MiB / 129.73 MiB [-------------->_____________________________________________] 24.34% ? p/s ?42.73 MiB / 129.73 MiB [------------------->________________________________________] 32.94% ? p/s ?54.18 MiB / 129.73 MiB [------------------->___________________________] 41.76% 58.62 MiB p/s ETA 1s66.05 MiB / 129.73 MiB [----------------------->_______________________] 50.91% 58.62 MiB p/s ETA 1s76.84 MiB / 129.73 MiB [--------------------------->___________________] 59.23% 58.62 MiB p/s ETA 0s87.58 MiB / 129.73 MiB [------------------------------->_______________] 67.51% 58.43 MiB p/s ETA 0s98.29 MiB / 129.73 MiB [----------------------------------->___________] 75.77% 58.43 MiB p/s ETA 0s109.08 MiB / 129.73 MiB [-------------------------------------->_______] 84.09% 58.43 MiB p/s ETA 0s119.78 MiB / 129.73 MiB [------------------------------------------>___] 92.33% 58.13 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 58.13 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 58.13 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 55.44 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 55.44 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 55.44 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 51.87 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 51.87 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 51.87 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 48.52 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 48.52 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 48.52 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 45.39 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-----------------------------------------------] 100.00% 29.69 MiB p/s 4.6s2026-10-26T13:22:58Z	INFO	[vulndb] Artifact successfully downloaded	repo="mirror.gcr.io/aquasec/trivy-db:2"
2026-10-26T13:22:58Z	INFO	[vuln] Vulnerability scanning is enabled
2026-10-26T13:22:58Z	INFO	[misconfig] Misconfiguration scanning is enabled
2026-10-26T13:22:58Z	INFO	[checks-client] Need to update the checks bundle
2026-10-26T13:22:58Z	INFO	[checks-client] Downloading the checks bundle...
234.57 KiB / 234.57 KiB [---------------------------------------------------------] 100.00% ? p/s 0s2026-10-26T13:22:59Z	WARN	[rego] Module will be skipped as current version of Trivy is older than minimum trivy version required - please update Trivy to use this module	file_path="root/.cache/trivy/policy/content/policies/cloud/policies/aws/cloudfront/enable_logging.rego" minimum_trivy_version="0.72.0"
2026-10-26T13:22:59Z	ERROR	[dockerfile scanner] Failed to parse file	file_path="docker/server/Dockerfile.dockerignore" err="parse dockerfile instruction: parse instruction \".git\": unknown instruction: .git"
2026-10-26T13:22:59Z	INFO	Number of language-specific files	num=0
2026-10-26T13:22:59Z	INFO	Detected config files	num=9
Report Summary
┌──────────────────────────────┬────────────┬─────────────────┬───────────────────┐
│            Target            │    Type    │ Vulnerabilities │ Misconfigurations │
├──────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ benchmarks/docker/Dockerfile │ dockerfile │        -        │         2         │
├──────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ docker/android.Dockerfile    │ dockerfile │        -        │         2         │
├──────────────────────────────┼────────────┼─────────────────┼───────────────────┤
│ docker/appimage.Dockerfile   │ dockerfile │        -        │         5         │
…

🧹 Formatting only (layout, no behaviour; the nightly lint-fix job applies these as a PR): YAML · prettier (57 files checked), BASH · shfmt (11 files checked), JSON · prettier (147 files checked)

✅ Clean: actionlint, git_diff, gitleaks, grype, jsonlint, secretlint, stylelint, trufflehog, xmllint

MegaLinter on soucouyant · full logs in the Actions run · comment /improve for AI fix suggestions

<!-- kk-lint --> ## 🧹 Lint report · ❌ 38 problems in 6 checks · 🧹 3 formatting checks to tidy Nothing here blocks the merge (report only). | | Check | Errors | Warnings | Files | |---|---|---:|---:|---:| | ❌ | MARKDOWN · markdownlint | 24 | 0 | 253 | | ❌ | CPP · cppcheck | 9 | 0 | 935 | | ❌ | YAML · yamllint | 2 | 0 | 57 | | ❌ | BASH · shellcheck | 1 | 0 | 11 | | ❌ | DOCKERFILE · hadolint | 1 | 0 | 9 | | ❌ | REPOSITORY · trivy | 1 | 0 | – | <details><summary>MARKDOWN · markdownlint: first lines of the output</summary> ```text See documentation on https://megalinter.io/9.4.0/descriptors/markdown_markdownlint/ ----------------------------------------------- ❌ [ERROR] for workspace /workspace/khyretos/kk-engine Linter raw log: docs/ANDROID.md:87 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/ANDROID.md:128 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/ANDROID.md:136 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/ANDROID.md:149 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/ANDROID.md:163 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/ANDROID.md:186 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/ASSETS.md:155 error MD046/code-block-style Code block style [Expected: fenced; Actual: indented] docs/HISTORY.md:21 error MD025/single-title/single-h1 Multiple top-level headings in the same document [Context: " Kreative Kompas Engine (KKE)"] docs/HISTORY.md:520 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/HISTORY.md:727 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/HISTORY.md:734 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/HISTORY.md:2031 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/HISTORY.md:2090 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/MODDING.md:13 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/NETWORKING.md:114 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/PLATFORMS.md:48 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/PROCEDURAL_ANIMATION.md:36 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] docs/PROCEDURAL_ANIMATION.md:284 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] games/racing/README.md:34 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"] games/racing/README.md:76:91 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data] games/racing/README.md:77:89 error MD056/table-column-count Table column count [Expected: 4; Actual: 3; Too few cells, row will be missing data] … ``` </details> <details><summary>CPP · cppcheck: first lines of the output</summary> ```text See documentation on https://megalinter.io/9.4.0/descriptors/cpp_cppcheck/ ----------------------------------------------- ✅ [SUCCESS] benchmarks/kke_bench/main.cpp ✅ [SUCCESS] benchmarks/kke_benchmark/main.cpp ✅ [SUCCESS] engine/include/engine/Buffer.h ✅ [SUCCESS] engine/include/engine/Mesh.h ✅ [SUCCESS] engine/include/engine/Pipeline.h ✅ [SUCCESS] engine/include/engine/Renderer.h ✅ [SUCCESS] engine/include/engine/SwapChain.h ✅ [SUCCESS] engine/include/engine/VulkanCheck.h ✅ [SUCCESS] engine/include/engine/VulkanDevice.h ✅ [SUCCESS] engine/include/engine/Window.h ✅ [SUCCESS] engine/include/kke/AnimEvents.h ✅ [SUCCESS] engine/include/kke/AnimRig.h ✅ [SUCCESS] engine/include/kke/Animator.h ✅ [SUCCESS] engine/include/kke/Application.h ✅ [SUCCESS] engine/include/kke/AssetCatalog.h ✅ [SUCCESS] engine/include/kke/AudioMixer.h ✅ [SUCCESS] engine/include/kke/AutoRig.h ✅ [SUCCESS] engine/include/kke/BenchRecorder.h ✅ [SUCCESS] engine/include/kke/BenchmarkReport.h ✅ [SUCCESS] engine/include/kke/Bloom.h ✅ [SUCCESS] engine/include/kke/BodyShape.h ✅ [SUCCESS] engine/include/kke/BreakGraph.h ✅ [SUCCESS] engine/include/kke/Breakables.h … ``` </details> <details><summary>YAML · yamllint: first lines of the output</summary> ```text See documentation on https://megalinter.io/9.4.0/descriptors/yaml_yamllint/ ----------------------------------------------- ❌ [ERROR] for workspace /workspace/khyretos/kk-engine Linter raw log: games/goblin_horde/data/heroes.yml 53:11 error too many spaces after colon (colons) 63:11 error too many spaces after colon (colons) ``` </details> <details><summary>BASH · shellcheck: first lines of the output</summary> ```text See documentation on https://megalinter.io/9.4.0/descriptors/bash_shellcheck/ ----------------------------------------------- ❌ [ERROR] for workspace /workspace/khyretos/kk-engine Linter raw log: In tools/packaging/package.sh line 130: done < <(find "$stage" "$stage/benchmark" -maxdepth 1 -type f \( -name "*$exe" -o -name '*.dll' \) $([ -z "$exe" ] && echo "-perm -u+x") -print0) ^-- SC2046 (warning): Quote this to prevent word splitting. For more information: https://www.shellcheck.net/wiki/SC2046 -- Quote this to prevent word splitt... ``` </details> <details><summary>DOCKERFILE · hadolint: first lines of the output</summary> ```text See documentation on https://megalinter.io/9.4.0/descriptors/dockerfile_hadolint/ ----------------------------------------------- ❌ [ERROR] for workspace /workspace/khyretos/kk-engine Linter raw log: docker/android.Dockerfile:19 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check docker/appimage.Dockerfile:38 SC2016 info: Expressions don't expand in single quotes, use double quotes for that. docker/appimage.Dockerfile:51 DL3003 warning: Use WORKDIR to switch to a directory docker/appimage.Dockerfile:57 DL3003 warning: Use WORKDIR to switch to a directory docker/appimage.Dockerfile:63 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check docker/appimage.Dockerfile:63 DL3003 warning: Use WORKDIR to switch to a directory docker/appimage.Dockerfile:73 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check docker/appimage.Dockerfile:73 DL3003 warning: Use WORKDIR to switch to a directory docker/ci.Dockerfile:42 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check docker/ci.Dockerfile:56 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check docker/server/Dockerfile:22 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check docker/vm.Dockerfile:22 SC2086 info: Double quote to prevent globbing and word splitting. docker/vm.Dockerfile:29 DL3003 warning: Use WORKDIR to switch to a directory docker/vm.Dockerfile:29 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check website/Dockerfile:9 DL4006 warning: Set the SHELL option -o pipefail before RUN with a pipe in it. If you are using /bin/sh in an alpine image or if your shell is symlinked to busybox then consider explicitly setting your SHELL to /bin/ash, or disable this check ``` </details> <details><summary>REPOSITORY · trivy: first lines of the output</summary> ```text See documentation on https://megalinter.io/9.4.0/descriptors/repository_trivy/ ----------------------------------------------- ❌ [ERROR] for workspace /workspace/khyretos/kk-engine Linter raw log: 2026-10-26T13:22:53Z INFO [vulndb] Need to update DB 2026-10-26T13:22:53Z INFO [vulndb] Downloading vulnerability DB... 2026-10-26T13:22:53Z INFO [vulndb] Downloading artifact... repo="mirror.gcr.io/aquasec/trivy-db:2" 18.99 MiB / 129.73 MiB [-------->___________________________________________________] 14.64% ? p/s ?31.57 MiB / 129.73 MiB [-------------->_____________________________________________] 24.34% ? p/s ?42.73 MiB / 129.73 MiB [------------------->________________________________________] 32.94% ? p/s ?54.18 MiB / 129.73 MiB [------------------->___________________________] 41.76% 58.62 MiB p/s ETA 1s66.05 MiB / 129.73 MiB [----------------------->_______________________] 50.91% 58.62 MiB p/s ETA 1s76.84 MiB / 129.73 MiB [--------------------------->___________________] 59.23% 58.62 MiB p/s ETA 0s87.58 MiB / 129.73 MiB [------------------------------->_______________] 67.51% 58.43 MiB p/s ETA 0s98.29 MiB / 129.73 MiB [----------------------------------->___________] 75.77% 58.43 MiB p/s ETA 0s109.08 MiB / 129.73 MiB [-------------------------------------->_______] 84.09% 58.43 MiB p/s ETA 0s119.78 MiB / 129.73 MiB [------------------------------------------>___] 92.33% 58.13 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 58.13 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 58.13 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 55.44 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 55.44 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 55.44 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 51.87 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 51.87 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 51.87 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 48.52 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 48.52 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 48.52 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-------------------------------------------->] 100.00% 45.39 MiB p/s ETA 0s129.73 MiB / 129.73 MiB [-----------------------------------------------] 100.00% 29.69 MiB p/s 4.6s2026-10-26T13:22:58Z INFO [vulndb] Artifact successfully downloaded repo="mirror.gcr.io/aquasec/trivy-db:2" 2026-10-26T13:22:58Z INFO [vuln] Vulnerability scanning is enabled 2026-10-26T13:22:58Z INFO [misconfig] Misconfiguration scanning is enabled 2026-10-26T13:22:58Z INFO [checks-client] Need to update the checks bundle 2026-10-26T13:22:58Z INFO [checks-client] Downloading the checks bundle... 234.57 KiB / 234.57 KiB [---------------------------------------------------------] 100.00% ? p/s 0s2026-10-26T13:22:59Z WARN [rego] Module will be skipped as current version of Trivy is older than minimum trivy version required - please update Trivy to use this module file_path="root/.cache/trivy/policy/content/policies/cloud/policies/aws/cloudfront/enable_logging.rego" minimum_trivy_version="0.72.0" 2026-10-26T13:22:59Z ERROR [dockerfile scanner] Failed to parse file file_path="docker/server/Dockerfile.dockerignore" err="parse dockerfile instruction: parse instruction \".git\": unknown instruction: .git" 2026-10-26T13:22:59Z INFO Number of language-specific files num=0 2026-10-26T13:22:59Z INFO Detected config files num=9 Report Summary ┌──────────────────────────────┬────────────┬─────────────────┬───────────────────┐ │ Target │ Type │ Vulnerabilities │ Misconfigurations │ ├──────────────────────────────┼────────────┼─────────────────┼───────────────────┤ │ benchmarks/docker/Dockerfile │ dockerfile │ - │ 2 │ ├──────────────────────────────┼────────────┼─────────────────┼───────────────────┤ │ docker/android.Dockerfile │ dockerfile │ - │ 2 │ ├──────────────────────────────┼────────────┼─────────────────┼───────────────────┤ │ docker/appimage.Dockerfile │ dockerfile │ - │ 5 │ … ``` </details> 🧹 Formatting only (layout, no behaviour; the nightly lint-fix job applies these as a PR): YAML · prettier (57 files checked), BASH · shfmt (11 files checked), JSON · prettier (147 files checked) ✅ Clean: actionlint, git_diff, gitleaks, grype, jsonlint, secretlint, stylelint, trufflehog, xmllint <sub>MegaLinter on soucouyant · full logs in the Actions run · comment <code>/improve</code> for AI fix suggestions</sub>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
khyretos/kk-engine!131
No description provided.