Navmesh obstacles: tiled navmeshes that doors and crates change (ENG-F70) #119

Merged
kompas-review merged 1 commit from khyretos/claude/dynamic-navmesh into main 2026-10-25 15:46:52 +01:00 AGit
Owner

Requested by Kees · project thread

What (ENG-F70)

A navmesh that changes while the game runs: a door that shuts, a crate pushed into a doorway, a parked cart.

  • NavMesh::buildDynamic(vertices, indices, settings, {tileSize, maxObstacles}) builds the level as square tiles (16 m by default) in a DetourTileCache. DetourTileCache was already compiled in as part of recastnavigation and is wrapped now. Every tile's floors become layers the cache keeps, stored uncompressed (a byte or two per cell).
  • addBoxObstacle(centre, halfExtents, yaw) (the engine's yaw, as glm::rotate about +y) and addCylinderObstacle(base, radius, height) cut a hole. removeObstacle(id) fills it again (once). update() rebuilds only the touched tiles, a few per call, so call it every frame; updateAll() loops. revision() goes up when the surface changed. Also obstacleCount() and tileCount().
  • Every query (findPath, walkable, moveAlongSurface, nearestPoint, randomPointNear, debug triangles) works unchanged on either kind. save() is empty for a dynamic mesh, because it is rebuilt from the level.
  • AiWorld finds an agent's path again when the mesh's revision changes.
  • Docs: AI.md "Doors, crates and carts: a navmesh that changes" and GAPS F70. It stays 🟡: off-mesh links, area costs and obstacles from Lua are next.

Tests

  • 4 new tests in test_ai.cpp:
    • A 5 × 5-tile dynamic mesh finds the same path through a doorway as a built one, and walks across tile borders but not through the wall.
    • A crate in the doorway makes the path partial (it stops at the crate) until the crate is removed; removing it twice is refused.
    • A path bends round a pillar.
    • A box turned 45° blocks its own diagonal and not the other one; bad obstacles are refused.
    • A dog heading for a door that shuts walks round by the far door, never through the shut one.
  • All Ai* tests pass (36).

🤖 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)_ ## What (ENG-F70) A navmesh that changes while the game runs: a door that shuts, a crate pushed into a doorway, a parked cart. - `NavMesh::buildDynamic(vertices, indices, settings, {tileSize, maxObstacles})` builds the level as square tiles (16 m by default) in a DetourTileCache. DetourTileCache was already compiled in as part of recastnavigation and is wrapped now. Every tile's floors become layers the cache keeps, stored uncompressed (a byte or two per cell). - `addBoxObstacle(centre, halfExtents, yaw)` (the engine's yaw, as `glm::rotate` about +y) and `addCylinderObstacle(base, radius, height)` cut a hole. `removeObstacle(id)` fills it again (once). `update()` rebuilds only the touched tiles, a few per call, so call it every frame; `updateAll()` loops. `revision()` goes up when the surface changed. Also `obstacleCount()` and `tileCount()`. - Every query (`findPath`, `walkable`, `moveAlongSurface`, `nearestPoint`, `randomPointNear`, debug triangles) works unchanged on either kind. `save()` is empty for a dynamic mesh, because it is rebuilt from the level. - `AiWorld` finds an agent's path again when the mesh's revision changes. - Docs: AI.md "Doors, crates and carts: a navmesh that changes" and GAPS F70. It stays 🟡: off-mesh links, area costs and obstacles from Lua are next. ## Tests - 4 new tests in `test_ai.cpp`: - A 5 × 5-tile dynamic mesh finds the same path through a doorway as a built one, and walks across tile borders but not through the wall. - A crate in the doorway makes the path partial (it stops at the crate) until the crate is removed; removing it twice is refused. - A path bends round a pillar. - A box turned 45° blocks its own diagonal and not the other one; bad obstacles are refused. - A dog heading for a door that shuts walks round by the far door, never through the shut one. - All `Ai*` tests pass (36). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
Navmesh obstacles: tiled navmeshes that doors and crates change (ENG-F70)
All checks were successful
review / pr-agent PR-Agent reviewed this commit
CI / dependencies (pull_request) Successful in 4s
CI / std-includes (pull_request) Successful in 12s
CI / shipping-build (pull_request) Successful in 12m52s
Benchmarks / benchmarks (pull_request) Successful in 3m0s
Docs site / site (pull_request) Successful in 9s
lint / megalinter (pull_request) Successful in 1m0s
CI / build-test-and-coverage (pull_request) Successful in 1h10m56s
CI / release-build (pull_request) Successful in 43m59s
Windows (native) / build (pull_request) Successful in 10m29s
CI / android (pull_request) Successful in 30m5s
Windows (native) / test (pull_request) Successful in 7m17s
Windows (native) / publish (pull_request) Has been skipped
kk / all-checks All 13 checks passed
7d23a53286
NavMesh::buildDynamic builds the level as square tiles in a DetourTileCache.
addBoxObstacle (turned by the engine's yaw) and addCylinderObstacle cut holes,
removeObstacle fills them, and update() rebuilds only the touched tiles, a
few per call. Queries are unchanged. revision() counts the changes, and
AiWorld finds an agent's path again when it moves on, so agents go round a
door that shuts.

Tests: a dynamic mesh answers like a built one, a crate in a doorway blocks
the path until it is removed, paths bend round a pillar, a turned box blocks
its own diagonal and not the other, and a dog takes the far door when the
near one shuts. docs/AI.md; GAPS F70 updated.

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-25 04:37:32 +01:00
Collaborator

Title

Navmesh obstacles: tiled navmeshes that doors and crates change (ENG-F70)


User description

Requested by Kees · project thread

What (ENG-F70)

A navmesh that changes while the game runs: a door that shuts, a crate pushed into a doorway, a parked cart.

  • NavMesh::buildDynamic(vertices, indices, settings, {tileSize, maxObstacles}) builds the level as square tiles (16 m by default) in a DetourTileCache. DetourTileCache was already compiled in as part of recastnavigation and is wrapped now. Every tile's floors become layers the cache keeps, stored uncompressed (a byte or two per cell).
  • addBoxObstacle(centre, halfExtents, yaw) (the engine's yaw, as glm::rotate about +y) and addCylinderObstacle(base, radius, height) cut a hole. removeObstacle(id) fills it again (once). update() rebuilds only the touched tiles, a few per call, so call it every frame; updateAll() loops. revision() goes up when the surface changed. Also obstacleCount() and tileCount().
  • Every query (findPath, walkable, moveAlongSurface, nearestPoint, randomPointNear, debug triangles) works unchanged on either kind. save() is empty for a dynamic mesh, because it is rebuilt from the level.
  • AiWorld finds an agent's path again when the mesh's revision changes.
  • Docs: AI.md "Doors, crates and carts: a navmesh that changes" and GAPS F70. It stays 🟡: off-mesh links, area costs and obstacles from Lua are next.

Tests

  • 4 new tests in test_ai.cpp:
    • A 5 × 5-tile dynamic mesh finds the same path through a doorway as a built one, and walks across tile borders but not through the wall.
    • A crate in the doorway makes the path partial (it stops at the crate) until the crate is removed; removing it twice is refused.
    • A path bends round a pillar.
    • A box turned 45° blocks its own diagonal and not the other one; bad obstacles are refused.
    • A dog heading for a door that shuts walks round by the far door, never through the shut one.
  • All Ai* tests pass (36).

🤖 Generated with Claude Code

https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7


PR Type

Bug fix, Enhancement


Description

  • Adds tiled dynamic navmeshes via DetourTileCache

  • Enables runtime obstacles like doors and crates

  • Agents re-path when the walkable surface changes


Diagram Walkthrough

flowchart TD
  A["Level Geometry"] --> B["buildDynamic Tiles"]
  B --> C["addBoxObstacle"]
  B --> D["addCylinderObstacle"]
  C --> E["update Tiles"]
  D --> E
  E --> F["revision Change"]
  F -.->|"Agent Repath"| G["AiWorld Pathfinding"]

File Walkthrough

Relevant files
Enhancement
3 files
NavMesh.h
Declares buildDynamic, obstacle methods and revision         
+35/-1   
AiWorld.h
Adds pathRevision to Agent for dynamic mesh tracking         
+1/-0     
NavMesh.cpp
Implements tiled dynamic navmesh and obstacle management 
+296/-15
Bug fix
1 files
AiWorld.cpp
Re-finds paths when NavMesh revision changes                         
+2/-1     
Tests
1 files
test_ai.cpp
Tests dynamic mesh, obstacles and agent re-pathing             
+134/-0 
Documentation
2 files
AI.md
Documents dynamic navmesh usage and limitations                   
+25/-2   
GAPS.md
Updates ENG-F70 status to done for tiled navmesh                 
+1/-1     

## Title Navmesh obstacles: tiled navmeshes that doors and crates change (ENG-F70) ___ ### **User description** <!-- claude-projects-attribution: {"github_login":"Khyretos"} --> _Requested by **Kees** · [project thread](https://claude.ai/code/project/chan_01Ds4PKvSLCNCCKr5TJxrV2A?thread=cmsg_01Ds4PKvSLCNCCKr5TJxrV2ABb2WaYyLkc7eUMNFVK1p2Z)_ ## What (ENG-F70) A navmesh that changes while the game runs: a door that shuts, a crate pushed into a doorway, a parked cart. - `NavMesh::buildDynamic(vertices, indices, settings, {tileSize, maxObstacles})` builds the level as square tiles (16 m by default) in a DetourTileCache. DetourTileCache was already compiled in as part of recastnavigation and is wrapped now. Every tile's floors become layers the cache keeps, stored uncompressed (a byte or two per cell). - `addBoxObstacle(centre, halfExtents, yaw)` (the engine's yaw, as `glm::rotate` about +y) and `addCylinderObstacle(base, radius, height)` cut a hole. `removeObstacle(id)` fills it again (once). `update()` rebuilds only the touched tiles, a few per call, so call it every frame; `updateAll()` loops. `revision()` goes up when the surface changed. Also `obstacleCount()` and `tileCount()`. - Every query (`findPath`, `walkable`, `moveAlongSurface`, `nearestPoint`, `randomPointNear`, debug triangles) works unchanged on either kind. `save()` is empty for a dynamic mesh, because it is rebuilt from the level. - `AiWorld` finds an agent's path again when the mesh's revision changes. - Docs: AI.md "Doors, crates and carts: a navmesh that changes" and GAPS F70. It stays 🟡: off-mesh links, area costs and obstacles from Lua are next. ## Tests - 4 new tests in `test_ai.cpp`: - A 5 × 5-tile dynamic mesh finds the same path through a doorway as a built one, and walks across tile borders but not through the wall. - A crate in the doorway makes the path partial (it stops at the crate) until the crate is removed; removing it twice is refused. - A path bends round a pillar. - A box turned 45° blocks its own diagonal and not the other one; bad obstacles are refused. - A dog heading for a door that shuts walks round by the far door, never through the shut one. - All `Ai*` tests pass (36). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7 ___ ### **PR Type** Bug fix, Enhancement ___ ### **Description** - Adds tiled dynamic navmeshes via DetourTileCache - Enables runtime obstacles like doors and crates - Agents re-path when the walkable surface changes ___ ### Diagram Walkthrough ```mermaid flowchart TD A["Level Geometry"] --> B["buildDynamic Tiles"] B --> C["addBoxObstacle"] B --> D["addCylinderObstacle"] C --> E["update Tiles"] D --> E E --> F["revision Change"] F -.->|"Agent Repath"| G["AiWorld Pathfinding"] ``` <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>3 files</summary><table> <tr> <td><strong>NavMesh.h</strong><dd><code>Declares buildDynamic, obstacle methods and revision</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/119/head/engine/include/kke/ai/NavMesh.h">+35/-1</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>AiWorld.h</strong><dd><code>Adds pathRevision to Agent for dynamic mesh tracking</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/119/head/engine/include/kke/ai/AiWorld.h">+1/-0</a>&nbsp; &nbsp; &nbsp; </td> </tr> <tr> <td><strong>NavMesh.cpp</strong><dd><code>Implements tiled dynamic navmesh and obstacle management</code>&nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/119/head/engine/src/ai/NavMesh.cpp">+296/-15</a></td> </tr> </table></details></td></tr><tr><td><strong>Bug fix</strong></td><td><details><summary>1 files</summary><table> <tr> <td><strong>AiWorld.cpp</strong><dd><code>Re-finds paths when NavMesh revision changes</code>&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/119/head/engine/src/ai/AiWorld.cpp">+2/-1</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_ai.cpp</strong><dd><code>Tests dynamic mesh, obstacles and agent re-pathing</code>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </dd></td> <td><a href="https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/119/head/tests/test_ai.cpp">+134/-0</a>&nbsp; </td> </tr> </table></details></td></tr><tr><td><strong>Documentation</strong></td><td><details><summary>2 files</summary><table> <tr> <td><strong>AI.md</strong><dd><code>Documents dynamic navmesh usage and limitations</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/119/head/docs/AI.md">+25/-2</a>&nbsp; &nbsp; </td> </tr> <tr> <td><strong>GAPS.md</strong><dd><code>Updates ENG-F70 status to done for tiled navmesh</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/119/head/docs/GAPS.md">+1/-1</a>&nbsp; &nbsp; &nbsp; </td> </tr> </table></details></td></tr></tr></tbody></table> </details> ___
Collaborator

PR Reviewer Guide 🔍

📋 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: 3 🔵🔵🔵⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Potential Infinite Loop in update()

In the update() method of NavMesh, if m->cache->update() returns a failure status (DT_FAILURE), the function returns false immediately. However, the dirty flag is only set to true if m->dirty was already true before this call. If an obstacle is added or removed, dirty becomes true, but if the subsequent update() call fails, the revision counter is not incremented and the dirty state remains true. This could lead to repeated failed update attempts without progress, potentially causing agents to get stuck or the system to hang if called in a tight loop without checking the return value. The logic should ensure that a failed update does not leave the mesh in a permanently dirty state without attempting recovery or signaling an error condition more explicitly.

if (tn.serial <= a.lastNoise || tn.noise.source == a.id) continue;
const float h = hearingStrength(a.position, se, tn.noise);
if (h <= 0.0f) continue;
emit({ AiEvent::Kind::Heard, a.id, tn.noise.source, tn.noise.position, {} });
if (tn.noise.source && has(tn.noise.source)) addStim(tn.noise.source, h, tn.noise.position, glm::vec3(0.0f), SenseHearing);
Missing Validation for Dynamic Mesh Obstacles

The addBoxObstacle and addCylinderObstacle functions check for !m->cache before adding obstacles. However, there is no explicit check to ensure the dynamic mesh is actually valid or initialized correctly beyond just having a non-null cache pointer. If buildDynamic fails partially or leaves the cache in an inconsistent state, these functions might still attempt to add obstacles, leading to undefined behavior or silent failures. Additionally, the removeObstacle function checks !m->obstacles.count(id) but does not verify if the obstacle is currently active in the tile cache, which could lead to attempting to remove an obstacle that was never successfully added or has already been removed.

NavMesh::ObstacleId NavMesh::addBoxObstacle(const glm::vec3& centre, const glm::vec3& halfExtents, float yawRadians) {
    if (!m->cache || !(halfExtents.x > 0.0f && halfExtents.y > 0.0f && halfExtents.z > 0.0f) ||
        !std::isfinite(centre.x + centre.y + centre.z + yawRadians))
        return 0;
    dtObstacleRef ref = 0;
    float c[3] = { centre.x, centre.y, centre.z }, h[3] = { halfExtents.x, halfExtents.y, halfExtents.z };
    // Detour's yaw turns +x towards -z, as glm::rotate about +y does.
    if (dtStatusFailed(m->cache->addBoxObstacle(c, h, yawRadians, &ref))) return 0;
    m->obstacles.insert(ref);
    m->dirty = true;
    return ref;
}

bool NavMesh::removeObstacle(ObstacleId id) {
    if (!m->cache || !m->obstacles.count(id)) return false;
    if (dtStatusFailed(m->cache->removeObstacle(id))) return false; // too many changes waiting: update() first
    m->obstacles.erase(id);
    m->dirty = true;
    return true;
## PR Reviewer Guide 🔍 <!-- pr-agent:review:full --> 📋 **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>: 3 🔵🔵🔵⚪⚪</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>Recommended focus areas for review</strong><br><br> <details><summary><a href='https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/119/head/engine/src/ai/AiWorld.cpp#L438-L442'><strong>Potential Infinite Loop in update()</strong></a> In the `update()` method of NavMesh, if `m->cache->update()` returns a failure status (DT_FAILURE), the function returns false immediately. However, the `dirty` flag is only set to true if `m->dirty` was already true before this call. If an obstacle is added or removed, `dirty` becomes true, but if the subsequent `update()` call fails, the revision counter is not incremented and the dirty state remains true. This could lead to repeated failed update attempts without progress, potentially causing agents to get stuck or the system to hang if called in a tight loop without checking the return value. The logic should ensure that a failed update does not leave the mesh in a permanently dirty state without attempting recovery or signaling an error condition more explicitly. </summary> ```c++ if (tn.serial <= a.lastNoise || tn.noise.source == a.id) continue; const float h = hearingStrength(a.position, se, tn.noise); if (h <= 0.0f) continue; emit({ AiEvent::Kind::Heard, a.id, tn.noise.source, tn.noise.position, {} }); if (tn.noise.source && has(tn.noise.source)) addStim(tn.noise.source, h, tn.noise.position, glm::vec3(0.0f), SenseHearing); ``` </details> <details><summary><a href='https://git.kreative-kompas.com/khyretos/kk-engine/src/branch/refs/pull/119/head/engine/src/ai/NavMesh.cpp#L409-L427'><strong>Missing Validation for Dynamic Mesh Obstacles</strong></a> The `addBoxObstacle` and `addCylinderObstacle` functions check for `!m->cache` before adding obstacles. However, there is no explicit check to ensure the dynamic mesh is actually valid or initialized correctly beyond just having a non-null cache pointer. If `buildDynamic` fails partially or leaves the cache in an inconsistent state, these functions might still attempt to add obstacles, leading to undefined behavior or silent failures. Additionally, the `removeObstacle` function checks `!m->obstacles.count(id)` but does not verify if the obstacle is currently active in the tile cache, which could lead to attempting to remove an obstacle that was never successfully added or has already been removed. </summary> ```c++ NavMesh::ObstacleId NavMesh::addBoxObstacle(const glm::vec3& centre, const glm::vec3& halfExtents, float yawRadians) { if (!m->cache || !(halfExtents.x > 0.0f && halfExtents.y > 0.0f && halfExtents.z > 0.0f) || !std::isfinite(centre.x + centre.y + centre.z + yawRadians)) return 0; dtObstacleRef ref = 0; float c[3] = { centre.x, centre.y, centre.z }, h[3] = { halfExtents.x, halfExtents.y, halfExtents.z }; // Detour's yaw turns +x towards -z, as glm::rotate about +y does. if (dtStatusFailed(m->cache->addBoxObstacle(c, h, yawRadians, &ref))) return 0; m->obstacles.insert(ref); m->dirty = true; return ref; } bool NavMesh::removeObstacle(ObstacleId id) { if (!m->cache || !m->obstacles.count(id)) return false; if (dtStatusFailed(m->cache->removeObstacle(id))) return false; // too many changes waiting: update() first m->obstacles.erase(id); m->dirty = true; return true; ``` </details> </td></tr> </table> <!-- pr-agent-review-state:v1 {"findings":[{"body":"**Missing Validation for Dynamic Mesh Obstacles**\n\nThe `addBoxObstacle` and `addCylinderObstacle` functions check for `!m->cache` before adding obstacles. However, there is no explicit check to ensure the dynamic mesh is actually valid or initialized correctly beyond just having a non-null cache pointer. If `buildDynamic` fails partially or leaves the cache in an inconsistent state, these functions might still attempt to add obstacles, leading to undefined behavior or silent failures. Additionally, the `removeObstacle` function checks `!m->obstacles.count(id)` but does not verify if the obstacle is currently active in the tile cache, which could lead to attempting to remove an obstacle that was never successfully added or has already been removed.","finding_id":"1320b7c6fbcb","first_seen":"2026-10-25T03:39:43.492723Z","last_seen":"2026-10-25T03:39:43.492723Z","last_seen_head_sha":"7d23a53286ff5b0ef38d3dd59efc574e0b7ea39b","line_end":427,"line_start":409,"path":"engine/src/ai/NavMesh.cpp","state":"ACTIVE"},{"body":"**Potential Infinite Loop in update()**\n\nIn the `update()` method of NavMesh, if `m->cache->update()` returns a failure status (DT_FAILURE), the function returns false immediately. However, the `dirty` flag is only set to true if `m->dirty` was already true before this call. If an obstacle is added or removed, `dirty` becomes true, but if the subsequent `update()` call fails, the revision counter is not incremented and the dirty state remains true. This could lead to repeated failed update attempts without progress, potentially causing agents to get stuck or the system to hang if called in a tight loop without checking the return value. The logic should ensure that a failed update does not leave the mesh in a permanently dirty state without attempting recovery or signaling an error condition more explicitly.","finding_id":"5684e490515f","first_seen":"2026-10-25T03:39:43.492723Z","last_seen":"2026-10-25T03:39:43.492723Z","last_seen_head_sha":"7d23a53286ff5b0ef38d3dd59efc574e0b7ea39b","line_end":442,"line_start":438,"path":"engine/src/ai/AiWorld.cpp","state":"ACTIVE"}],"last_run":{"complete":true,"excluded_files":[],"head_sha":"7d23a53286ff5b0ef38d3dd59efc574e0b7ea39b","kind":"full","run_id":"https://git.kreative-kompas.com/khyretos/kk-engine/commit/7d23a53286ff5b0ef38d3dd59efc574e0b7ea39b"},"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 · ❌ 37 problems in 6 checks · 🧹 3 formatting checks to tidy

Nothing here blocks the merge (report only).

Check Errors Warnings Files
❌ MARKDOWN · markdownlint 23 0 250
❌ CPP · cppcheck 9 0 895
❌ YAML · yamllint 2 0 56
❌ 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/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]
games/racing/README.md:78:32 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/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
✅ [SUCCESS] engine/include/kke/Buffer.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-25T13:15:06Z	INFO	[vulndb] Need to update DB
2026-10-25T13:15:06Z	INFO	[vulndb] Downloading vulnerability DB...
2026-10-25T13:15:06Z	INFO	[vulndb] Downloading artifact...	repo="mirror.gcr.io/aquasec/trivy-db:2"
19.62 MiB / 129.70 MiB [--------->__________________________________________________] 15.13% ? p/s ?40.81 MiB / 129.70 MiB [------------------>_________________________________________] 31.47% ? p/s ?50.29 MiB / 129.70 MiB [----------------------->____________________________________] 38.77% ? p/s ?58.14 MiB / 129.70 MiB [--------------------->_________________________] 44.83% 64.57 MiB p/s ETA 1s65.86 MiB / 129.70 MiB [----------------------->_______________________] 50.78% 64.57 MiB p/s ETA 0s73.52 MiB / 129.70 MiB [-------------------------->____________________] 56.69% 64.57 MiB p/s ETA 0s81.49 MiB / 129.70 MiB [----------------------------->_________________] 62.83% 62.91 MiB p/s ETA 0s89.36 MiB / 129.70 MiB [-------------------------------->______________] 68.90% 62.91 MiB p/s ETA 0s97.44 MiB / 129.70 MiB [----------------------------------->___________] 75.13% 62.91 MiB p/s ETA 0s104.76 MiB / 129.70 MiB [------------------------------------->________] 80.78% 61.35 MiB p/s ETA 0s112.19 MiB / 129.70 MiB [--------------------------------------->______] 86.50% 61.35 MiB p/s ETA 0s119.61 MiB / 129.70 MiB [------------------------------------------>___] 92.23% 61.35 MiB p/s ETA 0s127.11 MiB / 129.70 MiB [--------------------------------------------->] 98.01% 59.80 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 59.80 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 59.80 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 56.22 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 56.22 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 56.22 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 52.59 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 52.59 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 52.59 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 49.20 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 49.20 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 49.20 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 46.02 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 46.02 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 46.02 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 43.06 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 43.06 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 43.06 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-----------------------------------------------] 100.00% 22.30 MiB p/s 6.0s2026-10-25T13:15:12Z	INFO	[vulndb] Artifact successfully downloaded	repo="mirror.gcr.io/aquasec/trivy-db:2"
2026-10-25T13:15:12Z	INFO	[vuln] Vulnerability scanning is enabled
2026-10-25T13:15:12Z	INFO	[misconfig] Misconfiguration scanning is enabled
2026-10-25T13:15:12Z	INFO	[checks-client] Need to update the checks bundle
2026-10-25T13:15:12Z	INFO	[checks-client] Downloading the checks bundle...
234.57 KiB / 234.57 KiB [---------------------------------------------------------] 100.00% ? p/s 0s2026-10-25T13:15:13Z	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-25T13:15:13Z	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-25T13:15:13Z	INFO	Number of language-specific files	num=0
2026-10-25T13:15:13Z	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 (56 files checked), BASH · shfmt (11 files checked), JSON · prettier (145 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 · ❌ 37 problems in 6 checks · 🧹 3 formatting checks to tidy Nothing here blocks the merge (report only). | | Check | Errors | Warnings | Files | |---|---|---:|---:|---:| | ❌ | MARKDOWN · markdownlint | 23 | 0 | 250 | | ❌ | CPP · cppcheck | 9 | 0 | 895 | | ❌ | YAML · yamllint | 2 | 0 | 56 | | ❌ | 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/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] games/racing/README.md:78:32 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/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 ✅ [SUCCESS] engine/include/kke/Buffer.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-25T13:15:06Z INFO [vulndb] Need to update DB 2026-10-25T13:15:06Z INFO [vulndb] Downloading vulnerability DB... 2026-10-25T13:15:06Z INFO [vulndb] Downloading artifact... repo="mirror.gcr.io/aquasec/trivy-db:2" 19.62 MiB / 129.70 MiB [--------->__________________________________________________] 15.13% ? p/s ?40.81 MiB / 129.70 MiB [------------------>_________________________________________] 31.47% ? p/s ?50.29 MiB / 129.70 MiB [----------------------->____________________________________] 38.77% ? p/s ?58.14 MiB / 129.70 MiB [--------------------->_________________________] 44.83% 64.57 MiB p/s ETA 1s65.86 MiB / 129.70 MiB [----------------------->_______________________] 50.78% 64.57 MiB p/s ETA 0s73.52 MiB / 129.70 MiB [-------------------------->____________________] 56.69% 64.57 MiB p/s ETA 0s81.49 MiB / 129.70 MiB [----------------------------->_________________] 62.83% 62.91 MiB p/s ETA 0s89.36 MiB / 129.70 MiB [-------------------------------->______________] 68.90% 62.91 MiB p/s ETA 0s97.44 MiB / 129.70 MiB [----------------------------------->___________] 75.13% 62.91 MiB p/s ETA 0s104.76 MiB / 129.70 MiB [------------------------------------->________] 80.78% 61.35 MiB p/s ETA 0s112.19 MiB / 129.70 MiB [--------------------------------------->______] 86.50% 61.35 MiB p/s ETA 0s119.61 MiB / 129.70 MiB [------------------------------------------>___] 92.23% 61.35 MiB p/s ETA 0s127.11 MiB / 129.70 MiB [--------------------------------------------->] 98.01% 59.80 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 59.80 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 59.80 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 56.22 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 56.22 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 56.22 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 52.59 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 52.59 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 52.59 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 49.20 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 49.20 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 49.20 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 46.02 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 46.02 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 46.02 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 43.06 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 43.06 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-------------------------------------------->] 100.00% 43.06 MiB p/s ETA 0s129.70 MiB / 129.70 MiB [-----------------------------------------------] 100.00% 22.30 MiB p/s 6.0s2026-10-25T13:15:12Z INFO [vulndb] Artifact successfully downloaded repo="mirror.gcr.io/aquasec/trivy-db:2" 2026-10-25T13:15:12Z INFO [vuln] Vulnerability scanning is enabled 2026-10-25T13:15:12Z INFO [misconfig] Misconfiguration scanning is enabled 2026-10-25T13:15:12Z INFO [checks-client] Need to update the checks bundle 2026-10-25T13:15:12Z INFO [checks-client] Downloading the checks bundle... 234.57 KiB / 234.57 KiB [---------------------------------------------------------] 100.00% ? p/s 0s2026-10-25T13:15:13Z 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-25T13:15:13Z 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-25T13:15:13Z INFO Number of language-specific files num=0 2026-10-25T13:15:13Z 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 (56 files checked), BASH · shfmt (11 files checked), JSON · prettier (145 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!119
No description provided.