feat: 服务层配置接线——email/push/rate_limit/AI凭据/行为开关/映射表/种子键
Task 9: 服务层对全局 settings 的业务引用清零,每个 DEFAULT_CONFIG 组 都有真实消费方。resolve_*_settings(email/push/ai)以空槽回退 env (平台默认层);contact 行为开关/种子白名单/国名扩表/限流上限经 manager 的 runtime.config 接线。收口: lead_push session_factory 必填、 config.py 死代码清理、PromptProvider frozen、no_contact 视图直取、 AIService wall 参数定型 CompiledWall。403 测试全绿(389+14)。 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -171,7 +171,8 @@ def _consume_round(state: dict) -> dict:
|
||||
|
||||
|
||||
def transit(state: dict | None, reply: dict | None,
|
||||
new_canon: str | None = None) -> dict | None:
|
||||
new_canon: str | None = None,
|
||||
extras: dict[str, str] | None = None) -> dict | None:
|
||||
"""消费一轮 cc_reply 推进状态机(纯函数,不变异入参;spec §4 答语树)。
|
||||
|
||||
参数:
|
||||
@@ -179,6 +180,8 @@ def transit(state: dict | None, reply: dict | None,
|
||||
reply —— None(无回应/extractor 漏填兜底)或 {"affirm": bool,
|
||||
"country": str|None}(extractor 单轮分类,消费后由调用方剥离);
|
||||
new_canon —— 本轮最新号码的纯数字形态;与 state["canon"] 不同 → 换号。
|
||||
extras —— misc.name_to_region_extras(Task 9:租户国名映射扩表,
|
||||
报国重算的查表经 name_to_region 合并消费)。
|
||||
|
||||
返回:
|
||||
None —— RESET(换号或无态):调用方对号码重走 classify 重建状态
|
||||
@@ -186,7 +189,7 @@ def transit(state: dict | None, reply: dict | None,
|
||||
dict —— 新状态:
|
||||
- affirm=true → confirmed=true(source=ip_confirm;报国重算后的确认
|
||||
保持 customer_stated,号源如实标注)→ 落定;
|
||||
- affirm=false + country → NAME_TO_REGION 转 ISO 重算 e164
|
||||
- affirm=false + country → NAME_TO_REGION(⊕extras) 转 ISO 重算 e164
|
||||
(source=customer_stated)→ 再回显,attempts+1;
|
||||
- affirm=false 无 country / 无回应 / 国名不识别 → attempts+1,
|
||||
达上限(常规 2 轮)落定 confirmed=false、source=fallback。
|
||||
@@ -210,7 +213,7 @@ def transit(state: dict | None, reply: dict | None,
|
||||
else "ip_confirm")
|
||||
return new
|
||||
if country:
|
||||
iso = name_to_region(country)
|
||||
iso = name_to_region(country, extras=extras)
|
||||
recalc = _complete_with_region(canon or "", iso) if iso else None
|
||||
if recalc:
|
||||
new["e164"] = recalc["e164"]
|
||||
@@ -288,21 +291,28 @@ NAME_TO_REGION: dict[str, str] = {
|
||||
"西班牙": "ES", "Spain": "ES",
|
||||
}
|
||||
|
||||
# 大小写容错影子表(中文 casefold 为恒等,不受影响)
|
||||
_NAME_LOOKUP = {k.casefold(): v for k, v in NAME_TO_REGION.items()}
|
||||
|
||||
|
||||
def name_to_region(name: str | None) -> str | None:
|
||||
def name_to_region(name: str | None,
|
||||
extras: dict[str, str] | None = None) -> str | None:
|
||||
"""国名(extractor 回传原样字符串)→ ISO;未命中返回 None。
|
||||
|
||||
容错:去首尾空白、大小写不敏感、弯撇号(U+2019)归一为 ASCII。
|
||||
Task 9: extras = misc.name_to_region_extras(租户扩表),可加键也可
|
||||
覆盖基础表同名键(租户纠偏)——查表序 extras 优先。
|
||||
"""
|
||||
if not name:
|
||||
return None
|
||||
key = name.strip().replace("’", "'")
|
||||
if key in NAME_TO_REGION:
|
||||
return NAME_TO_REGION[key]
|
||||
return _NAME_LOOKUP.get(key.casefold())
|
||||
for table in (extras, NAME_TO_REGION):
|
||||
if table and key in table:
|
||||
return table[key]
|
||||
folded = key.casefold()
|
||||
for table in (extras, NAME_TO_REGION):
|
||||
if table:
|
||||
hit = {k.casefold(): v for k, v in table.items()}.get(folded)
|
||||
if hit:
|
||||
return hit
|
||||
return None
|
||||
|
||||
|
||||
# ---- Task 6 出站渲染(spec §5):首封补全号的展示派生(纯函数,邮件/推送共用) ----
|
||||
|
||||
Reference in New Issue
Block a user