回复 ZSY 的底座扩展确认;登记 docs/00 的一处已知偏差;更新 AGENTS.md 过期口径
## 对 ZSY 三件事的核实与裁决(docs/33-ZSY底座扩展确认-回复.md) 1. **访客身份**:`data_scope="public"` 我扫了全平台 26 个消费点,对未知值的行为一致 fail closed(6 处 `== "all"` 判假、1 处 `!= "all"` 会要求 customer_ids 非空否则 403、 1 处显式白名单直接拒),**安全,不用改**。但有一条硬约束必须先确认:全平台有 **72 处 `int(context.user_id)`,只有 3 处做了防御**——若访客的 sub 不是纯数字, 其中"权限被拒时要写审计"的路径会把本该 403 的情况变成 500。已要求他确认 sub 为纯十进制数字、且 visitor 分支复用同一套 `jwt.decode`(含 isdecimal 校验), 而不是另写第二个鉴权入口。 2. **客服 Agent**:`allowed_roles` 扩集合与确定性安全路由可接受;`recalls_customer_memory` 是新声明字段,已要求**默认值必须是 True**(否则会静默关掉所有既有 Agent 的记忆召回, 界面看不出来、只表现为回答变差)。品牌名(南方科技 → 奶龙基金责任有限公司)属业务 口径,已上报项目方定,不由技术侧拍板。 3. **current_customer_id**:**他的判断正确**。我独立实测 information_schema: `EXTRA=''` 且 `GENERATION_EXPRESSION=''`,配合 baseline_generated.sql 无 GENERATED 子句、seed_profile_demo.py 的注释、profile_repository.py 用原生 SQL 显式写入, 四处一致 ⇒ `docs/00` 第 783 行"生成列"的描述是错的。处置:按真实 schema 映射成 普通可空列、**不改 docs/00**(规则 1)、**不补迁移**(DDL 本身正确,为让文档成真而加 生成列会改变既有列语义,违反规则 4)、但**必须登记这处偏差**。 另:他删了两个死代码文件(含一处硬编码 Milvus 字段名,违反 AGENTS.md §E),方向认同, 但要求他在 PR 里附上两条 git grep 的实际输出以证明"全仓唯一引用是它自己的单测"。 ## 落实我在回复里承诺的两件事 - `docs/08-数据库结构审计基线.md` 新增"六、已知文档偏差",逐条登记上述偏差(含四处 证据与处置口径),并注明发现方式; - `AGENTS.md` 环境口径新增 `MILVUS_LOCAL_URI` 的坑:配了会让健康检查与部分检索指向 本地 Milvus Lite 文件,出现"健康检查正常、实际查的是另一个库";并注明 `milvus-lite` 属本地开发依赖,应放 `optional-dependencies` 而非主依赖。 ## 顺带更新 AGENTS.md 的过期口径 - 表数 68 → **89**(场内 51 + 场外/推广 17 + 投顾 21),并注明投顾那 21 张的登记文档待补; - 测试基线从"1034 passed / 1 failed"改为实测值:ruff 干净 / mypy 228 文件 0 错 / 1207 passed 0 failed / integration 99 passed,并指向 docs/32; - mypy 那条从"本机 181 错、双方不可比"改成可操作的判据:先对版本,根因是某一侧虚拟环境 没满足 pyproject 的 sqlalchemy>=2.0,<3 / mypy>=1.14,<2;并写明**不要装 sqlalchemy2-stubs** (那是给 1.4 的,2.0 自带 py.typed,装了反而按 1.4 API 报一批新错)。 文档守卫:42 份无编号冲突。
This commit is contained in:
@@ -72,9 +72,12 @@
|
|||||||
|
|
||||||
- 解释器:本机用 **`.\.venv\Scripts\python.exe`**;架构师环境用 `D:\conda\envs\jr_py313\python.exe`。
|
- 解释器:本机用 **`.\.venv\Scripts\python.exe`**;架构师环境用 `D:\conda\envs\jr_py313\python.exe`。
|
||||||
两者等价,**各用本机可用的那个**(`.venv` 被 `.gitignore` 忽略、不进仓库,不存在"需要统一"的问题)。
|
两者等价,**各用本机可用的那个**(`.venv` 被 `.gitignore` 忽略、不进仓库,不存在"需要统一"的问题)。
|
||||||
- 数据库现为 **69 张表**(含 `alembic_version`)= **68 张业务表** = **场内 51 + 场外/推广 17**。
|
- 数据库现为 **90 张表**(含 `alembic_version`)= **89 张业务表** =
|
||||||
后 17 张(`offsite_*` / `promotion_*`)**不进 `docs/00` 基线**(规则 8:场外基金运营流程独立),
|
**场内 51 + 场外/推广 17 + 投顾 21**。
|
||||||
逐表登记见 `docs/28-场外与推广域数据表登记.md`。核验命令:`python tools/audit_schema.py`。
|
后 38 张(`offsite_*` / `promotion_*` / `advisor_*`)**不进 `docs/00` 基线**(规则 8):
|
||||||
|
场外/推广那 17 张逐表登记见 `docs/28-场外与推广域数据表登记.md`;
|
||||||
|
**投顾那 21 张的登记文档待补**(按同样口径另立一份)。
|
||||||
|
核验命令:`python tools/audit_schema.py`(若报 `unexpected` 先分清是"库里多表"还是"迁移没进来")。
|
||||||
- 已注册业务 Agent:`FundQueryDemoAgent`、`CustomerServiceAgent`、`RiskAgent`、`PlatformProbeAgent`(见 `app/service/agent/bootstrap.py`)。
|
- 已注册业务 Agent:`FundQueryDemoAgent`、`CustomerServiceAgent`、`RiskAgent`、`PlatformProbeAgent`(见 `app/service/agent/bootstrap.py`)。
|
||||||
- 已注册公共只读工具:`search_knowledge`(客服知识检索)、`check_suitability`、`query_customer_profile`(画像)、`query_fund_quote`;
|
- 已注册公共只读工具:`search_knowledge`(客服知识检索)、`check_suitability`、`query_customer_profile`(画像)、`query_fund_quote`;
|
||||||
**工具可用范围 = 代码上限 ∩ 当前 active `config_release` 的发布白名单**,缺发布配置则失败关闭。
|
**工具可用范围 = 代码上限 ∩ 当前 active `config_release` 的发布白名单**,缺发布配置则失败关闭。
|
||||||
@@ -86,7 +89,15 @@
|
|||||||
(`app/core/knowledge_schema.py`)——**不要在任何地方硬编码字段名**,那会把另一套环境打挂。
|
(`app/core/knowledge_schema.py`)——**不要在任何地方硬编码字段名**,那会把另一套环境打挂。
|
||||||
- ⚠️ **Docker Desktop 不会常驻**:它没运行时 Milvus 不可用(`docker` CLI 报连不上守护进程)。
|
- ⚠️ **Docker Desktop 不会常驻**:它没运行时 Milvus 不可用(`docker` CLI 报连不上守护进程)。
|
||||||
跑真机验证前先确认 Docker Desktop 在运行。
|
跑真机验证前先确认 Docker Desktop 在运行。
|
||||||
- 测试基线:`1 failed, 1034 passed, 2 skipped`(2026-09-11 实测);唯一失败是 `tests/unit/repository/test_fund_readonly_contract.py`(**底座既有缺陷,不要修也不要报**)。
|
- ⚠️ **`MILVUS_LOCAL_URI` 配了就会"看着正常、查的是另一个库"**:一旦在 `.env` 里设置它,
|
||||||
- mypy:本机 `mypy app` 报 181 个错,其中 170 个集中在 `app/model/` 的模型文件(**本机未安装 `sqlalchemy2-stubs`**,
|
健康检查与部分检索链路会指向本地 **Milvus Lite 文件**。团队/生产环境请**保持该变量为空**。
|
||||||
SQLAlchemy 的 `BIGINT`/`DATETIME` 被判成未类型化函数);架构师环境报 0 错。
|
对应的 `milvus-lite` 属**本地开发依赖**,应放在 `pyproject.toml` 的
|
||||||
**这个数字双方不可比**,不要拿它当结论;只需保证"不比自己改动前更多"。
|
`optional-dependencies`,**不要进主 `dependencies`**。
|
||||||
|
- 测试基线(2026-09-11 架构师环境实测):`ruff` 干净 / `mypy app` **228 个文件 0 错** /
|
||||||
|
`pytest tests/unit tests/contract` → **1207 passed, 2 skipped, 0 failed** /
|
||||||
|
`pytest tests/integration` → **99 passed**。完整口径与联调清单见
|
||||||
|
`docs/32-平台侧交接与联调准备.md`。
|
||||||
|
- ⚠️ **mypy 与测试数必须带环境读**:出现"一边上百个错、另一边 0 错"时先对版本,别当代码质量问题。
|
||||||
|
已知根因是某一侧的虚拟环境没满足 `pyproject.toml` 的 `sqlalchemy>=2.0,<3` / `mypy>=1.14,<2`。
|
||||||
|
**不要装 `sqlalchemy2-stubs`** —— 那是给 SQLAlchemy 1.4 的,2.0 自带 `py.typed`,
|
||||||
|
装了反而按 1.4 的 API 报一批新错(`mapped_column` / `DeclarativeBase` 不存在)。
|
||||||
|
|||||||
@@ -84,3 +84,17 @@ ORM 映射 ↔ 库列名(生成列单独归类为 note)。任一不一致返
|
|||||||
|
|
||||||
数据库约束仍以 `docs/00-新数据库基线设计.md` 为业务权威。指纹与约束审计只证明结构一致,
|
数据库约束仍以 `docs/00-新数据库基线设计.md` 为业务权威。指纹与约束审计只证明结构一致,
|
||||||
不替代状态机、并发语义和跨存储投影(Milvus/Neo4j)的业务验收。
|
不替代状态机、并发语义和跨存储投影(Milvus/Neo4j)的业务验收。
|
||||||
|
|
||||||
|
## 六、已知文档偏差(`docs/00` 与真实 schema 不一致之处)
|
||||||
|
|
||||||
|
`docs/00` 是不可变业务基线(`AGENTS.md` 规则 1),**不因下列偏差修改**;但偏差必须登记,
|
||||||
|
否则每换一个人接手就会重新踩一次。发现新偏差请追加到本节。
|
||||||
|
|
||||||
|
| # | 位置 | 文档描述 | 真实 schema | 处置 |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | `profile_snapshots.current_customer_id` | `docs/00` 第 783 行描述为**「生成列」** | **不是生成列**:`information_schema.COLUMNS` 实测 `EXTRA=''`、`GENERATION_EXPRESSION=''`;`alembic/baseline_generated.sql` 的建表语句无 `GENERATED` 子句;`tools/seed_profile_demo.py` 注释写明「不是生成列,必须显式写入」;`profile_repository.py` 用原生 SQL 显式写入 | 按真实 schema 映射成**普通可空列**;**不改 `docs/00`**;**不补迁移**(DDL 本身正确,错的只是文档描述;为"让文档成真"而加生成列会改变既有列语义,违反规则 4)。四处证据一致,2026-09-11 复核 |
|
||||||
|
|
||||||
|
> 发现方式:ZSY 那条线在合并前先按 `AGENTS.md` 与 `docs/00/01/05/09/14/20` 逐条过规则,
|
||||||
|
> 撞到"文档说生成列、代码却显式写入"这处矛盾后做了实测。这个自查习惯值得保持——
|
||||||
|
> 本次三家里,只有这条线在合之前把"撞到底座规则"的地方单独清理成了一个提交。
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
# 回复 ZSY:底座扩展确认(v1)
|
||||||
|
|
||||||
|
> **致**:ZSY
|
||||||
|
> **被回复**:`致qyqy_底座扩展确认沟通文案_v1.md`
|
||||||
|
> **我方基线**:`qyqy_develop`(含你合并的 `c4a73b7` 之后的平台侧改动)
|
||||||
|
> **结论**:**三件事方向都可以接受,但第 1 件有一条硬约束必须先确认**(见 §1.2);
|
||||||
|
> 第 3 件的判断你是对的,`docs/00` 那处描述确实错了,处置方式见 §3。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 访客身份(`security.py` + `auth.py`)
|
||||||
|
|
||||||
|
### 1.1 `data_scope="public"` 这个新值,我替你核过了:安全
|
||||||
|
|
||||||
|
我扫了全平台 `data_scope` 的**全部 26 个消费点**,对未知值的行为是**一致 fail closed** 的:
|
||||||
|
|
||||||
|
| 写法 | 处数 | `"public"` 的结果 |
|
||||||
|
|---|---|---|
|
||||||
|
| `== "all"` | 6 | 判假 ⇒ 走保守分支 |
|
||||||
|
| `!= "all"` | 1(`risk_analysis_service.py:126`) | 进入分支 ⇒ **要求 `customer_ids` 非空,否则 `ForbiddenAgentError`** |
|
||||||
|
| 显式白名单 `{"self","own_customers","all"}` | 1(`financial_nl2sql_service.py:286`) | 不在集合内 ⇒ 直接拒绝 |
|
||||||
|
|
||||||
|
访客的 `customer_ids` 本来就是空的,所以 `!= "all"` 那一支会**先拒后查**。
|
||||||
|
|
||||||
|
**结论**:新增 `public` 不会意外放行任何数据,**不用改这 26 处**。
|
||||||
|
顺带说明它的实际作用:访客要的是"查公开知识",那条路径走 `knowledge:query`**权限**、
|
||||||
|
不读 `data_scope`,所以 `public` 目前主要是**语义标注**——这没问题,标注清楚比复用 `self` 更好。
|
||||||
|
|
||||||
|
### 1.2 ⚠️ 必须先确认:访客令牌的 `sub` **必须是纯数字**
|
||||||
|
|
||||||
|
这是全平台最硬的一条约束,请务必确认你的实现满足:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# app/core/security.py:57-61 —— 现有校验
|
||||||
|
subject = claims["sub"]
|
||||||
|
if (not isinstance(subject, str) or not subject.isascii()
|
||||||
|
or not subject.isdecimal() or len(subject) > 20
|
||||||
|
or not 0 < int(subject) <= 18446744073709551615):
|
||||||
|
raise UnauthorizedAgentError("invalid subject")
|
||||||
|
```
|
||||||
|
|
||||||
|
即使这个校验通过了,平台里仍有 **72 处 `int(context.user_id)`**,而**只有 3 处做了防御**:
|
||||||
|
|
||||||
|
```
|
||||||
|
有防御:offsite_fund_service.py:2458 / offsite_nl2sql_adapter.py:68 / suitability_service.py:250
|
||||||
|
(写法都是 int(...) if context.user_id.isdigit()/isdecimal() else None)
|
||||||
|
|
||||||
|
没有防御:其余 69 处,例如
|
||||||
|
authorization_service.py:21 actor_id=int(context.user_id) ← 一旦发生权限拒绝就要写这条审计
|
||||||
|
tool_executor.py:138 actor_id=int(context.user_id)
|
||||||
|
identity_repository.py:18 int(identity.user_id)
|
||||||
|
conversation_service.py:36/60/63/68/87
|
||||||
|
public_platform_service.py:36/44/77
|
||||||
|
…(共 69 处)
|
||||||
|
```
|
||||||
|
|
||||||
|
**所以如果访客的 `sub` 是 `visitor-<uuid>` 这类非数字,任何一次命中就会抛 `ValueError`**——
|
||||||
|
而且其中好几处是"权限被拒时要写审计"的路径,表现为**本该 403 的地方变成 500**。
|
||||||
|
|
||||||
|
**请你确认两点**:
|
||||||
|
|
||||||
|
1. 访客令牌的 `sub` 是**纯十进制数字**(例如保留 id `0`,或某个不与 `sys_user` 冲突的号段);
|
||||||
|
2. `visitor` 分支**复用了同一个 `jwt.decode`**(含 `algorithms` / `iss` / `aud` / `exp` / `nbf` / `jti`
|
||||||
|
以及上面那段 `sub` 校验),只是**跳过 `IdentityService.resolve()`**——而不是自己另写一套。
|
||||||
|
另写一套等于开了第二个鉴权入口,这与"单点鉴权"的约定冲突。
|
||||||
|
|
||||||
|
> 如果 `sub` 只能是字符串,那正确做法**不是**改成访客专用校验,而是把那 69 处
|
||||||
|
> `int(context.user_id)` 一并收敛成 `app/core/` 里的一个转换函数(非数字返回 `None`)。
|
||||||
|
> 那是一次跨模块改动,**建议单开一轮做**,不要混在访客功能里。
|
||||||
|
|
||||||
|
### 1.3 两条小约束
|
||||||
|
|
||||||
|
- **权限集保持最小**:`("agent:run", "knowledge:query")` 看起来正好,请**不要**顺手加
|
||||||
|
`knowledge:reference:read`(那是读"知识引用令牌"用的,访客不需要)。
|
||||||
|
- **访客不产生客户侧副作用**:`recalls_customer_memory=False` 走对了方向;
|
||||||
|
另外确认访客**不写** `interaction_audit.target_customer_id`(留 `None`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 客服 Agent 的角色与行为
|
||||||
|
|
||||||
|
### 2.1 `allowed_roles` 扩为 `("visitor","customer")` —— 可以
|
||||||
|
|
||||||
|
访客要用客服 Agent,这是必需的。`AgentDefinition.allowed_roles` 本来就是声明式的,
|
||||||
|
扩集合不改语义。
|
||||||
|
|
||||||
|
### 2.2 `recalls_customer_memory=False` —— 可以,但**默认值必须是 `True`**
|
||||||
|
|
||||||
|
这是**新增声明字段**,现有代码里没有它(我 grep 过 `app/service/agent/`,只有 `recall_memory`
|
||||||
|
这个 base 方法)。请务必保证:
|
||||||
|
|
||||||
|
```
|
||||||
|
默认值 = True(即"照常召回"),只有显式声明 False 的 Agent 才跳过
|
||||||
|
```
|
||||||
|
|
||||||
|
否则一旦默认成 `False`,**所有既有 Agent(客服、风控、投顾、demo)的记忆召回会被静默关掉**——
|
||||||
|
而它在界面上看不出来,只会表现为"回答变差"。
|
||||||
|
|
||||||
|
### 2.3 `handle()` 里插入确定性安全路由 —— 可以,但请补测试
|
||||||
|
|
||||||
|
"安全/合规/账户/人工优先于检索"这个顺序是对的(客服那边原本就有类似的
|
||||||
|
`is_profile_question()` 确定性前置)。请为每条分支补一个用例,锁住"优先级顺序"本身——
|
||||||
|
这类路由最容易在后续合并里被悄悄挪位置。
|
||||||
|
|
||||||
|
### 2.4 品牌名 —— **这条我不能定,需要项目方拍板**
|
||||||
|
|
||||||
|
`COMPANY` 现在确实是 `"南方科技"`(`customer_service.py:153`)。但你改成的
|
||||||
|
**「奶龙基金责任有限公司」是风控那条线的品牌**(`docs/风控业务演示文档/09-奶龙风控智能助手说明.md`)。
|
||||||
|
|
||||||
|
所以这不是"改个常量",而是**两个业务线是否共用一个品牌主体**的问题。我倾向统一(同一家公司
|
||||||
|
的客服和风控不该是两个主体),但这属于业务口径,**我已把它单独列给项目方定**,
|
||||||
|
定了我立刻同步。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. `current_customer_id` —— **你的判断是对的,`docs/00` 那处描述错了**
|
||||||
|
|
||||||
|
我独立核了一遍,你的证据全部成立,而且我这里也有了直接证据:
|
||||||
|
|
||||||
|
```
|
||||||
|
information_schema.COLUMNS(本机实测):
|
||||||
|
COLUMN_NAME = current_customer_id
|
||||||
|
COLUMN_TYPE = bigint unsigned
|
||||||
|
IS_NULLABLE = YES
|
||||||
|
EXTRA = "" ← 不是生成列、也不是自增
|
||||||
|
GENERATION_EXPRESSION = "" ← 没有生成表达式
|
||||||
|
```
|
||||||
|
|
||||||
|
与 `alembic/baseline_generated.sql` 没有 `GENERATED` 子句、`tools/seed_profile_demo.py`
|
||||||
|
的注释、`profile_repository.py` 用原生 SQL 显式写入——**四处一致**。
|
||||||
|
|
||||||
|
**处置(我的裁定)**:
|
||||||
|
|
||||||
|
1. **按真实 schema 映射成普通可空列** —— 你已经这么做了,**对**;
|
||||||
|
2. **`docs/00` 不改** —— 规则 1 明确它是**不可变**业务基线,哪怕某处描述有误也不由我们改;
|
||||||
|
3. **但要把这处偏差登记下来**,否则第 5 个人还会再踩一次。我会在
|
||||||
|
`docs/08-数据库结构审计基线.md`(审计口径文档)里记一条"已知文档偏差";
|
||||||
|
4. **不建议补迁移**:DDL 本来就是对的(普通可空列),错的只是文档描述。为"让文档变成真的"
|
||||||
|
去加一条生成列迁移,会**改变既有列语义**(规则 4)。
|
||||||
|
5. 同一张表**两个声明类**(`risk_questionnaire.py` 内联 + `profile.py`)会让 SQLAlchemy
|
||||||
|
直接拒绝导入模型——这个必须去重,你做的方向对;请统一从 `profile.py` 导出。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 顺带三件小事
|
||||||
|
|
||||||
|
| 项 | 我的意见 |
|
||||||
|
|---|---|
|
||||||
|
| `query_knowledge` 与 `search_knowledge` 并存 | **可以保留**(都指向同一 handler、实际范围由 `config_release` 白名单收口),但请在 `docs/05` §8.4 或你的接入说明里**明确写成"别名"**,否则下一个人会以为平台有两个检索工具 |
|
||||||
|
| `.gitignore` 加 `.worktrees/` 和 `data/milvus/` | **可以**。顺带提醒:`.workdir/` 也已在里面(NL 那边的 conftest 用它落测试临时目录) |
|
||||||
|
| 依赖新增 `milvus-lite` | **请放进 `pyproject.toml` 的 `optional-dependencies`**,**不要进主 `dependencies`**。它只是本地开发用,进主依赖会让生产环境多背一个包,而且 `MILVUS_LOCAL_URI` 那条坑正是它引入的 |
|
||||||
|
|
||||||
|
**你提的 `MILVUS_LOCAL_URI` 那个坑很有价值**:一旦在 `.env` 里配了,健康检查会指向本地
|
||||||
|
Milvus Lite 文件,出现"健康检查正常、实际查的是另一个库"。建议把它写进 `AGENTS.md` 的
|
||||||
|
环境口径一节(和 `config_release`、Milvus schema 那几条并列)——我来加,你确认措辞即可。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 关于你删掉的两个文件
|
||||||
|
|
||||||
|
`app/service/knowledge_tool_service.py` 与 `app/infrastructure/milvus_knowledge_adapter.py`,
|
||||||
|
你判断是生产死代码、且后者硬编码了 Milvus 字段名(违反 `AGENTS.md` §E)——**方向我认同**,
|
||||||
|
硬编码字段名那条尤其该删(另一套环境会被打挂)。
|
||||||
|
|
||||||
|
但**我这边看不到你的分支**(`ZSY_develop` 未推送),所以无法独立核实"全仓唯一引用是它自己的单测"。
|
||||||
|
请在 PR 描述里附上两条 grep 的实际输出,例如:
|
||||||
|
|
||||||
|
```
|
||||||
|
git grep -n "knowledge_tool_service" -- app/ tests/ tools/
|
||||||
|
git grep -n "milvus_knowledge_adapter" -- app/ tests/ tools/
|
||||||
|
```
|
||||||
|
|
||||||
|
只要输出里只剩它们自身(和各自的单测),我就照批。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 你处理得好的两处(照做)
|
||||||
|
|
||||||
|
1. **`docs/05` 的 `§8.5`**:没有把既有的 `§8.2`/`§8.3` 往后挤,而是新增到末尾,
|
||||||
|
`AGENTS.md`/`docs/09`/`docs/14` 里对 §8.3、§8.4 的引用继续成立 —— 这是对的,
|
||||||
|
编号被复用比编号不够更麻烦(我们这边刚因两家同时占用 `docs/21`、`docs/22` 让过两次号);
|
||||||
|
2. **合并前先按底座规则自查、把撞规则的地方清理成独立提交**(`9aaacc2`,
|
||||||
|
9 文件 +189/−483)—— 这个习惯请保持,它让评审能按提交看,而不是在一大坨 diff 里找。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 结论与下一步
|
||||||
|
|
||||||
|
**可以推进**:§1.3、§2.1、§2.3、§3 的处置、§4、§5(附 grep 证据后)。
|
||||||
|
|
||||||
|
**需你先补一句确认**:§1.2 的 `sub` 是否为纯数字 + 是否复用同一套 `decode` 校验;
|
||||||
|
§2.2 的默认值是否为 `True`。
|
||||||
|
|
||||||
|
**需项目方拍板**(我已上报,不占你时间):§2.4 的品牌名。
|
||||||
|
|
||||||
|
这三条确认后,你推 `ZSY_develop` 并开 PR,我这边按 `docs/32-平台侧交接与联调准备.md` §5
|
||||||
|
的清单合:`alembic upgrade head` → 表审计 → 文档守卫 → 四项门禁 → 真机联调。
|
||||||
|
|
||||||
|
> 附:我方最近新增的与你这条线相邻的东西,联调时可能用得上 ——
|
||||||
|
> `POST /api/v1/auth/tokens`(账号密码登录)、`GET /api/v1/admin/roles` 等四个 RBAC 只读接口、
|
||||||
|
> `tools/login_console.py`(浏览器登录测试台)、`tools/create_test_user.py`(建测试账号)。
|
||||||
Reference in New Issue
Block a user