From f054bf25f139ceca91ad3918cee0a30f7c0e5343 Mon Sep 17 00:00:00 2001 From: popertots Date: Sat, 4 Apr 2026 12:21:52 +0100 Subject: [PATCH] Add session continuation prompt for next agent --- NEXT_SESSION_PROMPT.md | 159 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 NEXT_SESSION_PROMPT.md diff --git a/NEXT_SESSION_PROMPT.md b/NEXT_SESSION_PROMPT.md new file mode 100644 index 0000000..12a12c8 --- /dev/null +++ b/NEXT_SESSION_PROMPT.md @@ -0,0 +1,159 @@ +# Session Continuation Prompt + +## A) Starting Position + +The project had a working task system where dorfs would: +1. Get assigned jobs (FellTree, HaulCargo) +2. Walk to job locations +3. Chop trees +4. Haul logs + +**Last Known Good Commit:** The user started from commit `3c74a68` (Refactor job queue: add JobState enum, improve pathfinding fallback). However, the system was NOT fully working - dorfs would freeze because: +- The old provisional pathfinding used a node limit (4096) that would fail on distant jobs +- Job assignment was using provisional pathfinding to check "reachability" which is incorrect +- Jobs would stay `Unclaimed` forever because dorfs couldn't be assigned + +## B) Changes Made This Session and WHY + +### 1. New Traversal Distance Function (`src/entities/shared_systems/pathfinding.rs`) +**WHAT:** Added `calculate_traversal_distance()` - uses full A* with 15,000 node limit (not provisional) to check if a path actually exists. + +**WHY:** The old approach used `calculate_provisional_path()` which: +- Returns partial paths that hit node limits +- Was NOT designed for reachability checking +- Would return "no path" on distant jobs even though paths exist + +### 2. JobState Calculating (`src/entities/tasks/job_queue.rs`) +**WHAT:** Added `Calculating(Vec)` state to lock dorfs during pathfinding. + +**WHY:** Prevents race conditions where two jobs try to assign the same dorf. + +### 3. Candidate Filter Fix (`src/entities/tasks/job_pathfinding.rs`) +**WHAT:** Changed filter from `!queue.is_empty() && !matches!(state, Active)` to allow Idle tasks. + +```rust +// BEFORE: Only dorfs with empty queues +if !queue.is_empty() { return false; } + +// AFTER: Dorfs that are idle (empty queue OR Idle task) +let is_idle = queue.is_empty() + || current_task.map(|t| matches!(t, Task::Idle { .. })).unwrap_or(false); +let is_busy = matches!(*state, TaskState::Active) && !is_idle; +if is_busy { return false; } +``` + +**WHY:** The `job_assignment_system` gives Idle tasks to dorfs, then `task_executor_system` promotes them to Active. All dorfs had Active+Idle state, so they were ALL filtered out. + +### 4. Target Clearing Fix (`src/entities/tasks/job_pathfinding.rs`) +**WHAT:** Removed `ambulatory.target = None` from job assignment. + +**WHY:** The job_pathfinding_system was clearing `ambulatory.target` on assignment, but then the executor would set it, and the next frame job_pathfinding would clear it again. This oscillation prevented movement. + +### 5. HaulCargo Target Fix (`src/entities/tasks/executor.rs`) +**WHAT:** Added branch to set `ambulatory.target` when `approach.is_some()` and `target.is_none()`. + +```rust +} else if ambulatory.target.is_none() { + if let Some(approach_tile) = *approach { + ambulatory.target = Some(Vec3::new(...)); + ambulatory.current_path = None; + } +} +``` + +**WHY:** When `job_pathfinding_system` pre-computed the approach tile, the executor would skip the "find approach" block and never set the target. Dorfs had approach position but no path to walk there. + +## C) Current Plan for Improvement + +The architecture is correct: +1. `job_pathfinding_system` (FixedUpdate) - Finds idle dorfs, calculates traversal distances, assigns jobs with approach targets +2. `job_assignment_system` (FixedUpdate) - Gives Idle tasks to dorfs with empty queues +3. `task_executor_system` (FixedUpdate) - Executes tasks, handles movement via pathfinding + +**Planned improvements (NOT YET IMPLEMENTED):** +- Throttling: Only process N jobs per tick to prevent CPU spikes +- Expanding scope: Start with 5 nearest dorfs, expand to 20, then all if all fail +- Async pathfinding: Move expensive pathfinding to background threads + +## D) Current Issues and State + +### Last Test Result (output5.log): +- **Jobs ARE being assigned** - `[PATHFIND] SUCCESS` messages appeared +- **ChopTree works** - Trees are being chopped (120 tick countdown completes) +- **HaulCargo jobs created** - 8 HaulCargo jobs created after tree fell +- **BUG: `target=None`** - HaulCargo tasks showed `target=None` meaning no movement path was set + +### Last Fix Applied: +The HaulCargo target fix (commit `8e3e8b8`) should resolve the `target=None` issue. This fix was NOT tested yet. + +### Known Remaining Issues: +1. **Approach tile z-level mismatch** - The BFS finds standable tiles at cargo's z-level, but the dorf might be on a different floor. The z coordinate in approach might not match the dorf's current z. + +2. **Cargo position staleness** - If cargo moves after job is created, the job's `cargo_pos` is stale. + +3. **No pathfinding failure recovery** - If pathfinding fails, there's no retry or fallback. + +## E) Plan to Get to Working State + +**DO NOT MAKE MORE FIXES WITHOUT TESTING FIRST.** + +1. **Run the game with output logging** - Capture output6.log after the HaulCargo target fix. + +2. **Verify the fix works** - Look for: + - `[HAUL] {:?} setting target to approach {:?}` messages + - `target=Some(...)` instead of `target=None` + - Dorfs moving toward cargo (transform positions changing) + - `[HAUL] {:?} arrived at approach {:?}, picking up cargo` messages + - `[HAUL] {:?} picked up {:?} → hauling to {:?}` messages + +3. **If still broken** - Use targeted debug logging: + ```rust + info!("[DEBUG] approach={:?} target={:?} transform={:?}", approach, ambulatory.target, transform.translation); + ``` + Add this to `MovingToCargo` step in executor.rs to trace the exact state. + +4. **Check z-level issues** - If dorfs aren't moving, check if the approach tile is reachable. The approach z might not match the dorf's z: + - Dorf at (x, y, z=0) needs to reach cargo at (x, y, z=16) + - Approach tile should be adjacent to cargo AND reachable from dorf's z-level + +5. **Only after full working state** - Consider implementing: + - Throttling (MAX_JOBS_PER_TICK) + - Expanding scope for island scenarios + - Async pathfinding + +## Key Files to Focus On + +``` +src/entities/tasks/job_pathfinding.rs - Job assignment, pathfinding trigger +src/entities/tasks/executor.rs - Task execution, movement triggers +src/entities/shared_systems/pathfinding.rs - calculate_traversal_distance() +src/entities/tasks/job_queue.rs - JobState, job management +``` + +## Debug Commands + +```bash +# Check compilation +cargo check 2>&1 | tail -20 + +# Run with logging +cargo run 2>&1 | tee output.log + +# Search for specific log patterns +grep -E "\[PATHFIND\] SUCCESS" output.log +grep -E "\[HAUL\]" output.log | tail -50 +grep -E "target=None" output.log | head -10 +grep -E "setting target" output.log +``` + +## Critical Context: The Z-Level Problem + +The world has multiple Z-levels (not flat). A tree at position (32, 32, 16) has z=16. The trunk might be at surface level while nearby standable tiles could be at z=0, z=16, or z=32. + +The `find_all_standable_adjacent` BFS (in executor.rs) searches for standable tiles at the cargo's z-level. This works for 2D but may fail for 3D if: +1. Cargo is on z=16 surface +2. Approach tile found at z=16 +3. But the dorf is at z=0 underground +4. Pathfinding z=0 → z=16 might fail or not exist + +**IF dorfs still freeze after the current fix, the z-level is the next place to investigate.** \ No newline at end of file