Skip to content

Commit 3fad61d

Browse files
committed
fix(config): allow leading dash in wing names
The _SAFE_NAME_RE regex required wing names to start AND end with an alphanumeric. Auto-mined wings derived from CC transcript paths (e.g. -Volumes-codeXD-vlad-ozweb) start with a dash, so every read API that called sanitize_name failed with 'wing contains invalid characters'. The auto-miner bypassed the validator on writes, creating wings that no read API could enumerate. Backward-pass gnome's daily run silently did nothing (it logged the diagnosis itself: 'taxonomy reports 47483 drawers exist, but cannot list them'). Relaxes the leading-character class from [^\W_] (letter/digit only) to [\w-] (letter/digit/underscore/dash). Trailing constraint and path-traversal blocks (.., /, \, null bytes) unchanged.
1 parent 94f1689 commit 3fad61d

1 file changed

Lines changed: 35 additions & 6 deletions

File tree

mempalace/config.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
# in file paths, SQLite, or ChromaDB metadata.
1717

1818
MAX_NAME_LENGTH = 128
19-
_SAFE_NAME_RE = re.compile(r"^(?:[^\W_]|[^\W_][\w .'-]{0,126}[^\W_])$")
19+
# Allow leading dash/underscore for auto-mined transcript wings whose names
20+
# derive from filesystem paths (e.g. "-Volumes-codeXD-vlad-ozweb"). Trailing
21+
# character must still be alphanumeric to prevent "wing." / "wing-" artifacts.
22+
# Local patch — re-apply on `pip install --upgrade mempalace`. See drawer
23+
# wing=mempalace room=patches for context.
24+
_SAFE_NAME_RE = re.compile(r"^(?:[^\W_]|[\w-][\w .'-]{0,126}[^\W_])$")
2025

2126

2227
def sanitize_name(value: str, field_name: str = "name") -> str:
@@ -30,7 +35,9 @@ def sanitize_name(value: str, field_name: str = "name") -> str:
3035
value = value.strip()
3136

3237
if len(value) > MAX_NAME_LENGTH:
33-
raise ValueError(f"{field_name} exceeds maximum length of {MAX_NAME_LENGTH} characters")
38+
raise ValueError(
39+
f"{field_name} exceeds maximum length of {MAX_NAME_LENGTH} characters"
40+
)
3441

3542
# Block path traversal
3643
if ".." in value or "/" in value or "\\" in value:
@@ -63,7 +70,9 @@ def sanitize_kg_value(value: str, field_name: str = "value") -> str:
6370
value = value.strip()
6471

6572
if len(value) > MAX_NAME_LENGTH:
66-
raise ValueError(f"{field_name} exceeds maximum length of {MAX_NAME_LENGTH} characters")
73+
raise ValueError(
74+
f"{field_name} exceeds maximum length of {MAX_NAME_LENGTH} characters"
75+
)
6776

6877
if "\x00" in value:
6978
raise ValueError(f"{field_name} contains null bytes")
@@ -131,8 +140,26 @@ def sanitize_content(value: str, max_length: int = 100_000) -> str:
131140
"server",
132141
],
133142
"identity": ["identity", "name", "who am i", "persona", "self"],
134-
"family": ["family", "kids", "children", "daughter", "son", "parent", "mother", "father"],
135-
"creative": ["game", "gameplay", "player", "app", "design", "art", "music", "story"],
143+
"family": [
144+
"family",
145+
"kids",
146+
"children",
147+
"daughter",
148+
"son",
149+
"parent",
150+
"mother",
151+
"father",
152+
],
153+
"creative": [
154+
"game",
155+
"gameplay",
156+
"player",
157+
"app",
158+
"design",
159+
"art",
160+
"music",
161+
"story",
162+
],
136163
}
137164

138165

@@ -166,7 +193,9 @@ def __init__(self, config_dir=None):
166193
@property
167194
def palace_path(self):
168195
"""Path to the memory palace data directory."""
169-
env_val = os.environ.get("MEMPALACE_PALACE_PATH") or os.environ.get("MEMPAL_PALACE_PATH")
196+
env_val = os.environ.get("MEMPALACE_PALACE_PATH") or os.environ.get(
197+
"MEMPAL_PALACE_PATH"
198+
)
170199
if env_val:
171200
# Normalize: expand ~ and collapse .. to match the CLI --palace
172201
# code path (mcp_server.py:62) and prevent surprise redirection

0 commit comments

Comments
 (0)