Commit Graph

31 Commits

Author SHA1 Message Date
浅念 7502176190 feat: 配置API(分组校验管线/整份版本/回滚/重置出厂/试金石/平台设置)
- config_validation.validate_group: 九组校验管线(类型/键 allowlist/数值
  范围/prompts 大小上限 50KB·100KB/wall 全量交 compile_wall/push.prefix
  跨租户查重 spec E1),错误清单中文带字段路径
- config_routes: GET/PUT config(整组替换原样入版本,MAX+1,热 reload)/
  reset(按 Tenant.profile 取出厂档案组)/versions 列表·详情/rollback
  (旧版复制为新版本,历史不可变)/wall/test 试金石(逐句判定,不落库
  不 bump)/settings 平台设置 CRUD(仅超管,resolver 接线归 Phase 3)
- db.write_config_version: 版本写入公共路径(创建向导与配置 API 单一
  事实源);Tenant 落 profile 列(重置出厂按它取对应档案)
- _profile_snapshot/_blankify 迁 tenant_source(两路由模块共用);
  db_source_app/super_client 夹具收拢 conftest(两测试文件共用)
- 测试: 519 → 537 全绿

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 10:07:40 +08:00
浅念 ec2e17d5e3 feat: 租户管理API(创建向导消费出厂档案/blank保留jc墙/域名/停用/slug不可变)
POST /api/platform/tenants: profile ∈ {auto,jiancai,blank}——首版快照复用
FileTenantSource(seed).read_tenant(profile).snapshot(Task 4 审查指定);
blank=jiancai 档案 _blankify 去身份组但保留 wall/prompts(compile_wall/
PromptProvider 的硬要求)。建 Tenant+main 站点+版本1+租户管理员
(must_change_password=True),创建后 registry_reload(upsert)立即可用。

站点 CRUD(brand_overlay 整字典赋值,M-2a)/域名绑定解绑(全局唯一,
撞车 400 带现有归属)/PATCH 租户(name/status;slug 不可变 400;停用走
reload 路径 dispose 引擎)。列表/详情管理员概要显式挑字段,凭据永不外泄。
鉴权: 写操作+列表 require_super;GET 详情放宽 require_tenant(slug)。

测试: db_source_app 夹具(registry 用 DbTenantSource 生产形态指向临时
platform.db,跨循环纪律: 直查走独立 NullPool 连接),16 项全绿,全量 519。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 09:20:28 +08:00
浅念 1bd341c21a fix: 数据源审查小修(from_config 类型守卫/PROMPTS_KEYS 消重/契约措辞)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 09:05:09 +08:00
浅念 c7fd533320 feat: TenantSource 抽象——File源(测试/档案)与DB源(生产),registry 数据源可切换+reload upsert
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 08:50:16 +08:00
浅念 386b5eb90a feat: /api/platform 豁免租户解析(认证守护)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 08:32:55 +08:00
浅念 c5e8dd6ded fix: 认证审查修复(角色依赖连锁409门/停用租户token取舍注记/公共面整理)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 08:29:01 +08:00
浅念 f49e8e92b1 feat: 平台认证(scrypt上移/内存token 8h/登录限流/改密/角色依赖/409语义)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 08:18:15 +08:00
浅念 bfcaba5c87 fix: platform.db 前瞻加固(bootstrap竞态/哈希版本化/json_valid CHECK/测试补空/凭据列警示)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 08:08:22 +08:00
浅念 2d62108c73 feat: platform.db 模型与超管引导(WAL/scrypt/幂等bootstrap)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 07:57:15 +08:00
浅念 9ad02a778f fix: 终审修复——墙执行侧接租户管道(端到端回归锁)+seed补email组+措辞与死依赖清理
C-1(必须修): 墙的执行侧没接租户管道——runtime.compiled_wall 全库只有
AIService 的 $DEFLECTION_POOL 一处消费,conversation.py 执行侧全走模块级
DEFAULT_WALL(jiancai 出厂),auto 租户会话实际跑的是 jc 墙。修复:
- manager 构造时 self._wall = runtime.compiled_wall(与 AIService 同源);
- 6 处过滤调用(violates_boundary/no_contact_value/asks_contact 的句内
  与 pending 尾巴两路)、CC 墙模板/替换句、no_contact 收尾选择、
  pivot/deflection、兜底句、contact_ask 触发日志判定全部传 wall=self._wall;
- _build_context_reminder/_contact_completion_note/_cc_confirm_note/
  _cc_script/_cc_wall_template/_lang_note_for 加 wall=None 尾参
  (None = 模块级默认墙,旧测试直调语义不变;流式侧 _contact_completion_note
  双胞调用同传 wall,写回与注入不漂移);
