# B 站动态主动刷新采集器 V004 formal-lock 接管最终修订 创建人员:`dev.developer.project.secondary / infodev-2` 文件职责:只关闭 V003 复审唯一剩余 `F2_F4_R2_FORMAL_LOCK_TAKEOVER_NOT_RESTARTABLE_FOR_ALLOWED_PATHS_AND_RECOVERY_IDENTITY`。V003 observation 计数已关闭;V001—V003 其余合同全部冻结。 基线:V003=`11225/99F05DC30C374F93B527F688319B479651FA5D19909DDDDB8135066C552A7FC4`;HOLD/1 回执=`msg_20260813135143290_a3bc85ea`。 ## 1. 同目录 quarantine V003 第 2.3 节 quarantine path 被本节替代。formal lock 与所有其历史隔离实物必须位于同一 `archive_dir`、同一父目录: ```text archive_dir/.bili-dynamic-formal-manifest.lock archive_dir/.bili-dynamic-formal-manifest.lock.quarantine/ -g-.json ``` 规则: - `archive_dir` 在任何 begin/lock 前做 lexical lstat;普通非reparse目录、父链无reparse;formal lock和quarantine目录都由该已验证 lexical root机械派生,禁止配置/输入覆盖。 - quarantine目录是本工具owned普通非reparse目录;若不存在,仅在无业务写入阶段创建并fsync父目录;若存在,必须普通非reparse、owner marker精确,否则 safety stop。 - 主lock到quarantine的 rename 源/目标父目录相同,Windows同卷由共同父目录构造保证;使用 no-overwrite atomic rename。目标已存在时只允许 exact bytes/hash匹配既有old claim并按reopen处理,不覆盖。 - pending 的 takeover 仅绑定 quarantine lexical relative path、old bytes/hash、目录 identity和expected generation;state_dir 不保存 quarantine副本。 - 启动时比较 `Path.GetPathRoot`/volume serial(Windows)或device ID(其他平台);不相等、查询失败或注入 cross-device error => `E_FORMAL_LOCK_VOLUME_IDENTITY`,在rename前停止。 - 原V003 `state_dir/refresh/lock-recovery/...` 路径明确废止;实现和fixture不得创建或fallback该路径。 测试使用可配置分离的 state/archive roots,证明 quarantine仍机械落在archive lock同目录;用模拟不同volume serial/EXDEV、reparse quarantine、existing different target、rename前后kill验证零覆盖和可恢复。 ## 2. holder-independent TAKEOVER_PLANNED V003 在 `TAKEOVER_PLANNED` 冻结 new holder claim 的描述废止。该 phase只冻结与恢复进程身份无关的 intent: ```text old_claim,old_lock_path,old_lock_bytes,old_lock_sha256, quarantine_path,next_generation=old_generation+1, takeover_reason=OWNER_DEAD_PROVEN,planned_at ``` 它**不得**含 new holder PID、process creation time、lock_created_at、new lock bytes/hash。任何含 holder-dependent new claim 的 persisted plan 拒绝。 状态机: 1. 当前进程在 StateLock 下证明 old owner dead、old lock和pending exact绑定;写 holder-independent `TAKEOVER_PLANNED`。 2. reopen无论是否换进程,都重新验证 old claim/owner状态/volume/quarantine。主lock=old且quarantine缺失时执行同目录rename;主lock缺失且quarantine=old时推进 `OLD_LOCK_QUARANTINED`。这一步不需要也不沿用前一恢复进程身份。 3. **只有 pending 已 durable `OLD_LOCK_QUARANTINED` 后**,当前恢复进程读取自己的 PID 与OS process creation time,构造 generation=`next_generation` 的 new lock record;先把 `new_claim_state=CREATE_PLANNED` 与该 current identity/bytes/hash 原子写入 pending,再 CreateNew主lock并回读,最后推进 `NEW_LOCK_HELD`。 4. current process若在 CREATE_PLANNED 后、CreateNew前被kill:下一进程验证主lock absent、quarantine exact和旧 planned holder dead/PID-reuse;然后原子替换 pending 中 holder-dependent claim为**当前进程**的 new claim(generation保持next_generation,另增 `claim_attempt`),再CreateNew。不得写上一进程identity。 5. 若主lock已存在:只有它exact等于pending CREATE_PLANNED claim且OS证明该holder alive同identity时返回busy;若holder dead则在仍持StateLock下把这一新stale lock作为同generation的失败claim隔离到同目录额外路径 `-g-attempt-.json`,pending记录失败attempt,再由当前进程生成新的claim_attempt;PID reuse/第三内容/异run一律ambiguous。 6. `NEW_LOCK_HELD` 后当前holder崩溃,generation+1的新takeover按V003通用协议开始;不复用旧claim。 `claim_attempt` 从0单调递增,每次holder-dependent claim更换+1;run/owner_nonce/transaction_id/next_generation保持不变。所有旧/失败claim隔离实物到terminal cleanup前保留并由pending exact列出,防止丢失接管历史。 ## 3. reopen矩阵与反例 | pending phase | main lock | quarantine | 唯一动作 | |---|---|---|---| | TAKEOVER_PLANNED | old | absent | reprove dead/volume,rename old | | TAKEOVER_PLANNED | absent | old exact | 推进 OLD_LOCK_QUARANTINED | | TAKEOVER_PLANNED | 其他 | 任意 | ambiguous | | OLD_LOCK_QUARANTINED,无new claim | absent | old exact | 当前进程生成CREATE_PLANNED | | CREATE_PLANNED | absent | old exact | 若planned holder为当前则CreateNew;否则证明旧planned holder dead/PID reuse后换绑当前 | | CREATE_PLANNED | exact planned new | old exact | alive同identity busy;dead则隔离失败attempt并换绑 | | CREATE_PLANNED | 第三内容 | 任意 | ambiguous | | NEW_LOCK_HELD | exact new | old exact | current继续;other alive busy;dead则新generation takeover | 全点真实kill:TAKEOVER_PLANNED落盘、old rename、OLD_LOCK_QUARANTINED、CREATE_PLANNED、new CreateNew、NEW_LOCK_HELD。重点断言 kill-after-TAKEOVER_PLANNED 的下一进程不写旧恢复PID;planned PID已复用不视为alive同holder;不同volume在rename前fail;两recovery竞争只有StateLock winner;formal append最多一次。 ## 4. 冻结和终态 F1 observation互斥计数、F3 mixed-history、F5 hourly slot以及source-controlled evidence、pending WAL、双candidate、五终态全部不重开。 状态=`V004_FINAL_LOCK_CLOSURE_PENDING_ORIGINAL_REVIEWER_IMPLEMENTATION_FROZEN`。 产品 code/test/fixture/formal modification=0;Chrome/network/download/extension/policy/HKCU/session/formal write=0。V001+V002+V003+V004仅在原reviewer PASS/0后实施。