Record the two-trees partial close and renderer records #116

Merged
weichen merged 37 commits from feature/rdm-two-trees-latest-templates into main 2026-10-19 07:51:30 +00:00
3 changed files with 31 additions and 0 deletions
Showing only changes of commit 582e7c0f06 - Show all commits
@@ -95,6 +95,7 @@ RDM保有领域、schema/事件与业务权限;Backend仅补必要通用公开
- [X2跨成员已提交业务审计链接修订r1](../records/2026-10-14-rdm-two-trees-latest-templates/rdm-two-trees-stage6-audit-link-design-adjustment-r1.md):W9发现只凭会话项目会泄露私域或重归属旧操作。建议仅将可信已提交项目事件与宿主行建立不可变链接,再按当前审计/资源权限投影。公开写/读合同改变了阶段4 X2,用户已于本聊天call_bf9116ffe4ff4c5bbc4809a58ab02cbe第0项选择“批准修订,继续跨成员审计(推荐)”;W9可按修订继续实施,但安全owner局部不等于跨成员完整审计。SHA256 `385d9d7570217ddcce9fe60a60c99dc58c9a4875ad790584a724d09a210a6e52`。
- [W2/W4实施顺序修订r1](../records/2026-10-14-rdm-two-trees-latest-templates/rdm-two-trees-stage6-w2-w4-sequence-adjustment-r1.md):W2的并发字典修订与事务回滚在当前RDM分支保留两条RED;建议将已批准W4事务隔离基础W4a移到W3之前,由W2 owner在同一工作区修复,W3仍等待DHF U1合入,W4提案/真人确认W4b仍在W3后。此关键依赖调整待人工评审;未获批前不开始W4a。SHA256 `aaf8c091772149a3547cbec272a7f38de3a47cc41c84b7bcef05e74510efbacf`。
- [W9 PostgreSQL审计截止水位修订r1](../records/2026-10-14-rdm-two-trees-latest-templates/rdm-two-trees-stage6-w9-pg-audit-cutoff-adjustment-r1.md):现有序列ID可低号晚提交,固定页游标缺少已提交前缀保证;建议在序列CACHE 1等前提下串行化在线审计ID分配,并补迁移/回滚/离线复制检查。此持久化顺序语义和写入吞吐变化待人工评审;未获批前不改W9生成器。SHA256 `2357b715a7c8f3451b34cc25a578d655e8a48f3f26d9cf7561ea7a13998ca857`。
## 阶段6启动记录
@@ -14,6 +14,7 @@
- [X1/X2基座公开扩展申请r1](rdm-two-trees-stage6-public-extension-requests-r1.md)
- [X2跨成员审计可信链接设计修订r1](rdm-two-trees-stage6-audit-link-design-adjustment-r1.md):用户已批准受影响公开合同,原对象保留评审前状态。
- [W2/W4关键依赖顺序修订r1](rdm-two-trees-stage6-w2-w4-sequence-adjustment-r1.md):W2并发与事务回滚失败后提出;待人工评审,未开始W4a。
- [W9 PostgreSQL审计截止水位修订r1](rdm-two-trees-stage6-w9-pg-audit-cutoff-adjustment-r1.md):低ID晚提交问题的受影响数据设计;待人工评审,未改在线生成器。
- [阶段4源码与在途依赖快照](stage4-sources.json)
- [模板与会议来源台账](rdm-two-trees-source-inventory.json)
- [旧DOC源码补充](rdm-two-trees-legacy-source-addendum.md)
@@ -0,0 +1,29 @@
# 阶段6受影响设计修订:PostgreSQL 宿主审计截止水位 r1
记录日期:2026-10-14。状态:**待人工评审**。本修订只影响 Backend W9 的 PostgreSQL `command_audit` 新写入顺序、固定截止分页和迁移恢复;X2 已批准的“仅可信已提交项目业务操作可跨成员关联”、owner 私域、当前权限检查与 RDM 操作级投影不变。W9 当前独立分支 HEAD `0e8cd040cc75c329eb8950676acc7a9a08487ad2` 尚未合入或部署。
## 发现与风险
隔离 PostgreSQL 18.6 的 `TestProjectAuditPostgresCutoffLateCommit` 已实际复现:事务 A 先分配低 `command_audit.id` 但暂不提交,事务 B 后分配较高 ID 并先提交;同一 `CutoffOffset` 后来可读到原先不可见的低 ID。该测试证明当前截止水位**不是固定可见快照**,尚未直接模拟跨页漏行;正式 RED 还需构造已提交的更低 ID、未提交的中间 ID、已提交的较高 ID,第一页游标越过中间 ID 后再提交。现有页面诚实标 `cutoffConsistency=offset-upper-bound-only`,不能作为 W9/W8 稳定历史分页完成证据。SQLite 当前单写连接没有该并发路径;它的测试结果不能证明 PostgreSQL 安全。
`command_audit.id` 同时是宿主审计 source offset 和可信链接的定位键。`REPEATABLE READ` 只固定一次 HTTP 请求内快照,不能固定多次请求;在现有 `CutoffOffset` 整数合同下,读取端无法识别之后才提交的低 ID。若改为服务端持久分页快照或新提交序列列,就要扩展游标/存储和清理规则。当前生产写入口 `cmdbus → Store.AppendAudit` 省略 `id`;离线 `storage-migrate` 及测试会显式复制 ID。以下为**方案建议,不是已实施或通过的能力**。
## 建议的最小修复
在 W9 PostgreSQL 迁移中,把 `command_audit.id` 的默认生成器改为 `next_command_audit_id('command_audit'::regclass)`:函数先取得该表的**事务级 advisory lock**(独立双整数命名空间+表 OID),再调用原序列 `nextval`,锁随事务提交/回滚释放。所有受支持的在线审计 INSERT 均省略 ID、走此生成器;后一个事务不能在前一个分配 ID 的事务结束前取得 ID。**前提是该序列 `CACHE 1`、正向、不循环、下一 ID 始终为正且高于既有最大 ID**:PostgreSQL 官方文档说明 `CACHE > 1` 可使不同会话从预留块取号而乱序;迁移必须核验配置与当前位置,不满足时失败关闭并要求先停写、排空持有旧缓存的连接后单独处理,不能单靠 `ALTER SEQUENCE ... CACHE 1` 认为旧连接缓存立即失效。函数及启动检查也应拒绝后续不符配置。在线显式插入 ID、`setval`/`RESTART` 回退、运行中调整序列参数都列为禁止的维护动作;授权的离线复制只能在排他停写窗口进行,随后把序列推进到已复制最大 ID 之上。否则即便主键唯一也可能利用空洞制造低 ID 迟提交。提交成功的受支持在线新行因此形成 ID 前缀;回滚造成的空洞不被误认为待提交行。表迁移锁应等待旧写事务退出,避免新旧生成器在过渡窗口并发分配。该锁只串行审计 append 的事务,不作为项目业务事务或 RDM 事件的统一顺序。[序列缓存与跨会话乱序](https://www.postgresql.org/docs/18/sql-createsequence.html)、[ALTER SEQUENCE 对既有缓存连接的影响](https://www.postgresql.org/docs/18/sql-altersequence.html)、[事务级 advisory lock](https://www.postgresql.org/docs/18/functions-admin.html)。
仍保留现有数值 `CutoffOffset`、`BeforeOffset` 和 `HostAuditOffset` 字段,不改历史链接身份。PostgreSQL 固定截止只在 schema、序列不变量及受支持写入口均经运行时核验后报告 `committed-prefix`;任一条件无法证实时失败关闭或降为明确 `offset-upper-bound-only`,不能裸报强保证。迁移前的旧历史行在迁移完成时已提交,可纳入之后的新查询。迁移前已发出的旧游标若可能被外部使用,应拒绝或显式标旧语义,不能静默升级;本 W9 公开读面目前仅未合入候选,应在首次发布前验证没有已部署使用者。若回滚到旧 schema/二进制,先停写并执行受控 down;旧二进制会因未知迁移版本拒绝启动,降级后覆盖语义须回到 `offset-upper-bound-only`,不能继续声称已提交前缀。
离线复制的显式 ID 不经默认函数,`storage-migrate.advanceSequences` 当前只识别 `column_default LIKE 'nextval%'` 或 identity;改为函数默认后必须通过 `pg_get_serial_sequence` 所有权识别并在恢复后推进原序列至最大已有 ID。迁移 up/down 要在隔离副本验证,down 先恢复原 `nextval` 默认再移除函数。SQLite 保持现有行为。锁键应稳定限定该表,避免与其他 advisory lock 冲突;函数、权限和升级过程须在目标 PostgreSQL 版本重放,不把测试库成功当现网迁移授权。
## 影响与取舍
好处是无需新增公开分页字段或复制整批 ID 的服务端快照,能在同一数值 cutoff 下保证**新在线写入**的已提交前缀。代价是 PostgreSQL 全部 `command_audit` append 按事务串行;一个长事务或卡住的写入会使后续审计写入等待,进而影响命令完成时延。迁移需锁表和停顿写入,必须测等待、超时及回滚。继续使用现有无序列化 ID 只能维持 `offset-upper-bound-only` 且会漏读,不满足当前完整追溯审计验收;服务端持久快照可避免写入串行,但引入快照生存期、清理和授权 epoch 绑定,范围更大。
## 验证与停止条件
- 隔离 PG 至少三行/两事务的真实跨页漏行负例先 RED 后 GREEN;`CACHE 10` 跨连接乱序负例以及 `CACHE 1` 正例;回滚空洞、迟到可信链接、同项目两成员/撤权、长事务等待与锁/语句超时均保持真实结果。当前 `AppendAudit` 没有 `context.Context`,本次只用 PostgreSQL `lock_timeout`/`statement_timeout` 测等待中止,不宣称请求取消可直接中止。当前 SQLite/PG 宿主审计和链接测试不得回退。
- 从既有 schema/数据升级并回滚,再在排他停写窗口运行离线 `storage-migrate` 复制显式 ID 并新增审计行;证明下一 ID 正且高于最大已有 ID、无重复键、原链接定位不变。用序列回退到空洞、在线显式 ID、`CACHE > 1`、不正常 down/旧二进制等负例证明强 coverage 不会被误报。迁移需与 W6 的 v31/v32 冲突在真实串行合入时重排并做组合验证,不能在两个未合分支各自宣称组合通过。
- 压力测试记录审计 append 的等待/吞吐变化,超出可接受运行预算则停下并回到替代方案;阶段7继续验证 RDM operation 级分页及当前授权过滤。这个 Backend 修复不等于 W8 RDM 投影已完成。
请评审是否接受上述 PostgreSQL 新写入提交前缀语义和串行化代价。批准仅放行 W9 在隔离分支实现与测试;真实运行库迁移、发布及完整阶段6/7出口仍按原门禁。