- 模块级 DEFAULT_WALL 视图常量(BOUNDARY_TRIGGER_RE/_CC_*/_EMAIL_NOTE_* 等)
  保留——boundary_filter 出厂默认与旧测试锚定,boundary_filter 模块级
  DEFAULT_WALL 照旧,conversation 会话流内一律租户墙;
- 端到端回归锁 tests/test_wall_execution_tenant.py(两租户真 runtime +
  脚本化假 AI): jc 独有 [€£] pattern 句在 jiancai 拦截替换(收尾=jc
  pivots 池)/auto 放行逐字流出;同一邮箱违规句两租户各自精确收到自己
  no_contact["web"](12 hours vs replies fast!);contact_ask 提醒注入
  各自墙文案互不渗漏。已验证模拟旧 DEFAULT_WALL 行为时三测全败。

I-1: 两租户 seed 补 email 组(以 brand_values.json 实际值为准:
auto=notify_email 环境值,jiancai=品牌邮箱——其 notify_email 记录是
notify@example.com 占位): auto {sender_name: XYH, notify_emails:
[18339827479@163.com]}, jiancai {sender_name: HESUPIPE, notify_emails:
[hesu@hesuu.com]};seed 存裸名,From 头渲染时外层再包【】。补测
test_seed_tenants_ship_email_group: env NOTIFY_EMAIL patch 成异值证明
seed 槽胜出。

M-1/M-2: README/CLAUDE.md "platform.db 热加载"改为"文件级 registry_reload
热加载(Phase 2 升级为 platform.db)";requirements.txt 删 alembic
(全库零引用,grep 实证唯一命中即该行)。

M-3/M-4(挂账): CLAUDE.md Phase 2 清理单补两项——/health 分级健康
(Phase 4 部署批次)、PromptProvider.from_dir FileNotFoundError 带路径上下文。

全量回归: 463 passed(459 基线 + 4 新增),根目录与 tests/ 子目录同数。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-13 00:18:54 +08:00
浅念 3d6064dc14 docs: 上游吸收审查修补(注释纠偏/上游标点恢复/交叉引用闭合)
- test_lead_push_cc: 两处"双钉"注释与模块头改为如实的跨文件互补分工
  (常量同源钉本文件,字节级措辞钉 test_lead_push_service.py /
  test_email_rendering.py)
- chat_rest: _server_ip/_merge_client_info docstring 与调用点注释恢复
  上游半角标点原文(逐字同步,便于将来 diff 式跟上游)
- chat.py WS 自报注释补 REST 侧交叉引用,闭合悬空不对称说明

全量回归 459 passed(不变)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 23:44:02 +08:00
浅念 d1aed8e722 feat: 吸收上游 7 个测试文件断言与 placeholder 配置化对齐
上游 ai-kefu → phase1 吸收(Task 11 unit 12):
- 拷入 7 个测试文件,import/夹具按目标库重锚(app.engine.* / conftest
  async_db+build_jiancai_runtime / seed_profiles 提示词锚点)
- 补实现(同步自上游): chat_rest 服务端可信 IP(_server_ip/
  _merge_client_info,直连场景自报假 IP 不再原样落库);widget.js 与
  chat.js 的 data-placeholder 读取(叠加 Task 10 管道:data-* > brand >
  中性兜底,tests/test_placeholder_static.py 守卫)
- 断言重锚以 jc 主线为准: ev.contact_info 存裸号+等待尾注(e164 走
  _cc 派生)、source 值 fallback/customer_stated 口径、推送标注键
  号码补全说明、prompt 静态锚按租户(seed_profiles)双测
