ソースを参照

refactor(v3-cleanup-B2): 老游走策略 13 段删 10 僵尸段,校验器同步收窄

- douyin_walk_strategy.v1.json 仅留 3 个仍被消费的段(边目录/规则包绑定/事实契约);
  老预算/停止/重试/触发规则等 10 段运行时零消费(已被 walk_graph+walk_policy 取代),
  原仅靠非空校验被迫活着,-489 行
- REQUIRED_SECTIONS 13→3,删 _check_edge_nodes/_check_action_refs;
  游走 Excel 删 10 个对应 sheet,同步脚本 _WALK/WALK_MEANINGS 收窄
- rule packs: 删零消费段 global_budgets;清 shared_contracts/run_record_policy 里
  B1 已退役的 age_50_plus_level 残留(deprecated 打分维度标记有意保留);
  映射 Excel 删冗余 sheet walk_next_step_mapping(值实际维护在 query_effect_aggregation)
- 新增钉死测试: 3 段集合断言;config gate 五闸 pass,Excel↔JSON byte-equal,324 passed
- 验收岗交叉核验: 施工 7 项+防误删 4 项全 PASS

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sam Lee 1 日 前
コミット
3e09a91cfd

+ 5 - 53
content_agent/integrations/walk_strategy_json.py

@@ -10,19 +10,13 @@ from content_agent.findings import fail as _fail
 
 
 WALK_STRATEGY_PATH = Path("product_documents/抖音游走策略/douyin_walk_strategy.v1.json")
 WALK_STRATEGY_PATH = Path("product_documents/抖音游走策略/douyin_walk_strategy.v1.json")
 RULE_PACK_PATH = Path("product_documents/规则包/douyin_rule_packs.v1.json")
 RULE_PACK_PATH = Path("product_documents/规则包/douyin_rule_packs.v1.json")
+# V3 清理: 13 段收窄到 3 个仍被运行时/校验消费的段——
+# walk_edge_catalog(walk_graph.json 边 ID 合法性校验)、walk_rule_pack_binding
+# (终端阶段归属包)、walk_fact_contract(runtime 文件契约校验);其余 10 段
+# (老预算/停止/重试/触发规则等)已被 walk_graph+walk_policy 取代,随段删除。
 REQUIRED_SECTIONS = [
 REQUIRED_SECTIONS = [
-    "walk_strategy_meta",
-    "walk_node_catalog",
     "walk_edge_catalog",
     "walk_edge_catalog",
-    "walk_edge_trigger_rules",
     "walk_rule_pack_binding",
     "walk_rule_pack_binding",
-    "walk_budget_policy",
-    "walk_stop_policy",
-    "walk_retry_policy",
-    "walk_action_catalog",
-    "walk_source_path_mapping",
-    "walk_event_mapping",
-    "walk_query_generation_policy",
     "walk_fact_contract",
     "walk_fact_contract",
 ]
 ]
 
 
