@@ -788,6 +788,59 @@ def test_kg_stats(self, monkeypatch, config, palace_path, seeded_kg):
788788 result = tool_kg_stats ()
789789 assert result ["entities" ] >= 4
790790
791+ # --- Date validation at the MCP boundary (issue #1164) ---
792+
793+ def test_kg_add_rejects_invalid_valid_from (self , monkeypatch , config , palace_path , kg ):
794+ _patch_mcp_server (monkeypatch , config , kg )
795+ from mempalace .mcp_server import tool_kg_add
796+
797+ result = tool_kg_add (
798+ subject = "Alice" ,
799+ predicate = "likes" ,
800+ object = "coffee" ,
801+ valid_from = "Jan 2025" ,
802+ )
803+ assert result ["success" ] is False
804+ assert "valid_from" in result ["error" ]
805+ assert "ISO-8601" in result ["error" ]
806+
807+ def test_kg_query_rejects_invalid_as_of (self , monkeypatch , config , palace_path , seeded_kg ):
808+ _patch_mcp_server (monkeypatch , config , seeded_kg )
809+ from mempalace .mcp_server import tool_kg_query
810+
811+ result = tool_kg_query (entity = "Max" , as_of = "March 2026" )
812+ assert "error" in result
813+ assert "as_of" in result ["error" ]
814+
815+ def test_kg_invalidate_rejects_invalid_ended (self , monkeypatch , config , palace_path , seeded_kg ):
816+ _patch_mcp_server (monkeypatch , config , seeded_kg )
817+ from mempalace .mcp_server import tool_kg_invalidate
818+
819+ result = tool_kg_invalidate (
820+ subject = "Max" ,
821+ predicate = "does" ,
822+ object = "chess" ,
823+ ended = "yesterday" ,
824+ )
825+ assert result ["success" ] is False
826+ assert "ended" in result ["error" ]
827+
828+ def test_kg_query_rejects_partial_iso_dates (self , monkeypatch , config , palace_path , seeded_kg ):
829+ _patch_mcp_server (monkeypatch , config , seeded_kg )
830+ from mempalace .mcp_server import tool_kg_query
831+
832+ # Partial ISO dates are rejected: KG queries compare TEXT dates
833+ # lexicographically, so "2026-01-01" <= "2026" is False, which
834+ # silently excludes facts. Reject at the boundary — only YYYY-MM-DD
835+ # produces correct results.
836+ for value in ("2026" , "2026-03" ):
837+ result = tool_kg_query (entity = "Max" , as_of = value )
838+ assert "error" in result , f"accepted partial date { value !r} : { result } "
839+
840+ # Full ISO-8601 dates still pass.
841+ result = tool_kg_query (entity = "Max" , as_of = "2026-03-15" )
842+ assert "error" not in result , f"rejected valid date: { result } "
843+
791844
792845# ── Diary Tools ─────────────────────────────────────────────────────────
793846
0 commit comments