feat: heal dead sync channels and block deleting system default (Z12h)

Ensure default channel and rebind Agent/Binding on list, ticket, agents/me, and ensure-binding so SyncPage does not stay on deleted-channel errors.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
whm
2026-08-06 08:57:30 +08:00
parent 2a7da53769
commit 362dcee242
8 changed files with 309 additions and 85 deletions

View File

@@ -1,7 +1,7 @@
# 联调后修改意见 · 宇恒松离线(形态 B
> 初稿2026-08-01 · 修订至 **2026-08-05 18:25**
> 焦点:**§0.2 / §0.3**Z10d / Z14 / Z14c **代码已合入**,生产须 `bash ./restart.sh --pull`;已修项勿再挂「仍待办」
> 初稿2026-08-01 · 修订至 **2026-08-06**Z12h 已落实)
> 焦点:**§0.2**(按负责方:宇恒改宇恒、智建改智建);配合见 **§0.3**
> 来源:宇恒 `yuhengyihao_client` ↔ 智建(生产 `aisite.yuxindazhineng.com`
> 依据:`松离线-dbsync方案-最终版.md`、`宇恒-松离线数据同步使用文档.md`
@@ -11,13 +11,14 @@
| 级别 | 状态 | 说明 |
|------|------|------|
| **硬改(阻塞接口)** | **无** | Z1Z14 代码侧齐;剩生产 pull + 配号/Secret/白名单 |
| **硬改(阻塞接口)** | **无** | 契约不变;剩生产 pull + 配号/Secret |
| **生产栈** | **已恢复** | `SMS.Provider: "off"` 须引号health `platform/ai=true` |
| **Z1Z9 / Z11Z13** | **已落实** | 绑定/凭票/模块导入等;见 §5 |
| **Z10 + Z10d** | **代码齐;生产 pull** | 空表 ensure已存在表 **ADD COLUMN**§5.7 |
| **Z12 默认同步** | **已落实** | 启用即通道;**默认运行中**`cb76824` |
| **Z14 + Z14c** | **代码齐;生产 pull** | fingerprint API;智能体挂载 `online_db_id` 已放行§5.11 |
| **仍关注** | 用法 | SQLite 按库串行 drain历史数据靠 full-push,不是「点启动」 |
| **Z12 默认同步** | **已落实(含 Z12h** | 启用即通道;误删 → Ensure+重挂§5.9 |
| **Z14 + Z14c** | **代码齐;生产 pull** | fingerprint智能体挂载 `online_db_id`§5.11 |
| **Z14d 双向补齐** | **宇恒已接** | 误删任一侧 → 心跳/选同步按主键并集 pullpush§5.11 |
| **仍关注** | 用法 | 通道断了靠智建自愈;表数据靠宇恒双向指纹;不是「再点启动」 |
### 0.1 绑定产品冻结Z13 · 试运行)
@@ -31,6 +32,7 @@
### 0.2 待改清单(按负责方)
> **分工冻结**:宇恒只改 `yuhengyihao_client`;智建只改 `ai建站`;互不代改对方仓。
> 智建轨迹:`d195aa4` 凭票 → `4222667` SMS 引号 → `cb76824` 默认启动 → `4fae7ae` Z10d+fingerprint → **`bb59bb5` Z14c**。生产:`bash ./restart.sh --pull`。
#### A. 宇恒 · 已完成
@@ -39,14 +41,16 @@
|------|------|
| **Z10c** | `ensure_before_drain`(选同步 force + drain 前 TTL |
| **Z13be** | 绑定码 / 同号确认 / policy / 凭票 / 选「同步」即 Binding+drain |
| **Z14a** | 表级指纹慢心跳不一致 → ensure + full-push |
| **Z14a** | 表级指纹慢心跳(原:不一致 → ensure + full-push |
| **Z14d** | **双向并集补齐2026-08-06**:不一致 → 先 `pull` 灌本机(不进 outbox再 ensure+full-push选「同步」同样先 pull 再 push**默认不做 prune**`YXD_SYNC_PRUNE_EXTRAS=1` 才清线上多余)。覆盖:线上误删 / 本地误删 / 缺表 |
#### A. 宇恒 · 配合注意(非新开发)
#### A. 宇恒 · 配合注意(非阻塞新开发)
| 优先级 | 内容 |
|--------|------|
| **P0** | 端到端见 **§0.3**:绑定 → 库选「同步」→ drain线上表只反映已 push/ensure |
| **P0** | **`online_db_id`**:生产 pull Z14c 后,智能体 JWT **用** ticket/`agents/me``{channel}_uN`人类自助仍走本人 Binding |
| **P0** | 端到端见 **§0.3**:绑定 → 库选「同步」→ drain线上表只反映已 push/ensure/pull |
| **P0** | **`online_db_id`**:生产 pull Z14c 后,智能体 JWT **用** ticket/`agents/me``{channel}_uN``apply_bind_success` 勿再长期吞掉 `_uN` |
| **P1** | 通道失效push/agents/me 报通道不存在)→ **重新换票**,用返回的新 `channel_id` 覆盖 env根因自愈见智建 **Z12h** |
| **P1** | Binding 带可读名;同库串行 drain指纹优先 `schema/fingerprint`404 回退 `row_count` |
#### B. 智建 · 已完成(仓内)
@@ -58,12 +62,21 @@
| 默认同步通道默认启动 | 创建即 enabled重启自动 Start |
| **Z14c** ACL | 智能体 JWT 放行挂载 `online_db_id``agentOwnsOnlineDB` |
| Podman DNS / 脚本可执行位 | compose aliases`restart.sh` 100755 |
| **Z12h / Z12h-1 / Z12h-2** | `HealTenantSyncBind`Ensure 默认通道 + 重挂 Agent/Binding`is_system_default` 禁删;列表/换票/`agents/me`/ensure Binding 触发;见 §5.9 |
> 产品一句:**账号已绑定 ⇒ 落点信息固定;通道没了平台自动补,终端无需手填 channel_id。**
#### B″. 智建 · 仍待办(**开发** · 本仓改)
| 优先级 | 编号 | 项 | 说明 |
|--------|------|----|------|
| — | — | **无阻塞开发项** | Z12h 已合入;后续仅生产 pull 与运维配号 |
#### B. 智建 · 仍待办(仅运维)
| 优先级 | 项 | 说明 |
|--------|----|------|
| **P0** | **生产 pull 本批** | Z10d + `schema/fingerprint` + Z14c`bash ./restart.sh --pull` |
| **P0** | **生产 pull 本批** | Z10d + `schema/fingerprint` + Z14c + **Z12h**`bash ./restart.sh --pull` |
| **P0** | 成员手机 | 「宇信达」绑 **`13531041944`**;勿超管号 |
| **P0** | 通道表白名单 | **勿**「填入测试默认」;形态 B 可空 |
| **P1** | 凭票 Secret | `YuhengTicket.Secret``YXD_YUHENG_TICKET_SECRET` |
@@ -75,8 +88,9 @@
| 项 | 说明 |
|----|------|
| 终端冲突台 | 仅平台超管 |
| 智建代改宇恒仓 | 分工冻结 |
| 智建代改宇恒仓 / 宇恒代改智建仓 | **分工冻结** |
| 平台 push 租约 | version 幂等 + 宇恒串行 drain |
| 用户手填 channel_id / DSN 为开通终态 | 已否决;见 Z12 / Z12h |
### 0.3 双方怎么配合(开通 → 看到线上表)
@@ -87,20 +101,25 @@
3. 启用智能体 → 默认同步通道应「运行中」
4.(可选)生成绑定码
【智建 · Z12h 已落实】
误删默认同步 / Binding 挂死 → 打开 SyncPage / 换票 / agents/me 自动 Ensure+重挂
【宇恒终端】
5. 未绑定 → policy → lookup/confirm 或 redeem 或 ticket-exchange
6. 本机库选「同步」→ Binding + ensure + drain/full_pushZ13e
7. 慢心跳指纹Z14;缺列依赖生产已 pull 的 Z10d
6. 本机库选「同步」→ Binding + pull + ensure + drain/full_pushZ13e / Z14d
7. 慢心跳指纹Z14d本地缺←pull线上缺→push;缺列依赖生产已 pull 的 Z10d
8. 若仍报通道不存在 → 再换票刷新 channel_id生产须已 pull Z12h
【智建验收】
8. 「查看线上表」刷新 → 应有业务表(含曾 0 行空表)
9. 仍空 = 终端尚未 push/ensure不是再点一次「启动」就能灌表
9. 「查看线上表」刷新 → 应有业务表(含曾 0 行空表)
10. 仍空 = 终端尚未 push/ensure/pull,不是再点一次「启动」就能灌表
11. 故意删默认同步通道后:换票或打开 SyncPage / agents/me → 通道自动回来Binding 不再红字
```
| 角色 | 负责 | 不负责 |
|------|------|--------|
| **智建** | 落点/通道/鉴权/ensure/fingerprint控制台看线上表 | 不替宇恒灌本机历史行 |
| **宇恒** | 绑定 UX、选同步、outbox、drain、指纹修复、full-push | 不以手填 DSN/通道为产品终态 |
| **智建** | 落点/通道自愈/鉴权/ensure/fingerprint API;控制台看线上表 | 不替宇恒灌本机历史行;不改宇恒仓 |
| **宇恒** | 绑定 UX、选同步、outbox、drain、**双向**指纹修复、full-push/pull | 不以手填 DSN/通道为产品终态;不改智建仓 |
| **共同** | 联调号 `13531041944`Secret 对齐;试运行免短信仍须确认 | 不用超管号 |
宇恒对照脚本:`smoke_zhijian_e2e.py` / `smoke_offline_concurrent.py` / `smoke_zhijian_gateway_burst.py` / `smoke_stress_sync.py`
@@ -511,7 +530,7 @@ POST .../schema
**说明**:存量表补列一律可空,避免 NOT NULL 迁库失败。已有库需**再发布一次**(或编辑发布增字段)才会 ALTER之后新字段随发布自动补。
### 5.9 【智建已落实 Z12】生产:账号绑定即落点,禁止手填通道 / 手建通道(2026-08-05
### 5.9 【Z12 · 已落实 Z12h】账号绑定即落点,禁止手填通道2026-08-05 / 修订 2026-08-06
> **产品约定(生产 · 冻结意向)**
> 1. **一个登录账号 / 一个智能体 ↔ 本公司同步落点**:绑定后,该账号的本机库只进自己的(或公司共享的)线上库,**不会**接到别人账号的库。
@@ -532,18 +551,27 @@ POST .../schema
| **Z12e** | **P1** | **唯一默认通道** | 每公司至多 1 条 `is_system_default`;复用已有默认 | **智建已落实** + 宇恒「仅 1 条则写入 env」 |
| **Z12f** | **P1** | **开通 UX** | 启用智能体即可DSN 用公司级默认 | **智建已落实** |
| **Z12g** | **P1** | **默认同步通道默认启动** | 创建 `Enabled=true`;重启对 `IsSystemDefault` 自动 Start控制台保存后自动启动 | **智建已落实**`cb76824` |
| **Z12h** | **P0** | **通道误删自愈** | `HealTenantSyncBind`Ensure 默认通道 + 重挂挂死 Agent/Binding保留 `online_db_id`);触发:`ensureAgentSyncBind` / `agents/me` / 换票 / 通道·Binding 列表 / 删非默认通道后 | **智建已落实** |
| **Z12h-1** | **P1** | **禁删或删后重建默认同步** | `is_system_default` **禁止删除**;删其它通道后 heal | **智建已落实** |
| **Z12h-2** | **P1** | **orphan Binding heal** | 列表 / Ensure Binding 时通道缺失 → 静默改挂默认通道 | **智建已落实** |
**缺口说明2026-08-06 · 已关闭)**
-SyncPage「通道已删除」、`ensureAgentSyncBind` 见非空 `channel_id` 即跳过。
- 现:列表/换票等路径先 heal默认通道不可删。生产须 **pull** 后验收第 4 条。
**宇恒已做2026-08-05**
1. 当前生产通道 `691575c0-…` 已写入 env过渡缓存Z12c 落地后应由换票/唯一通道自动获得)。
1. 当前生产通道已写入 env过渡缓存Z12c/Z12h 落地后应由换票/自愈自动获得)。
2. `resolve_sync_channel_id()`env → Binding → 租户仅 1 通道自动选用。
3. 不把「手建通道 + 手抄 ID」当作产品终态。
3. 不把「手建通道 + 手抄 ID」当作产品终态;通道失效时配合再换票(根因仍靠 Z12h
**验收**
1. 新公司:只「启用智能体」,**不**点新建通道,换票已带 `channel_id`,宇恒可 drain。
2. 账号 A 的本机库 push 不会出现在账号 B 的线上库;共享库仅在显式共享时可见。
3. 用户全程无需 F12、无需手填 `YXD_SYNC_CHANNEL_ID`
3. 用户全程无需 F12、无需手填 `YXD_SYNC_CHANNEL_ID`
4. **Z12h** 默认同步通道 API **不可删**;若 Binding/Agent 仍挂历史死 `channel_id`(或误删非默认通道)→ `agents/me` / 换票 / 打开 SyncPage → Ensure 默认通道并重挂,「通道已删除」红字消失;宇恒无需手填新 ID。
### 5.10 【双方代码已接 Z13】绑定流程简化绑定码 / 手机号2026-08-05
@@ -618,15 +646,17 @@ POST .../schema
6. 未确认 / 他人绑定码,不能绑进别的公司或别人账号。
7. 正式且启凭票:同号走 `ticket-exchange`,不再依赖明文 `attested_same_phone`
### 5.11 【新增 Z14 · 2026-08-05 晚】表级指纹对账(慢心跳)+ 联调踩坑
### 5.11 【Z14 · 2026-08-05 / 修订 2026-08-06】表级指纹对账 + 双向补齐 + 联调踩坑
> **诉求**
> 仅靠 agent「推送心跳」pending/pushed发现不了「本机 96 行、线上 0 行」或「行数相同但内容不同」。
> 需要**慢周期表级指纹**`row_count` +(可选)`content_hash`;不一致则 ensure + 对该表 full-push。
> 1. 仅靠 agent「推送心跳」发现不了「本机 96 行、线上 0 行」或「同 count 不同内容」。
> 2. **已绑定账号后**:线上误删或本地误删,都应能从另一侧按主键**并集**补回;心跳检测到不一致即自动修。
> 3. **通道被删**不属于表级修复,见 **Z12h**(智建已落实;须生产 pull
| 编号 | 优先级 | 诉求 | 现状 |
|------|--------|------|------|
| **Z14a** | **P0** | 宇恒本机指纹 + 对比线上 + 自动修复 | **宇恒已接**`sync_fingerprint.py`TTL **600s**`POST /database/sync/fingerprint` |
| **Z14a** | **P0** | 宇恒本机指纹 + 对比线上 | **宇恒已接**`sync_fingerprint.py`TTL **600s**`POST /database/sync/fingerprint` |
| **Z14d** | **P0** | **双向并集修复** | **宇恒已接2026-08-06**`sync_pull.py`;本地缺/更少 → pull直写 B、不进 outbox线上缺/更少 → ensure+full_pushhash/count 冲突 → 先 pull 再 push。选「同步」同路径**默认不 prune** |
| **Z14b** | **P1** | 智建 `content_hash` | **已合入,生产 pull**`POST .../schema/fingerprint` |
| **Z10d** | **P0** | ensure 已存在表补列 | **已合入,生产 pull**;未 pull 时 `填土高度``id` 仍 503 |
| **Z14c** | **P0** | 智能体 `online_db_id` ACL | **已合入,生产 pull**`agentOwnsOnlineDB`;人类 Binding 规则不变 |
@@ -641,33 +671,45 @@ POST /api/v1/agent/sync/channels/{id}/schema/fingerprint
哈希:`sha256( table+"|"+pk+"|" + Σ json(row, sort_keys=True)+"\n" )` 前 32 hex。
下行(宇恒已用,智建保持兼容):
```http
POST /api/v1/agent/sync/channels/{id}/pull
{ "mode": "bootstrap", "table": "...", "after_pk": "", "limit": 200, "online_db_id": "..." }
result: { columns, items[], has_more, next_after_pk, pk_column }
```
**分工**
| 方 | 做什么 |
|----|--------|
| 宇恒 | 本机指纹;优先 fingerprint API404 回退 `row_count`不一致 ensure+full_push |
| 智建 | 生产 pullfingerprint + Z10d + Z14c |
| 宇恒 | 本机指纹404 回退 `row_count`**Z14d** 双向 pullpush;选同步默认不 prune |
| 智建 | 生产 pullfingerprint + Z10d + Z14c + **Z12h**;保持 pull/bootstrap 契约 |
**联调踩坑(宇信达 · 已回写)**
1. **行数对不上**:开通同步不会自动灌历史 → full-push;指纹可检出
1. **行数对不上**:开通同步不会自动灌历史 → full-push / 指纹修复;**Z14d** 后本地缺也会 pull
2. **`填土高度``id`**push 默认 pk=`id`;须 Z10d 补列或删表重建后再推(宇恒 `mark_error` 堵队已修)。
3. **`_uN` 曾 403**:智能体 JWT `user_id=agent_id`Binding 在人类成员上 → **Z14c** 放行挂载 online。
3. **`_uN` 曾 403**:智能体 JWT `user_id=agent_id`Binding 在人类成员上 → **Z14c** 放行挂载 online。
4. **删通道后再同步仍空**Binding「通道已删除」→ 生产 pull **Z12h** 后打开 SyncPage/换票自愈;表级指纹无法重建通道。
**验收**
1. 改本机行数后 ≤TTL 检出 mismatch 并排队修复。
2. 未 pull fingerprint仅 count 对账仍可用。
3. pull 后:同 count 不同内容 → `hash_mismatch`
4. Z10d pull 后:`填土高度` 可推满。
3. pull 后:同 count 不同内容 → `hash_mismatch` → 双向修
4. Z10d pull 后:`填土高度` 可推满。
5. **Z14d** 线上删某表行 → 心跳后本机行仍在且线上恢复;本机删某表行(未 prune→ 心跳后本机从线上拉回。
6. **Z12h** 见 §5.9 验收第 4 条。
---
## 6. 联系与附件
- **待改清单(优先看)**§0.2**双方配合****§0.3**
- **待改清单(优先看)**§0.2**A 宇恒配合 · B 智建运维**;开发项已清空);配合**§0.3**
- 方案:`松离线-dbsync方案-最终版.md`(含 2026-08-01 联调建议落地记录)
- 宇恒使用说明:`宇恒-松离线数据同步使用文档.md`(含 Z10 schema/ensure、Z13 绑定)
- 开通说明:`docs/数据同步-开通说明.md`
- 绑定策略探测:`GET /api/v1/auth/bind/policy``trial_mode` / `require_for_bind`
- 本意见如与冻结方案冲突,**以冻结方案为准**§5.15.11 为产品增量与复测记录,不推翻 H1H6 默认无感约束。
- 本意见如与冻结方案冲突,**以冻结方案为准**§5.15.11 为产品增量与复测记录,不推翻 H1H6 默认无感约束。
- **分工**:宇恒只改宇恒仓;智建只改智建仓;互不代改。