- 全量回归 459 passed(基线 421 + 吸收 38)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 23:19:02 +08:00
浅念 7697673a3b fix: 品牌下发审查修复(esc统一/语料中性化/穿越加固/反向断言动态化)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 22:52:08 +08:00
浅念 bbc7bc520e feat: brand 白名单下发(站点覆盖/租户头像/CORS) + widget/chat 客户端 key 租户化 + 会话站点标
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 22:26:15 +08:00
浅念 49e2b476f5 fix: 配置接线审查修复(push数值哨兵化/恒真测试修正/哨兵防漂移/种子映射消双路径)
Important-1: push 数值字段(timeout/max_attempts/retry_backoff_base)
出厂默认改 None 哨兵(与 ai.model 同款),resolve_push_settings 对 None
回退 env——根治 truthy 出厂默认永久遮住 env 覆盖;恒真测试修正(env 数值
patch 成 7.5/5/2.0 与出厂区分)+租户显式数值优先断言;ai.provider 遮
env 的边界记入 docstring。Minor-2: 出厂 model 哨兵与 DEFAULT_CONFIG
一致性测试 + defaults.py 双源注释(model/rate_limit_per_hour)。
Minor-4: allowed_seed_keys → context_seed_map(返回映射,单一取值路径)。
Minor-6/7/3/8: WS 配置冻结时机注释/name_to_region 查表序注释改准确/
chat_rest limit 0 语义注释/resolver None 路径仅供测试注释。404 全绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 21:57:57 +08:00
浅念 32b582aac8 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>
2026-10-12 21:37:48 +08:00
浅念 8453d3cc56 test: conn_limiter 差异覆盖与导入清理
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 21:05:54 +08:00
浅念 54a65ed7da feat: WS 每 IP 并发连接上限(默认10,(租户,IP) 键,finally 释放)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 20:54:28 +08:00
浅念 fd0f49870c fix: Host中间件审查修复(本地开发文档/顺序守护测试/ws断连分支/夹具清理)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 20:47:01 +08:00
浅念 eaa5bf7e51 feat: Host 中间件租户路由(纯ASGI覆盖WS/未知404/停用503暂停页/health豁免)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 20:30:30 +08:00
浅念 1824bb1590 test: PromptProvider 审查修复(组装缝断言/占位符约定文档与glob守护/边界注记)
- I-1: test_company_facts 捕获完整 prompt 的用例补话术池注入断言
  ("- EN:"/"- ZH:" 分组行在场)——守 AIService 组装缝,防 Task 9
  重接提示词线时静默丢池
