# 交接：给 russell 开 ad_assistant.db 读写权限（方案 B，路径不动）

**发起**：russell（阿涂代写） · **执行**：xunan · **日期**：2026-08-28
**目标**：russell 需要在 `ad_assistant.db` 里**新建并写入 `ci_*` 前缀的表**（素材智能链路），
不修改、不删除你现有的任何表。路径保持不动，只加 ACL + 把 journal 模式切成 WAL。

## 为什么必须同时做 WAL（这条别跳）

当前 `journal_mode=delete`。这个模式下：

- 写事务会给**整个数据库文件**加排他锁
- **writer 会阻塞 reader**，reader 也会阻塞 writer

你的 gateway 是常驻进程，russell 这边要跑批量写入。两边同时用，delete 模式下必然互相卡死甚至报
`database is locked`。切到 WAL 后是「一写多读并行」，两边才能共存。

WAL 模式写在数据库文件头里，**设置一次就永久生效**，之后所有连接自动使用，不用改任何代码。

---

## 第 1 步：加 ACL（4 级路径，你自己就能跑，不用 sudo）

前三级只给 `search`（= 允许穿过目录，但**不能列出内容**，看不到你其他文件）：

```bash
chmod +a "user:russell allow search" /Users/xunan/.openclaw
chmod +a "user:russell allow search" /Users/xunan/.openclaw/workspace-feishu
chmod +a "user:russell allow search" /Users/xunan/.openclaw/workspace-feishu/data
```

`local_db` 目录需要能列出 + 能新建文件（WAL 要在这里建 `-wal` / `-shm`）：

```bash
DIR=/Users/xunan/.openclaw/workspace-feishu/data/local_db

chmod +a "user:russell allow list,search,add_file,delete_child,readattr,readextattr,readsecurity" "$DIR"
```

**关键一条**：让**将来新建**的 `-wal` / `-shm` 文件自动带上 russell 的读写权限。
少了这条，WAL 文件被你的进程创建后 russell 写不了：

```bash
chmod +a "user:russell allow read,write,append,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,only_inherit" "$DIR"
```

反向也要一条 —— russell 的进程也可能先创建 `-wal`/`-shm`，那时文件属主是 russell，
你的 gateway 得能写：

```bash
chmod +a "user:xunan allow read,write,append,readattr,writeattr,readextattr,writeextattr,readsecurity,file_inherit,only_inherit" "$DIR"
```

最后给 db 文件本身加读写（它已存在，不受 inherit 影响，必须单独加）：

```bash
chmod +a "user:russell allow read,write,append,readattr,writeattr,readextattr,writeextattr,readsecurity" "$DIR/ad_assistant.db"
```

如果 `-wal` / `-shm` 此刻已经存在，也一并加：

```bash
for f in "$DIR"/ad_assistant.db-wal "$DIR"/ad_assistant.db-shm; do
  [ -e "$f" ] && chmod +a "user:russell allow read,write,append,readattr,writeattr,readextattr,writeextattr,readsecurity" "$f"
done
```

### 验证（你这边）

```bash
ls -lde /Users/xunan/.openclaw/workspace-feishu/data/local_db
ls -le  /Users/xunan/.openclaw/workspace-feishu/data/local_db/ad_assistant.db
```

应能看到对应的 `user:russell allow ...` 条目。

---

## 第 2 步：切 WAL（需要短暂独占，建议停 gateway）

切换要求当时**没有其他活动连接**。你的 gateway 常驻会持有连接，所以：

```bash
# 1) 先停 gateway
openclaw gateway stop

# 2) 切 WAL —— 必须回显 wal，回显 delete 就是没切成功（有锁）
DIR=/Users/xunan/.openclaw/workspace-feishu/data/local_db
sqlite3 "$DIR/ad_assistant.db" "PRAGMA journal_mode=WAL;"

# 3) 确认
sqlite3 "$DIR/ad_assistant.db" "PRAGMA journal_mode;"

# 4) 起回来
openclaw gateway start
```

⚠️ 第 2 步如果回显 `delete`，说明还有连接占着，检查是否有别的脚本/cron 在跑，别硬来。

切完后目录里会多出 `ad_assistant.db-wal` 和 `ad_assistant.db-shm`，这是正常的，别删。

---

## 双方共同约定

1. **russell 只碰 `ci_*` 前缀的表**，绝不 ALTER / DROP / UPDATE 你现有的 8 张表
   （`material` / `material_channel_data` / `material_appsflyer_data` / `channel_data` /
   `appsflyer_data` / `package` / `tenant` / `user`）。
2. **请确认一件事**：你的建表 / 迁移 / 同步逻辑里有没有「删除未知表」或 `DROP TABLE IF EXISTS` 之类的
   全库清理动作？如果有，需要把 `ci_*` 加白名单，否则我们的表会被你那边悄悄清掉。
3. russell 侧所有连接会设 `PRAGMA busy_timeout=10000`，避免瞬时争抢直接报错。
4. russell 侧写入是分批的（约 300 条/批），不会长事务占锁。

## 回滚（随时可撤，一条命令）

```bash
DIR=/Users/xunan/.openclaw/workspace-feishu/data/local_db
chmod -a "user:russell allow search" /Users/xunan/.openclaw
chmod -a "user:russell allow search" /Users/xunan/.openclaw/workspace-feishu
chmod -a "user:russell allow search" /Users/xunan/.openclaw/workspace-feishu/data
# 目录与文件上的 russell ACE 可用 `ls -lde` 看序号后按号删：chmod -a# <序号> <路径>
```

WAL 也可以回滚（但不建议，会退回互相锁死的状态）：
`sqlite3 "$DIR/ad_assistant.db" "PRAGMA journal_mode=DELETE;"`

---

有任何一步报错，把命令和报错原文回在这个文件末尾或直接找 russell，别自己改语法硬试。

---

## xunan 执行反馈（2026-08-28 11:2X）

**第 1 步（ACL）：** 已按文档逐条执行完毕，全部验证通过：
- 4级路径 search：`/Users/xunan/.openclaw`、`workspace-feishu`、`data`、`local_db` 均已加 `user:russell allow search`
- `local_db` 目录：已加 `list,search,add_file,delete_child,readattr,readextattr,readsecurity` + inherit 条目（russell 和 xunan 双向都加了）
- `ad_assistant.db` 文件本身：已加 `read,write,append,...` 给 russell
- `-wal` / `-shm` 文件：当时已存在，已单独加 ACL 给 russell

**第 2 步（WAL）：** 检查发现 `PRAGMA journal_mode` 当前已经是 `wal`（之前已经切过），**无需再停 gateway 操作**，跳过。

**关于「删除未知表」的确认（文档里问的那件事）：**
检查了 `scripts/data_sync.py`（负责往 `ad_assistant.db` 写 8 张现有表的脚本）和 `scripts/local_data_manager.py`：
- `data_sync.py` 里没有任何 `DROP TABLE`、全库清理或按 schema 名单清理未知表的逻辑，只对配置里列出的 8 个 task 做 upsert，不会碰其他表。
- `local_data_manager.py` 有 `purge`（按时间字段删过期行）和 `vacuum`（压缩文件）命令，但都是**针对指定 `--task` 对应的单个表**做操作，不是全库扫描删表，也不会碰 `ci_*` 前缀的表。
- 结论：**没有会清理未知表的逻辑**，`ci_*` 表是安全的，不需要额外加白名单。

全部就绪，可以开始建表写入了。
