Files
MediaCrawler/mac-agent-os-main/04_memory/cross_machine/ARCHITECTURE-v2.md
T
butubb 2112c1a870
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。

**目前能用的(真环境实测,非推断)**:

    profile/other : 200, 7075 字节  —— 博主主页指标(粉丝/获赞/作品数/昵称)
    aweme/detail  : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)

**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
  1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
     带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
     同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
     挑中的恰好是「批量拉作品列表」这个最敏感的动作。
  2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
     代价,过几小时要重测)。

  所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。

**排查中控住变量后得到的两条事实**(都写进注释了):
  · `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
    UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
    (我先前猜的 sec-ch-ua 不是关键。)
  · 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
    从 CDP 取齐 cookie + UA + hints,而不是各自写死。

「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。

测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
2026-10-10 17:12:25 +08:00

26 KiB
Raw Blame History

联邦多机协同架构 v2.0 —— WPRA 写分区·读聚合

版本: 2.0.0 | 最后更新: 2026-05-31 | 状态: 设计文档 核心原则: 各写各的文件,最后统一读取


目录


1. 问题审计

1.1 当前架构的冲突根源

在仔细审计了 guardd.py、app.py、matrix_mgmt.py、plugins/base.py 四个核心文件后,发现以下 4 个冲突源:

# 文件 写入者 问题
C1 status/live/_registry.json 每台机器的 guardd (全员写) 单文件、全员写,每次 git push 必然冲突
C2 data/*/{uid}.json 每台机器写自己的 ✅ 无冲突,但 guardd 在 _registry.json 重建时扫描这个目录(多余)
C3 accounts_registry.yaml 混合:一次写入 + git 传播,但谁改谁冲突 单文件跨越所有机器,改一次冲突一次
C4 git add -A 每台机器的 guardd (全员执行) 把全目录都 staging 了,包括别的机器写的文件

1.2 冲突链路

机器A guardd 运行
  → module_heartbeat() → 写 status/live/{A_UID}.json ✅ (安全)
  → 还写 _registry.json ← 扫描全 data/ 目录重建 ← 可能包含了机器B刚push的
  → _git_sync() → git add -A → 把机器B的 status/live/{B_UID}.json 也 add 了
  → git commit → git push

机器B guardd 运行
  → git pull → 看到机器A刚push的 _registry.json (可能和B自己的版本不同)
  → 写自己的 status/live/{B_UID}.json
  → 又写 _registry.json (覆盖A刚写的)
  → git add -A → git commit → git push
  → 冲突!因为 _registry.json 被双方先后修改

1.3 根因

核心病根只有两个:

  1. _registry.json 不该由 guardd 写——它是个聚合产物,应该只由 Dashboard 生成
  2. git add -A 不能用在联邦系统中——必须用 git add <自己写的文件>
  3. accounts_registry.yaml 不该是所有机器共享的单文件

2. 核心架构:WPRA 模型

2.1 基本原理

┌─────────────────────────────────────────────────────┐
│                   WPRA 模型                         │
│                                                     │
│  Write Partitioned     +     Read Aggregated        │
│  (写分区)                    (读聚合)               │
│                                                     │
│  每台机器只写自己的命名空间       读取方遍历所有机器   │
│  从来不碰别人的文件               按时间戳合并        │
│  git commit 只提交自己的修改       呈现统一视图       │
│                                                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐          │
│  │ 机器A    │  │ 机器B    │  │ 机器C    │          │
│  │ 写A/     │  │ 写B/     │  │ 写C/     │          │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘          │
│       │              │              │                │
│       └──────┬───────┴───────┬──────┘                │
│              ▼               ▼                       │
│        ┌──────────────────────────┐                  │
│        │   Git 仓库 (共同载体)     │                  │
│        │   机器A/ 机器B/ 机器C/   │                  │
│        └──────────────────────────┘                  │
│                     │                                │
│                     ▼                                │
│        ┌──────────────────────────┐                  │
│        │  Dashboard (读聚合)      │                  │
│        │  读A/ + 读B/ + 读C/     │                  │
│        │  按updated_at排序合并    │                  │
│        └──────────────────────────┘                  │
└─────────────────────────────────────────────────────┘

2.2 三定律

  1. 写分区定律:任何机器只能写以自己 machine_uid 命名的文件。禁止写其他机器的文件。禁止写匿名文件。
  2. 读聚合定律:任何读取方必须遍历所有机器的文件来做合并。禁止假设"某文件只由一个机器写"。
  3. Git 精确提交定律:git add 必须精确指定本机文件,禁止 -A 或 --all。

3. 机器身份系统

3.1 身份三层结构

每台机器有三层身份,从上到下稳定性递增:

层级 字段 示例 稳定性 来源
L0 machine_uid 4cf443bc-ff14-4ed9-885b-b04c5326304d 🔒 永久不变 UUID v4,第一次启动生成
L1 machine_name chengzigedeAir ⚡ 变但不失真 缓存的 hostname
L2 display_name Ghai's MacBook Air 🔄 用户可改 用户设置的别名

L0 是程序主键——所有文件名以 {machine_uid} 命名。

3.2 机器身份声明文件

每台机器在首次初始化时,在自己的命名空间根目录写入一个 MACHINE.yaml,终身不改:

# cross_machine/machines/{machine_uid}/MACHINE.yaml
# 机器身份声明 — 创建后只读,永不修改
machine_uid: "4cf443bc-ff14-4ed9-885b-b04c5326304d"
machine_name: "chengzigedeAir"
created_at: "2026-04-25T09:45:16+08:00"
schema_version: "2.0"
role: "workstation"

3.3 身份文件位置

agent-local/identity/
├── machine_uid             ← UUID v4,一行文本
├── cached_hostname         ← 缓存的 hostname
└── machine_name            ← 用户友好名(可选)

3.4 命名空间目录结构

cross_machine/
  machines/
    {machine_uid}/              ← 每台机器一个目录
      MACHINE.yaml              ← 身份声明(创建后只读)
      heartbeat.json            ← 最新心跳
      accounts.yaml             ← 本机管理的账号
      capabilities.yaml         ← 本机能力清单
    {machine_uid}/              ← 另一台机器
      ...

4. 写分区策略

4.1 每台机器只写以下文件

04_memory/cross_machine/machines/{MACHINE_UID}/
├── heartbeat.json              ← guardd 写(每300s)
├── accounts.yaml               ← matrix_mgmt 写(账号变更时)
├── capabilities.yaml           ← guardd 写(安装/卸载时)
└── events/                     ← guardd 写(事件记录)
    └── 2026-05-31.jsonl        ← append-only 事件日志

04_memory/cross_machine/data/{plugin_name}/
└── {MACHINE_UID}.json          ← Dashboard plugin 写(已经是这个模式 ✅)

4.2 写的规则

# ❌ 禁止操作
git add -A                                 # 错误:会 staging 别人文件
git add 04_memory/cross_machine/status/    # 错误:范围太宽
echo '{...}' > cross_machine/machines/{other_uid}/heartbeat.json  # 错误:写别人文件

# ✅ 允许操作
git add 04_memory/cross_machine/machines/{MY_UID}/
git add 04_memory/cross_machine/data/*/{MY_UID}.json

4.3 文件格式规范

每台机器写的所有数据文件,格式必须统一:

# 通用字段(所有数据文件必须包含)
schema_version: "2.0"           # 文件格式版本
file_version: 42                # 本文件修改次数(单调递增)
machine_uid: "...uuid..."       # 谁写的
machine_name: "chengzigedeAir"  # 谁写的(人类可读)
updated_at: "2026-05-31T17:48:28+08:00"  # 最后更新时间
# ... 业务数据 ...

5. 读聚合策略

5.1 Dashboard 读聚合流程

① git pull (获取所有机器最新数据)
  ↓
② 遍历 cross_machine/machines/*/ (每台机器一个目录)
  ↓
③ 读取每台机器的 heartbeat.json → 构建联邦总览
  ↓
④ 读取每台机器的 accounts.yaml → 构建账号注册表全貌
  ↓
⑤ 读取 data/{plugin}/*.json → 构建插件数据
  ↓
⑥ 按 updated_at 排序 → 去重 → 冲突处理
  ↓
⑦ 呈现统一视图

5.2 冲突合并规则

场景 规则
同一账号在两台机器上都有定义 updated_at 最新的覆盖旧的(打日志告警)
同一台机器写了多个版本 取 file_version 最大的
某台机器 24h 未更新 heartbeat 标记为 offline
文件 schema_version 不匹配 跳过不兼容的文件,打日志告警
某台机器 MACHINE.yaml 不存在 标记为未知机器,数据仍读取

5.3 聚合示例

# 读聚合的伪代码
def aggregate_machine_data():
    machines = {}
    for machine_dir in Path("machines/").iterdir():
        if not machine_dir.is_dir():
            continue
        uid = machine_dir.name
        hb_file = machine_dir / "heartbeat.json"
        if hb_file.exists():
            machines[uid] = read_and_validate(hb_file)
    return machines

def aggregate_accounts():
    all_accounts = []
    for machine_dir in Path("machines/").iterdir():
        acct_file = machine_dir / "accounts.yaml"
        if acct_file.exists():
            accounts = read_and_validate(acct_file)
            for acct in accounts:
                acct["_source_machine"] = machine_dir.name
                all_accounts.append(acct)
    return all_accounts  # 返回时已包含来源机器标记

6. 版本与时间戳控制

6.1 三层版本体系

层级 作用域 字段 示例 说明
V0 全局架构 schema_version "2.0" 整个 WPRA 架构版本
V1 每类文件 file_schema "heartbeat-v2" 某类数据文件的格式版本
V2 每次修改 file_version 42 本文件的修改次数
V3 每次修改 updated_at "2026-05-31T17:48:28+08:00" 最后更新时间

6.2 版本不兼容处理

# 读聚合时的版本判断逻辑
schema_version: "2.0"   ← 文件格式版本
file_schema: "hb-v2"    ← 心跳格式版本

# 读取方判断:
if file_schema == "hb-v2":
    正常解析
elif file_schema == "hb-v1":
    走旧版解析器 (兼容)
else:
    跳过,打日志告警

6.3 时间戳在联邦中的用途

用途 数据源 比较方式
判断机器在线 heartbeat.updated_at now - updated_at < 300s → online
判断数据陈旧 accounts.updated_at 按时间取最新
冲突裁决 各机器同类型文件 max(file_version) + updated_at
事件排序 events/*.jsonl 按 timestamp 排序
数据过期清理 所有文件 updated_at < 30天前 → 清理

6.4 跨机器事件板

# events/{machine_uid}/2026-05-31.jsonl
# 格式: 每行一个 JSON 事件,append-only
{"event_id":"evt_001","machine_uid":"4cf443bc...","type":"heartbeat","timestamp":"2026-05-31T17:48:28+08:00","data":{"cpu":0.5}}
{"event_id":"evt_002","machine_uid":"4cf443bc...","type":"nurture_run","timestamp":"2026-05-31T17:50:00+08:00","data":{"account":"douyin_test","result":"success"}}

事件日志解决了"谁在什么时候做了什么"的问题——这是机器间协调的事实基础。


7. Git 冲突消除方案

7.1 冲突预防三原则

  1. 粒度控制:每个机器的写操作只影响自己的命名空间
  2. 精确 add:不用 -A,改用 git add <own_namespace>
  3. 拆分单文件:不存在的共享文件需要聚合,就由 Dashboard 动态生成

7.2 guardd 的 git 操作规范

# ❌ 当前问题代码 (guardd.py line 376-393)
def _git_sync():
    subprocess.run(["git", "add", "-A"])    # ← 罪魁祸首
    subprocess.run(["git", "commit", ...])
    subprocess.run(["git", "push", ...])

# ✅ 修复后
def _git_sync(machine_uid, machine_name):
    # 只 add 本机命名空间的文件
    git_add_paths = [
        f"04_memory/cross_machine/machines/{machine_uid}/",
        f"04_memory/cross_machine/data/*/{machine_uid}.json",
        f"04_memory/cross_machine/events/",
    ]
    for path in git_add_paths:
        subprocess.run(["git", "add", path],
                      capture_output=True, timeout=15, cwd=str(repo))
    # 只在本机有变更时才 commit
    r = subprocess.run(["git", "status", "--porcelain",
                        f"04_memory/cross_machine/machines/{machine_uid}/"],
                      capture_output=True, text=True, timeout=10, cwd=str(repo))
    if r.stdout.strip():
        subprocess.run(["git", "commit", "-m", ...], ...)

7.3 账号注册表重构

将 accounts_registry.yaml(单文件、全员写)重构为:

# ❌ 旧结构:单文件,所有机器共享,谁改谁冲突
agent-sync/05_tools/07_matrix/accounts_registry.yaml

# ✅ 新结构:每台机器声明自己管理的账号
04_memory/cross_machine/machines/{machine_uid}/
  accounts.yaml         ← 本机管理的账号清单

Dashboard 读聚合时遍历所有机器的 accounts.yaml:

def get_all_accounts():
    """遍历所有机器,聚合账号注册表"""
    all_accounts = []
    machines_dir = CROSS_MACHINE / "machines"
    for machine_dir in machines_dir.iterdir():
        if not machine_dir.is_dir():
            continue
        acct_file = machine_dir / "accounts.yaml"
        if acct_file.exists():
            data = yaml.safe_load(acct_file.read_text())
            for acct in data.get("accounts", []):
                acct["_source_machine_uid"] = machine_dir.name
                acct["_source_machine_name"] = data.get("machine_name", "")
                all_accounts.append(acct)
    return all_accounts

7.4 _registry.json 的消除

_registry.json 是当前问题最大的单文件——它是最频繁写入的聚合文件。

处理方案:

  • guardd 不再写 _registry.json —— 删除 guardd.py 中 module_heartbeat() 里构建 _registry.json 的代码(line 331-358)
  • 只有 Dashboard 在响应 /api/push/heartbeat API 时才更新它(app.py line 609-611,这个只有一个实例运行,不会有冲突)
  • Dashboard 的 _registry.json 只作为运行时缓存,不是数据源

7.5 最终的目录结构和写权限

cross_machine/
├── machines/                          ← 核心:每台机器的数据
│   ├── {machine_uid_a}/              ← 只被机器A写入
│   │   ├── MACHINE.yaml              ← 一次写入,终身只读
│   │   ├── heartbeat.json            ← 机器A的 guardd 写
│   │   ├── accounts.yaml             ← 机器A的 matrix_mgmt 写
│   │   ├── capabilities.yaml         ← 机器A的 guardd 写
│   │   └── events/                   ← 机器A的 guardd 写
│   │       └── 2026-05-31.jsonl
│   ├── {machine_uid_b}/              ← 只被机器B写入
│   └── {machine_uid_c}/              ← 只被机器C写入
│
├── data/                              ← 插件数据(已正确 ✅)
│   ├── guardd/{uid}.json              ← 只被 uid 对应机器写
│   ├── matrix/{uid}.json              ← 只被 uid 对应机器写
│   └── ...
│
├── status/
│   └── live/
│       ├── {uid}.json                 ← 只被 uid 对应机器写 ✅
│       └── _registry.json             ← 只被 Dashboard app.py 写
│                                       ← guardd 不碰它
│
├── events/                            ← 全局事件(计划废弃 → 移到 machines/*/events/)
├── tasks/                             ← 任务分发(保持现有)
├── encrypted/                         ← 加密通信(保持现有)
├── knowledge/                         ← 共享知识(保持现有)
└── ARCHITECTURE-v2.md                 ← 本文档

8. 数据文件规范总表

8.1 心跳文件 (heartbeat.json)

# 路径: machines/{machine_uid}/heartbeat.json
# 写入者: guardd module_heartbeat() 每300s
schema_version: "2.0"
file_schema: "heartbeat-v2"
file_version: 142           # 单调递增
machine_uid: "4cf443bc-ff14-4ed9-885b-b04c5326304d"
machine_name: "chengzigedeAir"
updated_at: "2026-05-31T17:48:28+08:00"

status: "online"
guardd_version: "2.2.0"
cpu_load: 0.42
memory_pct: 45.2
disk_avail_gb: 161.3
uptime_sec: 86400
current_task: null

8.2 账号注册文件 (accounts.yaml)

# 路径: machines/{machine_uid}/accounts.yaml
# 写入者: matrix_mgmt 账号管理操作时
schema_version: "2.0"
file_schema: "accounts-v2"
file_version: 5
machine_uid: "4cf443bc-ff14-4ed9-885b-b04c5326304d"
machine_name: "chengzigedeAir"
updated_at: "2026-05-31T11:09:00+08:00"

accounts:
  - id: douyin_test
    platform: douyin
    phone: 153****8283
    status: logged_in
    enabled: true

8.3 MACHINE.yaml (身份声明)

# 路径: machines/{machine_uid}/MACHINE.yaml
# 写入者: 初始化时一次写入,终身只读
schema_version: "2.0"
file_schema: "machine-identity-v1"
machine_uid: "4cf443bc-ff14-4ed9-885b-b04c5326304d"
machine_name: "chengzigedeAir"
created_at: "2026-04-25T09:45:16+08:00"
role: "workstation"
notes: "Ghai's primary development machine"

8.4 已废弃/不再使用的文件

文件 废弃原因 替代方案
registry/{hostname}.json 旧格式,和 machines/*/ 重复 machines/*/MACHINE.yaml
status/live/_registry.json (guardd写入部分) 全员写导致冲突 只由 Dashboard app.py 写入
accounts_registry.yaml 单文件全员写 machines/*/accounts.yaml
status/{hostname}/heartbeat.json 旧格式,基于 hostname 不安全 machines/*/heartbeat.json
guardd-required-version.txt 单文件全员写,读聚合即可 废弃,用 version 字段在各文件中

9. 审计清单

9.1 设计审计

审计项 状态 说明
每台机器都有唯一不可变身份 ✅ machine_uid = UUID v4,永久不变
各写各的文件 ✅ 每台机器只操作自己的命名空间
从来不碰别人的文件 ✅ 禁止写入 machines/{other_uid}/
git add 精确可控 ✅ 不允许 -A,只 add 本机文件
读取方遍历所有机器 ✅ Dashboard 遍历 machines/*/
版本号控制文件兼容性 ✅ schema_version + file_schema 双保险
时间戳控制数据新鲜度 ✅ updated_at + file_version
废弃文件的迁移路径 ✅ 旧文件保持只读兼容,新系统用新路径
无全局共享单文件 ✅ _registry.json 由单实例 Dashboard 写入

9.2 安全审计

审计项 状态 说明
机器A不能冒用机器B的身份 ✅ 私钥在 agent-local,git 无法伪造
数据不泄露到其他机器 ✅ 敏感信息在 agent-local,不进 git
删除操作可追溯 ✅ events/ 日志作为审计线索

9.3 容错审计

场景 行为
机器A断网,机器B正常 机器A的 updated_at 停留在断网前,Dashboard 标记 offline
机器A的机器_uid 文件丢失 guardd 生成新 UUID → 成为新机器 → MACHINE.yaml 标记旧机退役
两台机器写了同名的账号 时间戳判定:后写的覆盖,标记冲突告警
某台机器的 accounts.yaml 损坏 跳过该文件,其他机器的数据不受影响
机器A搬到了新电脑 新 UUID → 新机器身份 → 迁移脚本导入账号数据

10. 全流程实操演练

10.1 场景:三台机器协同运转

机器: chengzigedeAir (UID: 4cf4...)  →  主力工作站
      5kechengdeAir  (UID: f13b...)  →  养号机
      7kecheng       (UID: d197...)  →  辅助采集机

10.2 Step-by-step 无冲突运转

T+0s: 三台机器同时启动 guardd
  ├─ 机器A → git pull → 写 machines/4cf4.../heartbeat.json
  │          → git add machines/4cf4.../ → git commit → git push
  ├─ 机器B → git pull → 写 machines/f13b.../heartbeat.json
  │          → git add machines/f13b.../ → git commit → git push
  └─ 机器C → git pull → 写 machines/d197.../heartbeat.json
             → git add machines/d197.../ → git commit → git push

  ✅ 结果:三个 push 无冲突,因为各写各的文件,各 add 各的命名空间


T+5min: 机器B完成一轮养号,更新账号状态
  ├─ 机器B → 写 machines/f13b.../accounts.yaml (更新账号状态)
  │          → git add machines/f13b.../accounts.yaml
  │          → git commit → git push ↴
  └─ 机器A → 同时写自己的 heartbeat
             → git add machines/4cf4.../
             → git commit → git push ↴

  ✅ 并行无冲突:B 改 B 的文件,A 改 A 的文件,互不干扰


T+1h: Dashboard 刷新查看所有机器状态
  ├─ git pull (获取所有机器最新数据)
  ├─ 遍历 machines/4cf4.../ + machines/f13b.../ + machines/d197.../
  ├─ 读取各自的 heartbeat.json → 3台机器都在线
  ├─ 读取各自的 accounts.yaml → 聚合得到完整账号表
  └─ 呈现统一视图

  ✅ 读聚合:一次遍历,全貌呈现


T+1天: 机器C下线
  ├─ machines/d197.../heartbeat.json 的 updated_at 不再更新
  └─ Dashboard 检测到 updated_at > 24h → 标记 offline

  ✅ 无额外操作:没有"下线通知"需要写,消失就是下线

10.3 冲突场景对比

场景 旧架构 新架构
三台机器同时写心跳 _registry.json 三方覆盖 → git冲突 ❌ 各写各的 machines/*/heartbeat.json → 无冲突 ✅
两台机器同时更新账号 accounts_registry.yaml 被覆盖 各写各的 machines/*/accounts.yaml → 无冲突 ✅
一台机器 push 后另一台 push git add -A 包含了对方文件 → 冲突 git add 只加自己文件 → 无冲突 ✅
Dashboard 刷新 读 _registry.json → 可能读到旧的 遍历 machines/*/ → 总是最新 ✅
新机器加入 手动在 registry/ 加文件 写自己的 machines/{new_uid}/ → 自动被发现 ✅

11. 分阶段实施计划

Phase 1:修复冲突根源(本次实施)

# 任务 涉及文件 风险
1.1 guardd: 删除 _registry.json 重建代码 guardd.py line 330-358 低
1.2 guardd: 删除 _registry.json 中扫描 data/ 的逻辑 guardd.py line 340-357 低
1.3 guardd: 将 git add -A 改为精确 add 本机文件 guardd.py line 380 中
1.4 guardd: 将 status 写入改为 machines/*/ 新格式 guardd.py module_heartbeat 低
1.5 创建本机 MACHINE.yaml 身份声明 guardd 首次运行时 低
1.6 废弃旧文件标记(不删,加注释) 文档 低

Phase 2:账号注册表重构(已完成 ✅)

# 任务 涉及文件 状态
2.1 matrix_mgmt: 新增 _write_self_accounts() matrix_mgmt.py ✅
2.2 matrix_mgmt: 新增 _read_all_machines_accounts() matrix_mgmt.py ✅
2.3 list_accounts(): WPRA优先,降级到旧文件 matrix_mgmt.py ✅
2.4 publish_status(): 触发 WPRA 同步写入 matrix_mgmt.py ✅
2.5 create/update/delete: 操作后更新 WPRA matrix_mgmt.py ✅
2.6 修复硬编码 /Users/5kecheng/ 路径 matrix_mgmt.py ✅

Phase 3:Dashboard 读聚合适配(已完成 ✅)

# 任务 涉及文件 状态
3.1 Dashboard: _registry.py WPRA 优先读 machines/*/ _registry.py ✅ v2.0
3.2 Dashboard: guardd 插件 WPRA 心跳路径 plugins/guardd.py ✅ v3.1
3.3 Guardd: 增加 events/ 写入能力 guardd.py ✅ Phase 1

Phase 4:旧数据清理(已完成 ✅)

# 任务 涉及文件 状态
4.1 确认新系统稳定运行 1 周 — ⏳ 等待中 (目标: 2026-06-07)
4.2 归档旧 registry 文件 registry/*.json → registry/_archive/ ✅
4.3 删除旧 _registry.json status/live/_registry.json ⏳ 等待 4.1
4.4 删除旧 accounts_registry.yaml 07_matrix/accounts_registry.yaml ⏳ 已标记废弃,等待 4.1
4.5 归档旧 status/{hostname}/ 目录 status/chengzigedeAir/ 等 → status/_archive/ ✅

Phases 5:文档化与标准化

# 任务 涉及文件 风险
5.1 更新 CORE-ARCHITECTURE.md 03_knowledge/99_system/ 低
5.2 同步本文档到 Gitee + GitHub — 低