fix: 终审修复——站点停用接线/prefix查重补创建reset/默认凭据警示+取舍补录

- I-1 站点停用全链接线: Site 数据类加 status 字段; DB 源 _load_one 与
  文件源 read_tenant 均只输出 active 站点(停用站点域名不进 registry
  索引 → 该域名 404;全停用=合法运营状态输出空 sites;文件源无 status
  键默认 active 兼容)。E2E: PATCH 站点 disabled → 其域名 404、复启用
  恢复;源级直测两源过滤。
- I-3 prefix 跨租户查重补两口: db.other_push_prefixes 共用助手
  (MAX(version) 逐租户当前前缀,排除自身);创建向导(出厂档案前缀被占
  → 400 提示改 blank/改占用方)与 reset push(重置回出厂撞车 → 400 提示
  走 PUT)接入;PUT 原有查重改用同一助手。rollback 维持豁免(历史不可变
  语义优先,取舍清单记档)。既有测试第二租户改 blank profile 避撞。
- I-4 默认凭据警示: lifespan 启动检测 ADMIN_PASSWORD 仍为 Settings 字段
  默认值(非硬编码第二份,防双源漂移)→ logger.warning 醒目提示;
  CLAUDE.md Phase 4 部署记档补 ADMIN_PASSWORD 生产要求。
- I-2/M-2 取舍补录: 密钥掩码未实现(GET config/settings 明文返回
  api_key/smtp 密码,Phase 3 前须定 __SET__ 哨兵方案);站点管理权限现为
  仅超管(Phase 3 对接时决策放开或改 spec);取舍清单第 2 条同步刷新
  (rollback 现为唯一豁免口)。

全量回归: 571 passed(基线 566 + 新增 5)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-13 12:40:21 +08:00
parent 6cd343e24a
commit 6839cb94d2
14 changed files with 281 additions and 52 deletions
+18 -4
View File
@@ -114,6 +114,12 @@ class FileTenantSource:
sites = tenant_json.get("sites") or []
if not sites:
raise ValueError(f"{slug}: 每租户至少一个站点(sites 为空)")
# 站点停用过滤(终审 I-1,与 DB 源同一语义):status 键缺省 = active
# (既有 tenant.json 均无该键,兼容);停用站点不进 LoadedTenant——
# 域名随之不进 registry 索引(该域名 404)、site_by_slug 取不到。
sites = [s for s in sites
if not isinstance(s, dict)
or s.get("status", "active") == "active"]
# wall 并入 snapshot["wall"]:data["wall"] 保留原始词表(后台编辑/
# 回滚用),编译产物挂 runtime.compiled_wall(引擎消费,单一编译)
snapshot = dict(tenant_json.get("config") or {})
@@ -148,8 +154,10 @@ class DbTenantSource:
的 config_json 解析。版本快照由 Task 5 创建向导写入(config 组 ⊕ wall
⊕ prompts 同构嵌套)。
已知边界:site.status 列暂不参与映射(全量输出)——Task 5 站点
CRUD/停用接线时定语义。
已知边界(终审 I-1 已接线):site.status != "active" 的站点**不进**
LoadedTenant(_load_one 过滤)——停用站点的域名不进 registry 索引
(该域名 404),site_by_slug 取不到;全停用输出空 sites(零站点校验
只对库表形状)。
"""
def __init__(self, engine: AsyncEngine):
@@ -215,10 +223,16 @@ class DbTenantSource:
f"{version.version} 的 config_json 缺少 {key!r} 配置组"
f"(或其不是对象)")
sites = [{"slug": s.slug, "name": s.name,
# 站点停用过滤(终审 I-1):status != "active" 的站点不进
# LoadedTenant——其域名不进 registry 域名索引(该域名 404)、
# site_by_slug 取不到。与"租户停用 → TenantDisabledError → 503
# 中性页"的语义差:站点停用 = 这张门面下线,404 合理(不是服务暂停)。
# 全部站点停用 = 输出空 sites(零站点校验只对库表形状——行数为零
# 才是数据坏;全停用是合法运营状态,域名全 404)。
sites = [{"slug": s.slug, "name": s.name, "status": s.status,
"domains": list(domains_by_site.get(s.id, [])),
"brand": dict(s.brand_overlay or {})}
for s in sites_rows]
for s in sites_rows if s.status == "active"]
return LoadedTenant(
slug=tenant.slug,
name=tenant.name,