What happened?
_load_hallways() accepts both the current {"schema_version": 1, "hallways": [...]} envelope and the legacy bare-list format, but it does not validate the envelope payload or individual records before returning them. Core consumers then assume every element is a hallway dict with a usable ID, wing, and entity pair.
One malformed value can therefore block every valid hallway in the same file:
null, strings, numbers, lists, and partial dicts raise during .get() access or entity-pair sorting;
- a truthy non-list
hallways payload leaks dict keys or string characters through unfiltered listing and crashes filtered operations;
- a nonnumeric
co_occurrence_count can crash mempalace hallways while sorting mixed types;
- malformed
rooms values are unsafe for consumers that iterate room names;
- invalid UTF-8, JSON decoder limit errors, and escaped lone surrogates escape the intended corrupt-file/save-safe behavior.
Affected MCP list/delete calls surface as generic internal tool errors.
What did you expect?
The loader should preserve usable hallway records while skipping malformed content:
- require non-empty string
id, wing, entity_a, and entity_b fields;
- when present, require a numeric
co_occurrence_count and a list of string rooms;
- preserve unrelated optional fields when the record is safe to persist as UTF-8;
- support both the envelope and legacy bare-list formats;
- emit one aggregated warning containing only the path and skipped count, never record contents;
- diagnose unsupported root/payload types without auto-wrapping them;
- never rewrite the sidecar during a read.
A later successful mutation may naturally persist only the valid records through the existing atomic write path; an unsuccessful delete should preserve the original bytes.
How to reproduce:
- On current
develop, point the hallway resolver at a temporary file.
- Write:
{"schema_version": 1, "hallways": [null, {"id": "h1", "wing": "wing_a", "entity_a": "A", "entity_b": "B"}]}
- Call
list_hallways("wing_a"), delete_hallway("h1"), or compute_hallways_for_wing() with a qualifying entity pair.
- Each path raises
AttributeError: 'NoneType' object has no attribute 'get'.
- Separately, store one valid-shaped record with
"co_occurrence_count": "not-a-number" beside a numeric record and run mempalace hallways; sorting raises TypeError.
Environment:
- OS: macOS arm64
- Python version: 3.12.12
- MemPal version:
develop at 06cb6987f02610784fefbad4b2bd5d026d164ba6
What happened?
_load_hallways()accepts both the current{"schema_version": 1, "hallways": [...]}envelope and the legacy bare-list format, but it does not validate the envelope payload or individual records before returning them. Core consumers then assume every element is a hallway dict with a usable ID, wing, and entity pair.One malformed value can therefore block every valid hallway in the same file:
null, strings, numbers, lists, and partial dicts raise during.get()access or entity-pair sorting;hallwayspayload leaks dict keys or string characters through unfiltered listing and crashes filtered operations;co_occurrence_countcan crashmempalace hallwayswhile sorting mixed types;roomsvalues are unsafe for consumers that iterate room names;Affected MCP list/delete calls surface as generic internal tool errors.
What did you expect?
The loader should preserve usable hallway records while skipping malformed content:
id,wing,entity_a, andentity_bfields;co_occurrence_countand a list of stringrooms;A later successful mutation may naturally persist only the valid records through the existing atomic write path; an unsuccessful delete should preserve the original bytes.
How to reproduce:
develop, point the hallway resolver at a temporary file.{"schema_version": 1, "hallways": [null, {"id": "h1", "wing": "wing_a", "entity_a": "A", "entity_b": "B"}]}list_hallways("wing_a"),delete_hallway("h1"), orcompute_hallways_for_wing()with a qualifying entity pair.AttributeError: 'NoneType' object has no attribute 'get'."co_occurrence_count": "not-a-number"beside a numeric record and runmempalace hallways; sorting raisesTypeError.Environment:
developat06cb6987f02610784fefbad4b2bd5d026d164ba6