feat(web): 项目级配置 + 会话命名/历史 + 设计文档纳入影响调查

- 会话支持 name/project 字段,上传要件定义后自动命名;前端侧边栏会话历史 + localStorage 恢复,顶部只显示会话名
- 新增 ProjectsStore(SQLite)与 /api/projects CRUD;绑定项目后 _rebuild_source 合并模板/规则/代码库/设计文档,上传区仅要件定义
- StructuredSource.design_docs 与 ImpactReport.design_references;影响调查新增既有设计文档确定性交叉引用(无 LLM)
- 同步更新 docs/design.md §12.7、README、_AI_USAGE_LOG.md;全量测试 558 通过,覆盖率 99.10%
This commit is contained in:
lhl
2026-08-27 12:13:28 +08:00
parent 838a93720e
commit 916c5beed7
18 changed files with 1174 additions and 65 deletions
+39 -2
View File
@@ -3,9 +3,9 @@ import pytest
from genesis.data_models import (
CellValue, ChangeType, ControllerInfo, EntityInfo, ExcelTable,
ExistingSystemInfo, Provenance, ServiceInfo, SheetType, StructuredSource,
ExistingSystemInfo, Provenance, RuleDocument, ServiceInfo, SheetType, StructuredSource,
)
from genesis.impact.impact_agent import ImpactAgent
from genesis.impact.impact_agent import ImpactAgent, impact_report_to_dict
def _cv(value) -> CellValue:
@@ -201,3 +201,40 @@ def test_impact_report_to_dict_serializable():
assert d["change_analysis"]["new_elements"][0]["change_type"] == "新規"
assert d["change_analysis"]["modified_elements"][0]["impacted_existing"] == ["OrderController"]
assert d["summary"]["modified"] == 1
def _doc(name: str, content: str) -> RuleDocument:
return RuleDocument(file_name=name, category="design", markdown_content=content,
source_path=name, file_type="word", hash="h")
def _ss_with_design(existing, tables, docs) -> StructuredSource:
return StructuredSource(tables=tables, template=None, rule_docs=[], image_analyses=[],
existing_system=existing, comments=[], design_docs=docs)
def test_design_doc_cross_reference_hits_identifier():
docs = [_doc("design_a.docx", "本章描述 OrderController 的限价单处理逻辑与风控。")]
tables = [_table("機能一覧", SheetType.FUNCTION, [_row("F001", "新功能", "新規", "")])]
report = ImpactAgent().run(_ss_with_design(_existing(), tables, docs), session_id="d")
refs = report.design_references
ids = {r.identifier for r in refs}
assert "OrderController" in ids
assert refs[0].doc_name == "design_a.docx"
assert "OrderController" in refs[0].snippet
# 序列化也包含
assert any(r["identifier"] == "OrderController"
for r in impact_report_to_dict(report)["design_references"])
def test_design_doc_cross_reference_empty_when_no_docs():
tables = [_table("機能一覧", SheetType.FUNCTION, [_row("F001", "新功能", "新規", "")])]
report = ImpactAgent().run(_ss_with_design(_existing(), tables, []), session_id="d")
assert report.design_references == []
def test_design_doc_with_empty_content_skipped():
docs = [_doc("empty.docx", "")] # 无正文 → continueline 164
tables = [_table("機能一覧", SheetType.FUNCTION, [_row("F001", "新功能", "新規", "")])]
report = ImpactAgent().run(_ss_with_design(_existing(), tables, docs), session_id="d")
assert report.design_references == [] # 无正文设计文档被跳过,line 165 正常执行