Skip to content

Environment::removeEntity leaves an entity present when it was added twice to one location #70

Closed

Description

@dmccoystephenson

Summary

Grid::removeEntity (src/grid.cpp:96) calls Location::removeEntity once per location, and Location::removeEntity (src/location.cpp:33) erases only the first matching pointer. An entity added twice to the same location therefore keeps one pointer in that location after removal, even though its ids have been reset.

addEntity and addEntityToLocation are documented as unchecked, so the double add itself is expected. The inconsistent state after removal is what is reported here.

Reproduction (traced through the source)

Environment environment(0, "Earth", 2);
Entity entity(0, "Daniel");
Location& location = environment.getGrid()->getLocationByCoordinates(0, 0);
environment.addEntityToLocation(entity, location);
environment.addEntityToLocation(entity, location);
environment.removeEntity(entity);

After removeEntity:

  • environment.isEntityPresent(entity) is true and environment.getNumEntities() is 1.
  • entity.getEnvironmentId() and entity.getGridId() are -1, and entity.getLocationId() is "N/S".
  • environment.moveEntityUp(0) throws std::runtime_error, because moveEntityInDirection calls getLocation("N/S") outside its try block (src/environment.cpp:127). The move methods are documented as throwing only when entityId names no entity in the environment.
  • moveEntityToNewLocation has the same root cause: its removal leaves the old pointer behind, so the entity ends up stored in both locations.

An entity added once each to two different locations is removed completely, because the loop visits both locations. Only the same-location case is affected.

Suggested fix

Grid::removeEntity could repeat the removal until the location no longer reports the entity present, or Location::removeEntity could erase every pointer with a matching id. Either choice should be weighed against the id-based matching described in the README's "Entity Identity" section, since a same-id twin stored in that location would be erased too.


This issue was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


drafted by Claude on behalf of Daniel Stephenson

Activity

  1. dmccoystephenson commented on Nov 4, 2026

    @dmccoystephenson
    MemberAuthor

    Reopened: this issue was closed by mistake. The body of PR #71 contained the phrase "does not close #70", and GitHub's closing-keyword matching treated "close #70" as a closing reference despite the negation.

    PR #71 did not fix this bug. It added Test 66, which pins the current behaviour, and it documented that behaviour in the README. Both should change when the fix lands. The CI run for PR #71 confirmed the reported state by execution: Test 66 passed, so one pointer survives removal, the ids are reset, and moveEntityUp throws. The moveEntityToNewLocation claim remains traced from source only.


    This comment was drafted during a Gardener session (https://github.com/Stephenson-Software/gardener).


    drafted by Claude on behalf of Daniel Stephenson

  2. added a commit that references this issue on Nov 5, 2026
    0d69d11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions