补充 lsfx 命中模式前后端实施计划
This commit is contained in:
@@ -0,0 +1,331 @@
|
||||
# LSFX Mock Rule Hit Mode Backend Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 为 `lsfx-mock-server` 增加可通过命令行切换的规则命中模式,在默认保持稳定随机子集命中的前提下,支持切换为“全部兼容规则命中”。
|
||||
|
||||
**Architecture:** 保持现有 `FileService -> StatementService -> FileRecord 缓存` 主链路不变,只在启动层新增命令行参数解析,在配置层新增统一模式值,在规则计划层新增 `subset/all` 两种编排路径。`all` 模式不做字面全开,而是通过显式互斥组裁剪产出“全部兼容规则命中”计划,避免样本语义冲突。
|
||||
|
||||
**Tech Stack:** Python 3, FastAPI, uvicorn, pydantic-settings, pytest, Markdown
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- `lsfx-mock-server/config/settings.py`: 新增 `RULE_HIT_MODE` 配置项,统一暴露规则命中模式。
|
||||
- `lsfx-mock-server/main.py`: 新增普通启动命令行参数解析,并在启动前校验模式值。
|
||||
- `lsfx-mock-server/dev.py`: 新增热重载启动入口,支持 `--reload --rule-hit-mode ...`。
|
||||
- `lsfx-mock-server/services/file_service.py`: 为 `subset/all` 两种模式生成命中计划,并显式维护互斥组裁剪逻辑。
|
||||
- `lsfx-mock-server/tests/test_file_service.py`: 锁定默认随机子集模式、`all` 模式全集逻辑和互斥组行为。
|
||||
- `lsfx-mock-server/tests/test_startup.py`: 锁定命令行参数解析、非法参数报错和热重载启动参数透传。
|
||||
- `lsfx-mock-server/README.md`: 更新普通启动、热重载启动与“全部兼容规则命中”的准确说明。
|
||||
- `docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-backend-record.md`: 记录本次后端实施范围、命中模式语义和落地结果。
|
||||
- `docs/tests/records/2026-03-22-lsfx-rule-hit-mode-backend-verification.md`: 记录测试命令、启动验证和进程清理结果。
|
||||
|
||||
### Task 1: 接入命令行启动参数并统一规则命中模式配置
|
||||
|
||||
**Files:**
|
||||
- Modify: `lsfx-mock-server/config/settings.py`
|
||||
- Modify: `lsfx-mock-server/main.py`
|
||||
- Create: `lsfx-mock-server/dev.py`
|
||||
- Create: `lsfx-mock-server/tests/test_startup.py`
|
||||
- Reference: `docs/superpowers/specs/2026-03-22-lsfx-rule-hit-mode-design.md`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
先在 `lsfx-mock-server/tests/test_startup.py` 中补三条失败用例,锁定启动参数语义:
|
||||
|
||||
```python
|
||||
import pytest
|
||||
|
||||
from main import parse_args as parse_main_args
|
||||
from dev import parse_args as parse_dev_args
|
||||
|
||||
|
||||
def test_main_parse_args_should_default_to_subset():
|
||||
args = parse_main_args([])
|
||||
assert args.rule_hit_mode == "subset"
|
||||
|
||||
|
||||
def test_main_parse_args_should_accept_all_mode():
|
||||
args = parse_main_args(["--rule-hit-mode", "all"])
|
||||
assert args.rule_hit_mode == "all"
|
||||
|
||||
|
||||
def test_dev_parse_args_should_reject_invalid_mode():
|
||||
with pytest.raises(SystemExit):
|
||||
parse_dev_args(["--rule-hit-mode", "invalid"])
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python3 -m pytest tests/test_startup.py -v
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `FAIL`
|
||||
- 原因是 `main.py` 与热重载入口尚未提供可测试的参数解析函数
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
按最小路径实现:
|
||||
|
||||
1. 在 `config/settings.py` 中新增默认配置:
|
||||
|
||||
```python
|
||||
RULE_HIT_MODE: str = "subset"
|
||||
```
|
||||
|
||||
2. 在 `main.py` 中新增参数解析函数,只允许 `subset|all`:
|
||||
|
||||
```python
|
||||
def parse_args(argv=None):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--rule-hit-mode", choices=["subset", "all"], default="subset")
|
||||
return parser.parse_args(argv)
|
||||
```
|
||||
|
||||
3. 在 `main.py` 启动前,将 `rule_hit_mode` 写入环境变量,再初始化/读取 `settings`。
|
||||
4. 新增 `dev.py`,复用同一套参数解析,支持:
|
||||
|
||||
```bash
|
||||
python dev.py --reload --rule-hit-mode all
|
||||
```
|
||||
|
||||
5. `dev.py` 内部调用 `uvicorn.run("main:app", reload=True, ...)` 或等价方式,不再要求用户直接运行裸 `uvicorn main:app --reload ...`。
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python3 -m pytest tests/test_startup.py -v
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- 默认模式为 `subset`
|
||||
- `all` 模式可被普通启动与热重载入口正确解析
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add lsfx-mock-server/config/settings.py lsfx-mock-server/main.py lsfx-mock-server/dev.py lsfx-mock-server/tests/test_startup.py
|
||||
git commit -m "补充Mock规则命中模式启动参数"
|
||||
```
|
||||
|
||||
### Task 2: 在 FileService 中实现全部兼容规则命中计划
|
||||
|
||||
**Files:**
|
||||
- Modify: `lsfx-mock-server/services/file_service.py`
|
||||
- Modify: `lsfx-mock-server/tests/test_file_service.py`
|
||||
- Reference: `lsfx-mock-server/services/statement_rule_samples.py`
|
||||
- Reference: `docs/superpowers/specs/2026-03-22-lsfx-rule-hit-mode-design.md`
|
||||
|
||||
- [ ] **Step 1: Write the failing test**
|
||||
|
||||
在 `lsfx-mock-server/tests/test_file_service.py` 中先补失败用例,锁定 `all` 模式语义:
|
||||
|
||||
```python
|
||||
def test_build_rule_hit_plan_should_return_all_compatible_rules_in_all_mode(monkeypatch):
|
||||
monkeypatch.setattr("services.file_service.settings.RULE_HIT_MODE", "all")
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
plan = service._build_rule_hit_plan(10001)
|
||||
|
||||
assert plan["large_transaction_hit_rules"] == LARGE_TRANSACTION_RULE_CODES
|
||||
assert plan["phase1_hit_rules"] == PHASE1_RULE_CODES
|
||||
assert plan["phase2_statement_hit_rules"] == PHASE2_STATEMENT_RULE_CODES
|
||||
assert plan["phase2_baseline_hit_rules"] == PHASE2_BASELINE_RULE_CODES
|
||||
|
||||
|
||||
def test_build_rule_hit_plan_should_keep_subset_mode_as_default():
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
plan1 = service._build_rule_hit_plan(10001)
|
||||
plan2 = service._build_rule_hit_plan(10001)
|
||||
|
||||
assert plan1 == plan2
|
||||
assert 2 <= len(plan1["large_transaction_hit_rules"]) <= 4
|
||||
|
||||
|
||||
def test_build_rule_hit_plan_should_drop_conflicting_rules_from_all_mode(monkeypatch):
|
||||
monkeypatch.setattr("services.file_service.settings.RULE_HIT_MODE", "all")
|
||||
monkeypatch.setattr(
|
||||
"services.file_service.RULE_CONFLICT_GROUPS",
|
||||
[["SALARY_QUICK_TRANSFER", "SALARY_UNUSED"]],
|
||||
)
|
||||
service = FileService(staff_identity_repository=FakeStaffIdentityRepository())
|
||||
|
||||
plan = service._build_rule_hit_plan(10001)
|
||||
|
||||
assert not (
|
||||
"SALARY_QUICK_TRANSFER" in plan["phase2_statement_hit_rules"]
|
||||
and "SALARY_UNUSED" in plan["phase2_statement_hit_rules"]
|
||||
)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python3 -m pytest tests/test_file_service.py -k "rule_hit_plan" -v
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `FAIL`
|
||||
- 原因是当前 `_build_rule_hit_plan()` 只有稳定随机子集逻辑,尚无模式切换和互斥裁剪
|
||||
|
||||
- [ ] **Step 3: Write minimal implementation**
|
||||
|
||||
在 `lsfx-mock-server/services/file_service.py` 中按职责做最小拆分:
|
||||
|
||||
1. 保留现有四类规则池常量。
|
||||
2. 新增互斥组常量,第一版允许为空列表:
|
||||
|
||||
```python
|
||||
RULE_CONFLICT_GROUPS = []
|
||||
```
|
||||
|
||||
3. 新增模式编排辅助函数:
|
||||
|
||||
```python
|
||||
def _build_subset_rule_hit_plan(self, log_id: int) -> dict:
|
||||
...
|
||||
|
||||
|
||||
def _build_all_compatible_rule_hit_plan(self) -> dict:
|
||||
...
|
||||
|
||||
|
||||
def _apply_conflict_groups(self, rule_plan: dict) -> dict:
|
||||
...
|
||||
```
|
||||
|
||||
4. `_build_rule_hit_plan()` 只负责分发:
|
||||
|
||||
```python
|
||||
if settings.RULE_HIT_MODE == "all":
|
||||
return self._apply_conflict_groups(self._build_all_compatible_rule_hit_plan())
|
||||
return self._build_subset_rule_hit_plan(log_id)
|
||||
```
|
||||
|
||||
5. 不修改 `FileRecord` 字段结构和后续消费链路,只改变计划生成方式。
|
||||
|
||||
- [ ] **Step 4: Run test to verify it passes**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python3 -m pytest tests/test_file_service.py -k "rule_hit_plan" -v
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- 默认仍为随机子集
|
||||
- `all` 模式返回全部兼容规则
|
||||
- 若未来配置互斥组,同组规则不会同时出现在结果里
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add lsfx-mock-server/services/file_service.py lsfx-mock-server/tests/test_file_service.py
|
||||
git commit -m "补充Mock全部兼容规则命中计划"
|
||||
```
|
||||
|
||||
### Task 3: 更新文档并完成后端验证记录
|
||||
|
||||
**Files:**
|
||||
- Modify: `lsfx-mock-server/README.md`
|
||||
- Create: `docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-backend-record.md`
|
||||
- Create: `docs/tests/records/2026-03-22-lsfx-rule-hit-mode-backend-verification.md`
|
||||
|
||||
- [ ] **Step 1: Update README with accurate startup instructions**
|
||||
|
||||
更新 `lsfx-mock-server/README.md`:
|
||||
|
||||
- 普通启动示例改为:
|
||||
|
||||
```bash
|
||||
python main.py --rule-hit-mode subset
|
||||
python main.py --rule-hit-mode all
|
||||
```
|
||||
|
||||
- 热重载示例改为:
|
||||
|
||||
```bash
|
||||
python dev.py --reload --rule-hit-mode subset
|
||||
python dev.py --reload --rule-hit-mode all
|
||||
```
|
||||
|
||||
- 文案统一使用“全部兼容规则命中”,不使用“全部规则命中”。
|
||||
|
||||
- [ ] **Step 2: Run targeted verification**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python3 -m pytest tests/test_startup.py tests/test_file_service.py -k "rule_hit_plan or parse_args" -v
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- `PASS`
|
||||
- 启动参数与规则计划两条主链路均被锁定
|
||||
|
||||
- [ ] **Step 3: Run startup smoke tests and stop processes**
|
||||
|
||||
分别执行并记录:
|
||||
|
||||
```bash
|
||||
cd lsfx-mock-server
|
||||
python3 main.py --rule-hit-mode all > /tmp/lsfx_main.log 2>&1 & echo $! > /tmp/lsfx_main.pid
|
||||
sleep 3
|
||||
kill "$(cat /tmp/lsfx_main.pid)"
|
||||
rm -f /tmp/lsfx_main.pid
|
||||
|
||||
python3 dev.py --reload --rule-hit-mode all > /tmp/lsfx_dev.log 2>&1 & echo $! > /tmp/lsfx_dev.pid
|
||||
sleep 5
|
||||
kill "$(cat /tmp/lsfx_dev.pid)"
|
||||
rm -f /tmp/lsfx_dev.pid
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 两种启动方式均成功拉起
|
||||
- 结束验证后无残留进程
|
||||
|
||||
- [ ] **Step 4: Write implementation and verification records**
|
||||
|
||||
在实施记录中写清:
|
||||
|
||||
- 默认模式保持不变
|
||||
- `all` 的准确语义是“全部兼容规则命中”
|
||||
- 当前互斥组为空或具体清单
|
||||
- 热重载改为项目脚本入口
|
||||
|
||||
在验证记录中写清:
|
||||
|
||||
- 测试命令及结果
|
||||
- 启动验证命令及结果
|
||||
- 进程清理动作
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add lsfx-mock-server/README.md docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-backend-record.md docs/tests/records/2026-03-22-lsfx-rule-hit-mode-backend-verification.md
|
||||
git commit -m "补充Mock命中模式后端实施与验证记录"
|
||||
```
|
||||
@@ -0,0 +1,119 @@
|
||||
# LSFX Mock Rule Hit Mode Frontend Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 明确本次 `lsfx-mock-server` 规则命中模式切换不引入前端代码改动,同时完成对前端接口契约和页面影响面的核验。
|
||||
|
||||
**Architecture:** 本次需求仅作用于 Mock 服务启动方式与命中计划生成逻辑,不新增接口字段、页面交互、路由或状态管理逻辑。前端计划采用“零代码变更 + 契约核验 + 文档记录”的最短路径;若核验发现契约漂移,则停止执行并回到设计阶段,不在本计划中临时扩展实现。
|
||||
|
||||
**Tech Stack:** Vue 2, Axios request wrapper, npm, Markdown
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
- `ruoyi-ui/src/api/`: 本次预期不修改,只用于核验现有接口封装是否依赖 Mock 启动方式或新增字段。
|
||||
- `ruoyi-ui/src/views/`: 本次预期不修改,只用于核验与流水拉取、标签结果、流水明细相关页面是否无需联动调整。
|
||||
- `docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-frontend-record.md`: 记录本次前端零代码改动的范围说明。
|
||||
- `docs/tests/records/2026-03-22-lsfx-rule-hit-mode-frontend-verification.md`: 记录前端契约核验与页面影响判断依据。
|
||||
|
||||
### Task 1: 核验前端接口契约与页面触点不受影响
|
||||
|
||||
**Files:**
|
||||
- Reference: `ruoyi-ui/src/api/`
|
||||
- Reference: `ruoyi-ui/src/views/`
|
||||
- Reference: `docs/superpowers/specs/2026-03-22-lsfx-rule-hit-mode-design.md`
|
||||
|
||||
- [ ] **Step 1: Identify existing frontend touchpoints**
|
||||
|
||||
检查以下触点,不写任何前端源码:
|
||||
|
||||
- 与“拉取本行信息”相关的接口封装
|
||||
- 与项目打标、结果总览、流水详情相关的调用链
|
||||
- 是否存在对 Mock 启动方式、端口或命中模式的前端硬编码依赖
|
||||
|
||||
- [ ] **Step 2: Verify no contract change is required**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd ruoyi-ui
|
||||
rg -n "getJZFileOrZjrcuFile|getBSByLogId|tag|result|statement" src
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 只命中现有接口调用和结果展示代码
|
||||
- 未发现前端依赖新增请求参数或新增响应字段
|
||||
|
||||
- [ ] **Step 3: Stop if any contract drift is found**
|
||||
|
||||
若核验发现以下任一情况,则停止,不做补丁式前端改造:
|
||||
|
||||
- 后端返回结构新增前端必填字段
|
||||
- 页面需要新增新的命中模式展示入口
|
||||
- 现有页面对热重载脚本入口有直接依赖
|
||||
|
||||
若未发现,则维持前端零代码改动。
|
||||
|
||||
- [ ] **Step 4: Record the no-op decision**
|
||||
|
||||
在实施记录中明确写明:
|
||||
|
||||
- 本次需求仅影响 Mock 服务
|
||||
- 前端页面、接口封装、路由、权限和状态管理均无需改动
|
||||
- 不为“展示模式切换”新增无业务价值 UI
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-frontend-record.md docs/tests/records/2026-03-22-lsfx-rule-hit-mode-frontend-verification.md
|
||||
git commit -m "记录Mock命中模式前端零改动结论"
|
||||
```
|
||||
|
||||
### Task 2: 补充前端实施与验证记录
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-frontend-record.md`
|
||||
- Create: `docs/tests/records/2026-03-22-lsfx-rule-hit-mode-frontend-verification.md`
|
||||
|
||||
- [ ] **Step 1: Write implementation record**
|
||||
|
||||
在 `docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-frontend-record.md` 中记录:
|
||||
|
||||
- 需求范围仅涉及 `lsfx-mock-server`
|
||||
- 前端无新增字段、无新增交互、无新增构建要求
|
||||
- 维持零代码改动是本次需求的最短正确路径
|
||||
|
||||
- [ ] **Step 2: Write verification record**
|
||||
|
||||
在 `docs/tests/records/2026-03-22-lsfx-rule-hit-mode-frontend-verification.md` 中记录:
|
||||
|
||||
- 核验范围
|
||||
- 检查命令
|
||||
- “无需前端改动”的依据
|
||||
- 最终结论
|
||||
|
||||
- [ ] **Step 3: Confirm build is not required**
|
||||
|
||||
若前端源码无改动,则不执行 `npm run build:prod`;在验证记录中明确写明“本次为零代码变更核验,因此未执行前端构建”。
|
||||
|
||||
- [ ] **Step 4: Verify git diff stays docs-only**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
git diff --name-only -- ruoyi-ui
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
- 无输出
|
||||
- 证明本次前端计划执行期间没有引入前端源码改动
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/reports/implementation/2026-03-22-lsfx-rule-hit-mode-frontend-record.md docs/tests/records/2026-03-22-lsfx-rule-hit-mode-frontend-verification.md
|
||||
git commit -m "补充Mock命中模式前端核验记录"
|
||||
```
|
||||
Reference in New Issue
Block a user