Przeglądaj źródła

feat: add vector route to projection router, handle rejected status

lingfengQAQ 2 miesięcy temu
rodzic
commit
7c849f8abd

+ 6 - 6
webnovel-writer/scripts/data_modules/event_projection_router.py

@@ -7,16 +7,16 @@ from typing import Dict, List, Set
 
 class EventProjectionRouter:
     TABLE = {
-        "character_state_changed": ["state", "memory"],
-        "power_breakthrough": ["state", "memory"],
-        "relationship_changed": ["index"],
-        "world_rule_revealed": ["memory"],
-        "world_rule_broken": ["memory"],
+        "character_state_changed": ["state", "memory", "vector"],
+        "power_breakthrough": ["state", "memory", "vector"],
+        "relationship_changed": ["index", "vector"],
+        "world_rule_revealed": ["memory", "vector"],
+        "world_rule_broken": ["memory", "vector"],
         "open_loop_created": ["memory"],
         "open_loop_closed": ["memory"],
         "promise_created": ["memory"],
         "promise_paid_off": ["memory"],
-        "artifact_obtained": ["index"],
+        "artifact_obtained": ["index", "vector"],
     }
 
     def route(self, event: Dict) -> List[str]:

+ 15 - 3
webnovel-writer/scripts/data_modules/state_projection_writer.py

@@ -12,10 +12,22 @@ class StateProjectionWriter:
         self.project_root = Path(project_root)
 
     def apply(self, commit_payload: dict) -> dict:
-        if commit_payload["meta"]["status"] != "accepted":
-            return {"applied": False, "writer": "state", "reason": "commit_rejected"}
-
         chapter = int(commit_payload.get("meta", {}).get("chapter") or 0)
+        status = commit_payload["meta"]["status"]
+
+        if status == "rejected":
+            if chapter > 0:
+                state_path = self.project_root / ".webnovel" / "state.json"
+                state = read_json_if_exists(state_path) or {}
+                progress = state.setdefault("progress", {})
+                chapter_status = progress.setdefault("chapter_status", {})
+                chapter_status[str(chapter)] = "chapter_rejected"
+                write_json(state_path, state)
+            return {"applied": True, "writer": "state", "reason": "commit_rejected_status_updated"}
+
+        if status != "accepted":
+            return {"applied": False, "writer": "state", "reason": f"unknown_status:{status}"}
+
         state_path = self.project_root / ".webnovel" / "state.json"
         state = read_json_if_exists(state_path) or {}
         entity_state = state.setdefault("entity_state", {})

+ 36 - 3
webnovel-writer/scripts/data_modules/tests/test_event_projection_router.py

@@ -9,7 +9,7 @@ def test_router_maps_power_breakthrough_to_state_and_memory():
     targets = router.route(
         {"event_type": "power_breakthrough", "subject": "xiaoyan", "payload": {}}
     )
-    assert targets == ["state", "memory"]
+    assert targets == ["state", "memory", "vector"]
 
 
 def test_router_maps_relationship_changed_to_index():
@@ -33,7 +33,7 @@ def test_router_maps_world_rule_broken_to_memory_only():
             "payload": {"field": "world_rule"},
         }
     )
-    assert targets == ["memory"]
+    assert targets == ["memory", "vector"]
 
 
 def test_router_collects_required_writers_from_commit_payload():
@@ -51,4 +51,37 @@ def test_router_collects_required_writers_from_commit_payload():
             "summary_text": "本章摘要",
         }
     )
-    assert targets == ["index", "memory", "state", "summary"]
+    assert targets == ["index", "memory", "state", "summary", "vector"]
+
+
+def test_router_maps_power_breakthrough_to_state_memory_vector():
+    router = EventProjectionRouter()
+    targets = router.route(
+        {"event_type": "power_breakthrough", "subject": "xiaoyan", "payload": {}}
+    )
+    assert "vector" in targets
+    assert "state" in targets
+    assert "memory" in targets
+
+
+def test_router_maps_relationship_changed_to_index_and_vector():
+    router = EventProjectionRouter()
+    targets = router.route(
+        {"event_type": "relationship_changed", "subject": "xiaoyan", "payload": {}}
+    )
+    assert "index" in targets
+    assert "vector" in targets
+
+
+def test_required_writers_includes_vector_for_key_events():
+    router = EventProjectionRouter()
+    payload = {
+        "meta": {"status": "accepted", "chapter": 5},
+        "accepted_events": [
+            {"event_type": "power_breakthrough", "subject": "xiaoyan", "payload": {}},
+        ],
+        "entity_deltas": [],
+        "summary_text": "摘要",
+    }
+    writers = router.required_writers(payload)
+    assert "vector" in writers