- I-2: seed_profiles/README.md 落档 $DEFLECTION_POOL 占位符约定
  (缺失 = 话术池静默不注入);test_prompt_provider 占位符防漂移改
  glob 遍历 seed_profiles/*/prompts/system.md,第三租户自动纳管
  (空 glob 显性兜底,防假守护)
- Minor-1 注记: _format_deflection_pool docstring 记已知边界——条目
  含引号/换行暂不转义,Phase 2 编辑器批次处理
- Minor-5: test_provider_loads_from_tenant_dir 删恒真 or 侧,改单一
  明确断言;registry 加载期显性失败清单补 prompts 读取失败
  (FileNotFoundError 说明);conftest build_jiancai_runtime 注明
  data_dir 仅占位、从不 ensure_ready

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 20:16:40 +08:00
浅念 e34378257f feat: PromptProvider 化 + $DEFLECTION_POOL 单一事实源注入 + runtime 必填化
- PromptProvider(app/engine/services/ai_service.py): 租户提示词四件套
  from_dir 加载;build_system 把 system.md 的 $DEFLECTION_POOL 占位符替换为
  wall.json deflections 话术池(按语言分组一行,EN/ZH/ES)再拼事实卡;
  extractor/evaluator 的 $existing_info/$messages/$profile/$recent_messages
  替换逻辑自 AIService 原样搬入(行为等价);删模块级 import 时读文件的
  PROMPTS_DIR 与四个常量,保留 DEFAULT_PROVIDER(jiancai 出厂,__file__ 锚定)
- 两租户 system.md「三类请求的处理」第2条的迂回话术枚举 → $DEFLECTION_POOL
  占位符(保留段落说明文字),话术只存 wall.json 一份,改一处两边同步变
- TenantRuntime 加 prompts 字段(加载期 from_dir(seed_dir/prompts));
  ConversationManager 的 runtime 转必填(keyword-only),默认 AIService 用
  runtime.prompts + compiled_wall.deflections 组装
- app/engine/prompts/ 删除(grep 无代码消费方,jiancai 出厂由
  seed_profiles/jiancai/prompts 承接);test_company_facts/
  test_system_prompt_dual_contact 的 cwd 相对路径改 Path(__file__) 锚定,
  test_extractor_evaluator_prompts 断言对象改 DEFAULT_PROVIDER(语义等价)
- 新增 tests/test_prompt_provider.py(14 用例): 加载/注入/格式/占位符防漂移/
  extractor-evaluator 组装/registry 接线/runtime 必填/池线过两墙

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 19:54:47 +08:00
浅念 20dddc151e fix: 装配切换审查修复(启动异常路径韧性/清扫隔离/文案与夹具卫生)
- main.lifespan: 预热+清扫挪进 try,finally dispose_all 覆盖启动半途
  失败(幂等于更少引擎,堵 engine 泄漏);清扫循环体 per-tenant
  try/except + logger.exception 后继续——一个租户坏库不炸平台启动,
  resolve/load_from_dir 保持 fail-fast
- routes/runtime.py: RuntimeError 文案补 registry_reload dispose 旧
  runtime 成因;TenantRuntime 注解挪 TYPE_CHECKING(engine 包运行期
  零 import platform)
- conftest client: teardown 置空 app.state.registry(关残留窗);
  rmtree 先正常删,失败 warnings.warn 留痕后再 ignore_errors 兜底

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 19:37:51 +08:00
浅念 d041077bb6 feat: 装配切换——main/服务构造线/conftest 迁至 Registry(含默认租户过渡兜底)
- main.py: 删全局 engine/async_session;lifespan 装配 TenantRegistry
  (seed_profiles → 仓库根 tenants/,路径锚定),预热默认租户 jiancai 挂
  app.state.default_runtime,逐 active 租户(库文件已存在)跑
  sweep_stale_pending,退出 dispose_all。app.state.registry 预置即沿用
  (测试注入缝)
- routes/runtime.py(过渡,Task 7 删): get_runtime——state.tenant 优先,
  缺省落 default_runtime;chat.py/chat_rest.py 全部改走它,消除
  main↔routes 循环依赖
- ConversationManager 构造线: 新增 runtime 可选参(持 session_factory/
  compiled_wall/config 引用;prompts 仍模块级,Task 6;业务接线 Task 9),
  fire_pending_pushes 随任务传 session_factory(后台写回派发租户的库)
- lead_push_service: 去 app.main import;写库入口显式收 session_factory,
  模块级 async_session=None 仅作测试注入兜底
- conftest: client 夹具 = 每测试独立 Registry(tmp data_dir)+ 真实
  lifespan 在 TestClient 循环内预热;删 _dispose_main_engine;
  async_db 保持 NullPool(跨 asyncio.run 循环安全,刻意不换 Registry 引擎)
- 测试仅动夹具/桩签名(断言零改动): wiring 桩补 session_factory 形参;
  history-404 用例改经真实 WS 路由造 widget 会话(引擎常驻连接绑定
  TestClient 循环,测试线程不得直开 session_factory)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 19:15:46 +08:00
浅念 0c296ca1ba fix: Registry 审查修复(JSON定位/校验测试/竞态窗口/TenantDisabledError/路径锚定/seed_dir)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 18:54:30 +08:00
浅念 607baff83c feat: TenantRuntime/Registry——每租户懒建 engine(WAL/pool2)+文件加载器+站点解析
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 18:24:47 +08:00
浅念 f5f54383fc fix: 词表墙的四项审查修复(es 池降级/占位符白名单校验/键 allowlist/提取自检+防呆测试)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 18:05:55 +08:00
浅念 bc903a273e feat: 词表数据化——AST 提取脚本 + wall.json + 编译器 + boundary/conversation 数据源切换(等价回归全绿)
- scripts/extract_config.py: AST 解析两老项目源码取常量(不 import 源模块),
  生成 seed_profiles/<slug>/{wall.json, brand_values.json, prompts/};幂等可重跑
- app/engine/wall_schema.py: compile_wall(json)→CompiledWall,坏结构/坏 regex
  编译期显性失败(WallConfigError 含字段路径)
- boundary_filter/conversation: 墙词表/话术数据源切换为 DEFAULT_WALL
  (jiancai 出厂 seed),函数逻辑不动、常量名保留为 wall 视图(既有测试零修改);
  wall 数据化新增 pivots/pivots_contact/zero_number/reask_patterns 字段
- 脆锚点迁移: test_inline_prohibitions 断言对象从 conversation.py 源码改为
  wall.json 数据文件,语义等价(唯一允许的测试修改)
- 回归: 322 既有全绿 + 10 新增 wall_schema 测试 = 332;提取脚本两遍无 diff

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 17:31:57 +08:00
浅念 8a16a2959b test: 钉住 deep_merge 的 None 替换与列表替换语义 + 只读约定注释
- characterization:显式 None 整体替换且兄弟键保留默认(Task 9 回退契约依赖);列表整体替换不与默认拼接
- DEFAULT_CONFIG 与 TenantConfig.data/Site.brand 补只读约定注释
- platform 包依赖章程改明确:defaults/tenant_config 为叶子模块供 engine 反向消费,registry 组装层可 import app/engine

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 16:59:31 +08:00
浅念 89339868db feat: 出厂默认与快照深合并(E4 配置演进)
- app/platform/defaults.py:DEFAULT_CONFIG(spec §5.1 九组,brand/wall 待 Task 4 填充)+ deep_merge(补缺/不动入参/兄弟保留)
- app/platform/tenant_config.py:TenantConfig/Site frozen dataclass;site.brand 以租户级 data["brand"] 为合并基线,租户自定义可被站点继承
- tests/test_config_merge.py:merge 三性质 + 站点覆盖/继承/无 sites 共 5 用例

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 16:44:49 +08:00
浅念 603c03eb4a feat: jc 引擎主线搬入 app/engine(315 测试基线全绿:320 去掉 admin 5 用例)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-12 16:25:32 +08:00