fix: unlike not supported — wallmood is idempotent SET, not toggle (v0.4.5)

Extensive FW_DEBUG=1 testing revealed:
- wallmood with moodType=STAR is an idempotent SET operation, not a toggle
- Tested: all moodType variations, moodStarShortcut param, 9 alternative
  endpoints — none could remove a like
- Service Worker in the web app prevents intercepting the real unlike payload
- like=False now returns a clear error; like=True continues to work correctly
- SPEC.md updated with full investigation notes and ruled-out approaches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 16:02:08 +02:00
parent a3274b349a
commit da5be55070
4 changed files with 48 additions and 17 deletions
+23 -10
View File
@@ -478,22 +478,36 @@ def delete_task(task_id: str) -> str:
@mcp.tool()
def like_post(post_id: str, like: bool = True) -> str:
"""Like or unlike a wall post/activity.
"""Like a wall post/activity with a STAR mood.
Note: Unlike (like=False) is not yet supported. The Family Wall API offers
no discoverable endpoint or parameter to remove a like. Passing like=False
returns an error without making any API call.
Args:
post_id: Wall post ID from get_activities (e.g. ``wall/23431854_31119189``).
like: ``True`` to like the post, ``False`` to unlike.
like: Must be ``True``. ``False`` is reserved for future unlike support.
Returns:
JSON success indicator or an error message.
"""
# wallmood toggles the STAR mood on a wall post (same endpoint for like/unlike).
# Unlike is not yet supported: extensive FW_DEBUG=1 testing showed that
# wallmood with moodType="STAR" is an idempotent SET operation (not a toggle).
# Tested and ruled out: moodType variations ("NONE", "REMOVE", "DELETE", ""),
# moodStarShortcut parameter, and alternative endpoints (all return 502).
# See SPEC.md for full investigation notes.
if not like:
return json.dumps(
{"error": "Unlike is not yet supported. The unlike mechanism is unknown."},
ensure_ascii=False,
indent=2,
)
# Verified via FW_DEBUG=1:
# - Parameter 'wall_message_id': post ID as returned by get_activities
# - Parameter 'moodType': "STAR" (Family Wall's internal like type)
# - Response a00.r.r: full wall message object with moodMap showing current state
# The endpoint is a toggle — calling it again removes the mood.
# 'like=False' relies on this toggle behaviour (call again to undo).
# - Parameter 'moodType': "STAR" (Family Wall's internal like type; "LIKE" is silently
# mapped to "STAR" server-side — use "STAR" directly)
# - Response a00.r.r: full wall message object with moodMap showing resulting state
params: dict[str, Any] = {
"wall_message_id": post_id,
"moodType": "STAR",
@@ -504,7 +518,7 @@ def like_post(post_id: str, like: bool = True) -> str:
except RuntimeError as exc:
return f"Error: {exc}"
# Extract moodMap from response to determine actual resulting state.
# Extract moodMap from the response to confirm the like was recorded.
try:
wall_obj = data["a00"]["r"]["r"]
if not isinstance(wall_obj, dict):
@@ -518,8 +532,7 @@ def like_post(post_id: str, like: bool = True) -> str:
indent=2,
)
# Determine whether the post is now liked by checking if any entry in
# moodMap contains "STAR" (the server-side representation of a like).
# Confirm the STAR is present in moodMap (server-side representation of a like).
now_liked = any("STAR" in moods for moods in mood_map.values())
return json.dumps(