@@ -73,10 +67,7 @@ def validate_walk_strategy_config(
         return findings
         return findings
 
 
     edge_ids = _ids(strategy["walk_edge_catalog"], "edge_id")
     edge_ids = _ids(strategy["walk_edge_catalog"], "edge_id")
-    node_types = _ids(strategy["walk_node_catalog"], "node_type")
-    _check_edge_nodes(strategy["walk_edge_catalog"], node_types, findings)
     _check_edge_refs(strategy, edge_ids, findings)
     _check_edge_refs(strategy, edge_ids, findings)
-    _check_action_refs(strategy["walk_action_catalog"], edge_ids, findings)
     _check_fact_contract(strategy["walk_fact_contract"], findings)
     _check_fact_contract(strategy["walk_fact_contract"], findings)
     _check_rule_pack_bindings(
     _check_rule_pack_bindings(
         strategy["walk_rule_pack_binding"],
         strategy["walk_rule_pack_binding"],
@@ -106,36 +97,12 @@ def _check_required_sections(strategy: dict[str, Any], findings: list[dict[str,
             _fail(findings, "section_missing", f"{section} must be a non-empty list")
             _fail(findings, "section_missing", f"{section} must be a non-empty list")
 
 
 
 
-def _check_edge_nodes(
-    edge_catalog: list[dict[str, Any]],
-    node_types: set[str],
-    findings: list[dict[str, Any]],
-) -> None:
-    for edge in edge_catalog:
-        for field in ["from_node_type", "to_node_type"]:
-            if edge.get(field) not in node_types:
-                _fail(
-                    findings,
-                    "edge_node_ref",
-                    f"{edge.get('edge_id')} references unknown {field}: {edge.get(field)}",
-                )
-
-
 def _check_edge_refs(
 def _check_edge_refs(
     strategy: dict[str, Any],
     strategy: dict[str, Any],
     edge_ids: set[str],
     edge_ids: set[str],
     findings: list[dict[str, Any]],
     findings: list[dict[str, Any]],
 ) -> None:
 ) -> None:
-    for section in [
-        "walk_edge_trigger_rules",
-        "walk_rule_pack_binding",
-        "walk_budget_policy",
-        "walk_stop_policy",
-        "walk_retry_policy",
-        "walk_source_path_mapping",
-        "walk_event_mapping",
-        "walk_query_generation_policy",
-    ]:
+    for section in ["walk_rule_pack_binding"]:
         for row in strategy.get(section, []):
         for row in strategy.get(section, []):
             if row.get("edge_id") not in edge_ids:
             if row.get("edge_id") not in edge_ids:
                 _fail(
                 _fail(
@@ -145,21 +112,6 @@ def _check_edge_refs(
                 )
                 )
 
 
 
 
-def _check_action_refs(
-    actions: list[dict[str, Any]], edge_ids: set[str], findings: list[dict[str, Any]]
-) -> None:
-    actions_by_name = _ids(actions, "walk_action")
-    if not actions_by_name:
-        _fail(findings, "action_catalog", "walk_action_catalog has no walk_action")
-    for action in actions:
-        if action.get("edge_id") not in edge_ids:
-            _fail(
-                findings,
-                "action_edge_ref",
-                f"{action.get('walk_action')} references unknown edge_id: {action.get('edge_id')}",
-            )
-
-
 def _check_fact_contract(
 def _check_fact_contract(
     contracts: list[dict[str, Any]], findings: list[dict[str, Any]]
     contracts: list[dict[str, Any]], findings: list[dict[str, Any]]
 ) -> None:
 ) -> None:

+ 0 - 489
product_documents/抖音游走策略/douyin_walk_strategy.v1.json

@@ -6,92 +6,6 @@
   "status": "active",
   "status": "active",
   "source_of_truth": "product_documents/抖音游走策略/douyin_walk_strategy.v1.json",
   "source_of_truth": "product_documents/抖音游走策略/douyin_walk_strategy.v1.json",
   "notes": "P6 runtime source of truth. Excel is the human-maintained source. The current schema and DB validator use the 21-table runtime contract.",
   "notes": "P6 runtime source of truth. Excel is the human-maintained source. The current schema and DB validator use the 21-table runtime contract.",
-  "walk_strategy_meta": [
-    {
-      "strategy_id": "douyin_walk_strategy_v1",
-      "strategy_version": "V1.0",
-      "platform": "douyin",
-      "status": "active",
-      "owner": "ContentFindAgent",
-      "source_json_path": "product_documents/抖音游走策略/douyin_walk_strategy.v1.json",
-      "description": "P6 walk strategy for bounded query pagination, author edge and hashtag edge.",
-      "notes": "P9 and P10 are merged into P6. This strategy is active for the current V1 runtime."
-    }
-  ],
-  "walk_node_catalog": [
-    {
-      "node_type": "pattern_seed",
-      "node_label": "Pattern seed",
-      "node_category": "input",
-      "id_field": "policy_run_id",
-      "can_expand": true,
-      "is_signal_node": false,
-      "notes": "P2 starts from seed terms."
-    },
-    {
-      "node_type": "query",
-      "node_label": "Search query",
-      "node_category": "action_input",
-      "id_field": "search_query_id",
-      "can_expand": true,
-      "is_signal_node": false,
-      "notes": "Initial item query or tag query."
-    },
-    {
-      "node_type": "search_page",
-      "node_label": "Search page",
-      "node_category": "platform_result",
-      "id_field": "search_page_id",
-      "can_expand": true,
-      "is_signal_node": true,
-      "notes": "Carries has_more and next_cursor."
-    },
-    {
-      "node_type": "video",
-      "node_label": "Douyin video",
-      "node_category": "content",
-      "id_field": "platform_content_id",
-      "can_expand": true,
-      "is_signal_node": false,
-      "notes": "Video is the core V1 content object."
-    },
-    {
-      "node_type": "author",
-      "node_label": "Douyin author",
-      "node_category": "entity",
-      "id_field": "platform_author_id",
-      "can_expand": true,
-      "is_signal_node": false,
-      "notes": "Author comes from discovered videos in this run."
-    },
-    {
-      "node_type": "author_works_page",
-      "node_label": "Author works page",
-      "node_category": "platform_result",
-      "id_field": "author_works_page_id",
-      "can_expand": true,
-      "is_signal_node": true,
-      "notes": "Author作品列表页."
-    },
-    {
-      "node_type": "hashtag",
-      "node_label": "Hashtag",
-      "node_category": "signal",
-      "id_field": "hashtag",
-      "can_expand": true,
-      "is_signal_node": true,
-      "notes": "Only strong relevant tags may expand."
-    },
-    {
-      "node_type": "asset",
-      "node_label": "Final asset",
-      "node_category": "asset",
-      "id_field": "asset_id",
-      "can_expand": false,
-      "is_signal_node": false,
-      "notes": "Final output object."
-    }
-  ],
   "walk_edge_catalog": [
   "walk_edge_catalog": [
     {
     {
       "edge_id": "query_next_page",
       "edge_id": "query_next_page",
@@ -224,63 +138,6 @@
       "notes": "Lower budget tier."
       "notes": "Lower budget tier."
     }
     }
   ],
   ],
-  "walk_edge_trigger_rules": [
-    {
-      "trigger_id": "tr_query_next_page_success",
-      "edge_id": "query_next_page",
-      "input_level": "query",
-      "field_path": "search_query_effect_status",
-      "operator": "equals",
-      "expected_value": "success",
-      "required": true,
-      "failure_policy": "skip_edge",
-      "notes": "Only effective query may page."
-    },
-    {
-      "trigger_id": "tr_query_next_page_cursor",
-      "edge_id": "query_next_page",
-      "input_level": "query",
-      "field_path": "raw_payload.next_cursor",
-      "operator": "not_empty",
-      "expected_value": true,
-      "required": true,
-      "failure_policy": "skip_edge",
-      "notes": "Cursor is required."
-    },
-    {
-      "trigger_id": "tr_video_author_exists",
-      "edge_id": "video_to_author",
-      "input_level": "content",
-      "field_path": "platform_author_id",
-      "operator": "not_empty",
-      "expected_value": true,
-      "required": true,
-      "failure_policy": "skip_edge",
-      "notes": "No author id means no author edge."
-    },
-    {
-      "trigger_id": "tr_hashtag_relevant",
-      "edge_id": "hashtag_to_query",
-      "input_level": "hashtag",
-      "field_path": "hashtag_effect_status",
-      "operator": "equals",
-      "expected_value": "success",
-      "required": true,
-      "failure_policy": "skip_edge",
-      "notes": "Only strong relevant hashtag expands."
-    },
-    {
-      "trigger_id": "tr_rule_blocked_stop",
-      "edge_id": "path_stop",
-      "input_level": "content",
-      "field_path": "content_effect_status",
-      "operator": "equals",
-      "expected_value": "rule_blocked",
-      "required": true,
-      "failure_policy": "continue",
-      "notes": "Rule blocked content stops expansion."
-    }
-  ],
   "walk_rule_pack_binding": [
   "walk_rule_pack_binding": [
     {
     {
       "binding_id": "bind_decision_asset_content_pack",
       "binding_id": "bind_decision_asset_content_pack",
@@ -293,352 +150,6 @@
       "notes": "Asset commit is owned by the Content pack decision."
       "notes": "Asset commit is owned by the Content pack decision."
     }
     }
   ],
   ],
-  "walk_budget_policy": [
-    {
-      "budget_id": "budget_query_next_page_v1",
-      "edge_id": "query_next_page",
-      "max_total_actions": 30,
-      "max_per_query": 2,
-      "max_per_content": null,
-      "max_pages": 3,
-      "max_depth": 3,
-      "max_tag_hops": null,
-      "budget_tier": "normal",
-      "notes": "First page plus at most two more pages."
-    },
-    {
-      "budget_id": "budget_video_author_v1",
-      "edge_id": "video_to_author",
-      "max_total_actions": 10,
-      "max_per_query": null,
-      "max_per_content": 1,
-      "max_pages": null,
-      "max_depth": 3,
-      "max_tag_hops": null,
-      "budget_tier": "normal",
-      "notes": "At most 10 authors per run."
-    },
-    {
-      "budget_id": "budget_author_works_v1",
-      "edge_id": "author_to_works",
-      "max_total_actions": 10,
-      "max_per_query": null,
-      "max_per_content": null,
-      "max_pages": 3,
-      "max_depth": 3,
-      "max_tag_hops": null,
-      "budget_tier": "normal",
-      "notes": "At most 20 works per author in later implementation."
-    },
-    {
-      "budget_id": "budget_tag_query_v1",
-      "edge_id": "hashtag_to_query",
-      "max_total_actions": 10,
-      "max_per_query": null,
-      "max_per_content": 3,
-      "max_pages": null,
-      "max_depth": 3,
-      "max_tag_hops": 10,
-      "budget_tier": "normal",
-      "notes": "At most 10 tag hops per run."
-    }
-  ],
-  "walk_stop_policy": [
-    {
-      "stop_policy_id": "stop_rule_blocked",
-      "edge_id": "path_stop",
-      "condition_label": "rule blocked",
-      "field_path": "content_effect_status",
-      "operator": "equals",
-      "expected_value": "rule_blocked",
-      "stop_action": "stop_path",
-      "reason_code": "rule_blocked",
-      "priority": 10,
-      "notes": "Hard gate blocked content cannot expand."
-    },
-    {
-      "stop_policy_id": "stop_failed_content",
-      "edge_id": "path_stop",
-      "condition_label": "failed content",
-      "field_path": "content_effect_status",
-      "operator": "equals",
-      "expected_value": "failed",
-      "stop_action": "stop_path",
-      "reason_code": "content_failed",
-      "priority": 20,
-      "notes": "Failed content does not expand."
-    },
-    {
-      "stop_policy_id": "stop_budget_exhausted",
-      "edge_id": "budget_downgrade",
-      "condition_label": "budget exhausted",
-      "field_path": "budget.remaining_actions",
-      "operator": "less_or_equal",
-      "expected_value": 0,
-      "stop_action": "stop_edge",
-      "reason_code": "budget_exhausted",
-      "priority": 30,
-      "notes": "No budget left."
-    },
-    {
-      "stop_policy_id": "stop_tag_hop_limit",
-      "edge_id": "hashtag_to_query",
-      "condition_label": "tag hop limit",
-      "field_path": "walk_context.tag_hop_count",
-      "operator": "greater_or_equal",
-      "expected_value": 10,
-      "stop_action": "stop_edge",
-      "reason_code": "tag_hop_limit",
-      "priority": 40,
-      "notes": "Max tag expansion reached."
-    }
-  ],
-  "walk_retry_policy": [
-    {
-      "retry_policy_id": "retry_query_next_page",
-      "edge_id": "query_next_page",
-      "operation": "douyin_keyword_search",
-      "max_retries": 0,
-      "retry_interval_seconds": 0,
-      "on_final_failure": "mark_edge_failed",
-      "notes": "Single query/page failure should not fail whole run."
-    },
-    {
-      "retry_policy_id": "retry_author_works",
-      "edge_id": "author_to_works",
-      "operation": "douyin_author_works",
-      "max_retries": 1,
-      "retry_interval_seconds": 2,
-      "on_final_failure": "mark_edge_failed",
-      "notes": "Author edge may retry once."
-    },
-    {
-      "retry_policy_id": "retry_hashtag_query",
-      "edge_id": "hashtag_to_query",
-      "operation": "tag_query_generation",
-      "max_retries": 0,
-      "retry_interval_seconds": 0,
-      "on_final_failure": "skip_edge",
-      "notes": "Tag query generation should be deterministic."
-    }
-  ],
-  "walk_action_catalog": [
-    {
-      "walk_action": "fetch_next_page",
-      "action_label": "拉下一页",
-      "edge_id": "query_next_page",
-      "runtime_effect": "creates_search_page",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Uses next_cursor."
-    },
-    {
-      "walk_action": "extract_content",
-      "action_label": "拆出视频",
-      "edge_id": "search_page_to_content",
-      "runtime_effect": "creates_video",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Search page to videos."
-    },
-    {
-      "walk_action": "expand_author",
-      "action_label": "扩作者",
-      "edge_id": "video_to_author",
-      "runtime_effect": "creates_author",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Author id from video."
-    },
-    {
-      "walk_action": "fetch_author_works",
-      "action_label": "拉作者作品",
-      "edge_id": "author_to_works",
-      "runtime_effect": "creates_author_works_page",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Author works page."
-    },
-    {
-      "walk_action": "convert_author_work",
-      "action_label": "作者作品入视频判断",
-      "edge_id": "author_work_to_content",
-      "runtime_effect": "creates_video",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Works become discovered content."
-    },
-    {
-      "walk_action": "extract_hashtag",
-      "action_label": "提取 tag",
-      "edge_id": "video_to_hashtag",
-      "runtime_effect": "creates_hashtag",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Extract from tags/text_extra/cha_list."
-    },
-    {
-      "walk_action": "create_tag_query",
-      "action_label": "生成 tag query",
-      "edge_id": "hashtag_to_query",
-      "runtime_effect": "creates_query",
-      "is_terminal": false,
-      "writes_next_hop": true,
-      "notes": "Writes tag query."
-    },
-    {
-      "walk_action": "commit_asset",
-      "action_label": "沉淀资产",
-      "edge_id": "decision_to_asset",
-      "runtime_effect": "creates_asset",
-      "is_terminal": true,
-      "writes_next_hop": true,
-      "notes": "Final output."
-    },
-    {
-      "walk_action": "stop_path",
-      "action_label": "停止路径",
-      "edge_id": "path_stop",
-      "runtime_effect": "stops_path",
-      "is_terminal": true,
-      "writes_next_hop": false,
-      "notes": "No more expansion."
-    },
-    {
-      "walk_action": "downgrade_budget",
-      "action_label": "降预算",
-      "edge_id": "budget_downgrade",
-      "runtime_effect": "lowers_budget",
-      "is_terminal": false,
-      "writes_next_hop": false,
-      "notes": "Continue with lower budget."
-    }
-  ],
-  "walk_source_path_mapping": [
-    {
-      "mapping_id": "sp_query_next_page",
-      "edge_id": "query_next_page",
-      "source_path_type": "query_to_search_page",
-      "from_node_type": "query",
-      "to_node_type": "search_page",
-      "origin_path_template": "query:{search_query_id}",
-      "source_evidence_ref_template": "search_queries:{search_query_id}",
-      "notes": "Pagination source path."
-    },
-    {
-      "mapping_id": "sp_search_page_content",
-      "edge_id": "search_page_to_content",
-      "source_path_type": "search_query_to_content",
-      "from_node_type": "search_page",
-      "to_node_type": "video",
-      "origin_path_template": "query:{search_query_id}/page:{page_cursor}",
-      "source_evidence_ref_template": "discovered_content:{content_discovery_id}",
-      "notes": "Search result content path."
-    },
-    {
-      "mapping_id": "sp_video_author",
-      "edge_id": "video_to_author",
-      "source_path_type": "video_to_author",
-      "from_node_type": "video",
-      "to_node_type": "author",
-      "origin_path_template": "video:{platform_content_id}",
-      "source_evidence_ref_template": "author:{platform_author_id}",
-      "notes": "Author clue from video."
-    },
-    {
-      "mapping_id": "sp_author_works",
-      "edge_id": "author_to_works",
-      "source_path_type": "author_to_works",
-      "from_node_type": "author",
-      "to_node_type": "author_works_page",
-      "origin_path_template": "author:{platform_author_id}",
-      "source_evidence_ref_template": "author_works:{author_works_page_id}",
-      "notes": "Author works page path."
-    },
-    {
-      "mapping_id": "sp_author_work_content",
-      "edge_id": "author_work_to_content",
-      "source_path_type": "author_work_to_content",
-      "from_node_type": "author_works_page",
-      "to_node_type": "video",
-      "origin_path_template": "author:{platform_author_id}/works_page:{page_cursor}",
-      "source_evidence_ref_template": "discovered_content:{content_discovery_id}",
-      "notes": "Author work content path."
-    },
-    {
-      "mapping_id": "sp_video_hashtag",
-      "edge_id": "video_to_hashtag",
-      "source_path_type": "video_to_hashtag",
-      "from_node_type": "video",
-      "to_node_type": "hashtag",
-      "origin_path_template": "video:{platform_content_id}",
-      "source_evidence_ref_template": "hashtag:{hashtag}",
-      "notes": "Hashtag from video."
-    },
-    {
-      "mapping_id": "sp_hashtag_query",
-      "edge_id": "hashtag_to_query",
-      "source_path_type": "hashtag_to_query",
-      "from_node_type": "hashtag",
-      "to_node_type": "query",
-      "origin_path_template": "hashtag:{hashtag}",
-      "source_evidence_ref_template": "search_queries:{search_query_id}",
-      "notes": "Tag creates query."
-    }
-  ],
-  "walk_event_mapping": [
-    {
-      "mapping_id": "evt_query_next_page",
-      "edge_id": "query_next_page",
-      "event_type": "walk.query_next_page",
-      "success_status": "success",
-      "failure_status": "failed",
-      "input_ref_template": "query:{search_query_id}",
-      "output_ref_template": "search_page:{search_page_id}",
-      "notes": "Pagination event."
-    },
-    {
-      "mapping_id": "evt_author_works",
-      "edge_id": "author_to_works",
-      "event_type": "walk.author_works",
-      "success_status": "success",
-      "failure_status": "failed",
-      "input_ref_template": "author:{platform_author_id}",
-      "output_ref_template": "author_works:{author_works_page_id}",
-      "notes": "Author works event."
-    },
-    {
-      "mapping_id": "evt_hashtag_query",
-      "edge_id": "hashtag_to_query",
-      "event_type": "walk.hashtag_query",
-      "success_status": "success",
-      "failure_status": "skipped",
-      "input_ref_template": "hashtag:{hashtag}",
-      "output_ref_template": "query:{search_query_id}",
-      "notes": "Hashtag query event."
-    },
-    {
-      "mapping_id": "evt_path_stop",
-      "edge_id": "path_stop",
-      "event_type": "walk.path_stop",
-      "success_status": "skipped",
-      "failure_status": "failed",
-      "input_ref_template": "node:{from_node_id}",
-      "output_ref_template": "none",
-      "notes": "Stop path event."
-    }
-  ],
-  "walk_query_generation_policy": [
-    {
-      "policy_id": "tag_query_v1",
-      "edge_id": "hashtag_to_query",
-      "query_generation_method": "tag_query",
-      "source_field": "hashtag",
-      "dedup_policy": "normalize_exact_and_recent_run",
-      "max_queries": 10,
-      "notes": "Tag query does not pollute initial P2 item queries."
-    }
-  ],
   "walk_fact_contract": [
   "walk_fact_contract": [
     {
     {
       "runtime_file": "walk_actions.jsonl",
       "runtime_file": "walk_actions.jsonl",

+ 0 - 17
product_documents/规则包/douyin_rule_packs.v1.json

@@ -127,7 +127,6 @@
     ],
     ],
     "nullable_output_fields": [
     "nullable_output_fields": [
       "score",
       "score",
-      "age_50_plus_level",
       "search_query_effect_status"
       "search_query_effect_status"
     ],
     ],
     "source_evidence_required": true,
     "source_evidence_required": true,
@@ -155,24 +154,9 @@
         "search_query_direct",
         "search_query_direct",
         "search_query_from_tag",
         "search_query_from_tag",
         "author_work"
         "author_work"
-      ],
-      "age_50_plus_level": [
-        "strong",
-        "medium",
-        "weak",
-        "missing"
       ]
       ]
     }
     }
   },
   },
-  "global_budgets": {
-    "max_tag_expansion_hops": 10,
-    "max_queries_per_pattern": 5,
-    "max_pages_per_query": 3,
-    "max_expand_authors": 10,
-    "max_author_work_pages": 3,
-    "max_author_works_per_author": 20,
-    "max_depth": 3
-  },
   "rule_packs": [
   "rule_packs": [
     {
     {
       "rule_pack_id": "douyin_content_discovery_rule_pack_v1",
       "rule_pack_id": "douyin_content_discovery_rule_pack_v1",
@@ -581,7 +565,6 @@
       "search_query_effect_status",
       "search_query_effect_status",
       "discovery_start_source",
       "discovery_start_source",
       "previous_discovery_step",
       "previous_discovery_step",
-      "age_50_plus_level",
       "tag_expansion_hop_count"
       "tag_expansion_hop_count"
     ],
     ],
     "related_runtime_outputs": {
     "related_runtime_outputs": {

+ 1 - 60
scripts/add_excel_field_comment_row.py

@@ -32,19 +32,8 @@ COMMENT_FILL = PatternFill(start_color="FFF2F2F2", end_color="FFF2F2F2", fill_ty
 COMMENT_FONT = Font(italic=True, color="FF7F7F7F")
 COMMENT_FONT = Font(italic=True, color="FF7F7F7F")
 
 
 # Walk-strategy meanings, per sheet, from 02_游走策略表字段说明.md.
 # Walk-strategy meanings, per sheet, from 02_游走策略表字段说明.md.
+# V3 清理: 仅保留 3 个仍存在的 sheet(其余 10 个僵尸 sheet 已随 JSON 段删除)。
 WALK_MEANINGS: dict[str, dict[str, str]] = {
 WALK_MEANINGS: dict[str, dict[str, str]] = {
-    "walk_strategy_meta": {
-        "strategy_id": "游走策略 ID", "strategy_version": "游走策略版本",
-        "platform": "平台,V1 为 douyin", "status": "策略状态,如 active / draft / deprecated",
-        "owner": "业务负责人", "source_json_path": "对应 runtime JSON 路径",
-        "description": "策略说明", "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_node_catalog": {
-        "node_type": "节点类型,如 query、video、author、hashtag", "node_label": "产品可读名称",
-        "node_category": "节点类别,如 input、platform_result、signal、asset",
-        "id_field": "识别该节点的字段", "can_expand": "是否可继续扩展",
-        "is_signal_node": "是否只是信号节点,不直接沉淀资产", "notes": "备注", "注释": "中文业务注释",
-    },
     "walk_edge_catalog": {
     "walk_edge_catalog": {
         "edge_id": "边 ID", "edge_type": "边类型", "from_node_type": "起点节点类型",
         "edge_id": "边 ID", "edge_type": "边类型", "from_node_type": "起点节点类型",
         "to_node_type": "终点节点类型", "edge_label": "产品可读名称", "enabled": "是否启用",
         "to_node_type": "终点节点类型", "edge_label": "产品可读名称", "enabled": "是否启用",
@@ -52,13 +41,6 @@ WALK_MEANINGS: dict[str, dict[str, str]] = {
         "can_loop": "是否允许循环或多轮", "priority": "边优先级,数字越小越先执行",
         "can_loop": "是否允许循环或多轮", "priority": "边优先级,数字越小越先执行",
         "notes": "备注", "注释": "中文业务注释",
         "notes": "备注", "注释": "中文业务注释",
     },
     },
-    "walk_edge_trigger_rules": {
-        "trigger_id": "触发规则 ID", "edge_id": "适用边",
-        "input_level": "判断粒度,如 query、content、author、tag",
-        "field_path": "用来判断的字段路径", "operator": "判断操作符", "expected_value": "期望值",
-        "required": "是否必需满足", "failure_policy": "不满足时的处理方式",
-        "notes": "备注", "注释": "中文业务注释",
-    },
     "walk_rule_pack_binding": {
     "walk_rule_pack_binding": {
         "binding_id": "绑定 ID", "edge_id": "被绑定的边",
         "binding_id": "绑定 ID", "edge_id": "被绑定的边",
         "target_entity": "规则判断对象,如 Content、Author、Hashtag、Path、Budget",
         "target_entity": "规则判断对象,如 Content、Author、Hashtag、Path、Budget",
@@ -67,47 +49,6 @@ WALK_MEANINGS: dict[str, dict[str, str]] = {
         "dispatch_policy": "调用方式,如 required / optional / advisory",
         "dispatch_policy": "调用方式,如 required / optional / advisory",
         "notes": "备注", "注释": "中文业务注释",
         "notes": "备注", "注释": "中文业务注释",
     },
     },
-    "walk_budget_policy": {
-        "budget_id": "预算规则 ID", "edge_id": "适用边",
-        "max_total_actions": "单 run 最多执行次数", "max_per_query": "每条 query 最多执行次数",
-        "max_per_content": "每条内容最多执行次数", "max_pages": "最大页数",
-        "max_depth": "最大游走深度", "max_tag_hops": "最大 tag 扩散跳数",
-        "budget_tier": "预算档位", "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_stop_policy": {
-        "stop_policy_id": "停止规则 ID", "edge_id": "适用边", "condition_label": "停止条件名称",
-        "field_path": "判断字段路径", "operator": "判断操作符", "expected_value": "期望值",
-        "stop_action": "停止后的动作", "reason_code": "停止原因码", "priority": "停止规则优先级",
-        "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_retry_policy": {
-        "retry_policy_id": "重试规则 ID", "edge_id": "适用边", "operation": "重试的外部操作",
-        "max_retries": "最大重试次数", "retry_interval_seconds": "重试间隔秒数",
-        "on_final_failure": "最终失败后的处理", "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_action_catalog": {
-        "walk_action": "游走动作枚举", "action_label": "产品可读名称", "edge_id": "适用边",
-        "runtime_effect": "运行影响", "is_terminal": "是否终止路径",
-        "writes_next_hop": "是否写入下一跳节点", "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_source_path_mapping": {
-        "mapping_id": "来源路径映射 ID", "edge_id": "适用边", "source_path_type": "来源路径类型",
-        "from_node_type": "起点节点类型", "to_node_type": "终点节点类型",
-        "origin_path_template": "来源路径模板", "source_evidence_ref_template": "来源证据引用模板",
-        "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_event_mapping": {
-        "mapping_id": "事件映射 ID", "edge_id": "适用边", "event_type": "运行事件类型",
-        "success_status": "成功状态", "failure_status": "失败状态",
-        "input_ref_template": "输入引用模板", "output_ref_template": "输出引用模板",
-        "notes": "备注", "注释": "中文业务注释",
-    },
-    "walk_query_generation_policy": {
-        "policy_id": "query 生成规则 ID", "edge_id": "适用边",
-        "query_generation_method": "query 生成方式", "source_field": "生成 query 的来源字段",
-        "dedup_policy": "去重策略", "max_queries": "最大生成 query 数",
-        "notes": "备注", "注释": "中文业务注释",
-    },
     "walk_fact_contract": {
     "walk_fact_contract": {
         "runtime_file": "runtime 文件名", "db_table": "对应 DB 表", "required_fields": "必填字段",
         "runtime_file": "runtime 文件名", "db_table": "对应 DB 表", "required_fields": "必填字段",
         "json_fields": "JSON 字段", "unique_key": "唯一键", "notes": "备注", "注释": "中文业务注释",
         "json_fields": "JSON 字段", "unique_key": "唯一键", "notes": "备注", "注释": "中文业务注释",

+ 5 - 5
scripts/build_config_from_excel.py

@@ -73,12 +73,12 @@ RULE_PACK_SPECS = [
 ]
 ]
 
 
 # Walk sheets mirror JSON 1:1 (identity columns; only 注释 skipped).
 # Walk sheets mirror JSON 1:1 (identity columns; only 注释 skipped).
+# V3 清理: 13 段收窄到 3 个仍被消费的段(其余 10 段已被 walk_graph+walk_policy 取代,
+# JSON 段与对应 Excel sheet 一并删除)。
 _WALK = {
 _WALK = {
-    "walk_strategy_meta": "strategy_id", "walk_node_catalog": "node_type", "walk_edge_catalog": "edge_id",
-    "walk_edge_trigger_rules": "trigger_id", "walk_rule_pack_binding": "binding_id", "walk_budget_policy": "budget_id",
-    "walk_stop_policy": "stop_policy_id", "walk_retry_policy": "retry_policy_id", "walk_action_catalog": "walk_action",
-    "walk_source_path_mapping": "mapping_id", "walk_event_mapping": "mapping_id",
-    "walk_query_generation_policy": "policy_id", "walk_fact_contract": "runtime_file",
+    "walk_edge_catalog": "edge_id",
+    "walk_rule_pack_binding": "binding_id",
+    "walk_fact_contract": "runtime_file",
 }
 }
 WALK_SPECS = [SheetSpec(sheet, section=sheet, id_excel=idc) for sheet, idc in _WALK.items()]
 WALK_SPECS = [SheetSpec(sheet, section=sheet, id_excel=idc) for sheet, idc in _WALK.items()]
 
 

BIN
tech_documents/游走策略/游走策略配置表.xlsx


BIN
tech_documents/规则包映射/规则包映射配置表.xlsx


+ 13 - 0
tests/test_walk_strategy_config.py

@@ -31,6 +31,19 @@ def test_walk_strategy_config_sections_and_references_are_closed():
     assert [section for section in REQUIRED_SECTIONS if section not in strategy] == []
     assert [section for section in REQUIRED_SECTIONS if section not in strategy] == []
 
 
 
 
+def test_walk_strategy_config_keeps_only_consumed_sections():
+    # V3 清理受控变化: 13 段收窄到 3 个仍被运行时/校验消费的段;
+    # 其余 10 段(老预算/停止/重试/触发规则等)已被 walk_graph+walk_policy 取代并删除。
+    strategy = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
+
+    assert set(REQUIRED_SECTIONS) == {
+        "walk_edge_catalog",
+        "walk_rule_pack_binding",
+        "walk_fact_contract",
+    }
+    assert {key for key in strategy if key.startswith("walk_")} == set(REQUIRED_SECTIONS)
+
+
 def test_walk_strategy_config_uses_clue_id_and_real_rule_packs():
 def test_walk_strategy_config_uses_clue_id_and_real_rule_packs():
     strategy = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
     strategy = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
     facts = {row["runtime_file"]: row for row in strategy["walk_fact_contract"]}
     facts = {row["runtime_file"]: row for row in strategy["walk_fact_contract"]}