Compare commits

...
Author SHA1 Message Date
weichen 73bbb4cea6 Merge remote-tracking branch 'origin/main' into feature/layered-python-env 2026-10-15 14:01:27 +00:00
weichenandCursor 945db355fc Record the layered Python environment proposal
Why: 8788 could not render docx because the sandbox hides host site-packages and there is no request path for extra packages. The proposal fixes the design before the implementation lands.
Evidence: SELF — proposal written from the cnv_7936c0a799ff transcript and the existing exec-deps-dir code path.
Impact: Documents only. Index lists the proposal as pending review, not approved.
Refs: docs/proposals/2026-10-15-layered-python-env.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 13:29:49 +00:00
weichen f01aefa4eb Merge pull request 'Record the document duty matrix rework' (#108) from feature/rdm-duty-matrix into main 2026-10-15 09:15:11 +00:00
weichen 5f411499c5 Merge remote-tracking branch 'origin/main' into feature/rdm-duty-matrix 2026-10-15 09:14:32 +00:00
weichenandCursor 034faa4021 Record the document duty matrix rework
Why: the duty page needs one record for the four domain rulings, and the earlier settings plan must show which duty-page sections it no longer owns.
Evidence: SELF review of the proposal text against the approved implementation plan.
Impact: r1 section 4 and the duty-page parts of P5 and P7 point at r2. Settings, members, and the permission matrix stay in r1.
Refs: docs/proposals/2026-10-15-rdm-duty-matrix-rework.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-15 07:20:46 +00:00
4 changed files with 169 additions and 4 deletions
@@ -81,6 +81,10 @@ product_contract_source: legacy-requirements
## 四、文档查找与职责分配 ## 四、文档查找与职责分配
> 2026-10-15:本节的职责页交互(文档清单加选中详情、章节级入口、整文审签)已被
> [文档职责矩阵整改 r2](2026-10-15-rdm-duty-matrix-rework.md) 取代。成员校验、版本冲突、
> 在途审签确认和历史保全仍然有效。下文保留作被取代前的记录。
文档职责页面采用“**文档清单+选中文档的职责详情**”: 文档职责页面采用“**文档清单+选中文档的职责详情**”:
- 上方提供统一搜索框,支持文档 ID 精确检索、标题精确/模糊匹配。 - 上方提供统一搜索框,支持文档 ID 精确检索、标题精确/模糊匹配。
@@ -162,9 +166,9 @@ product_contract_source: legacy-requirements
| P2 系统设置闭环 | Core 设置描述、Backend 设置 API/存储/生效链/模型及密钥解析;系统管理入口 | P1;**基座发版与 RDM/Dev 升 pins**(见评审补充 1) | 系统受管项只能由有权管理员配置,旧个人/项目值不能覆盖 | | P2 系统设置闭环 | Core 设置描述、Backend 设置 API/存储/生效链/模型及密钥解析;系统管理入口 | P1;**基座发版与 RDM/Dev 升 pins**(见评审补充 1) | 系统受管项只能由有权管理员配置,旧个人/项目值不能覆盖 |
| P3 人员与成员接口 | 扩展公开账号搜索;RDM 专业角色摘要、成员查询、项目身份调整与提交校验 | P1;姓名来源核实(见评审补充 3) | 账号/姓名/角色过滤同源,添加与身份调整明确分离 | | P3 人员与成员接口 | 扩展公开账号搜索;RDM 专业角色摘要、成员查询、项目身份调整与提交校验 | P1;姓名来源核实(见评审补充 3) | 账号/姓名/角色过滤同源,添加与身份调整明确分离 |
| P4 文档与职责接口 | 专用文档目录、当前职责读取、统一职责服务、版本校验、变更失效及成员移除联动 | P1、P3 | 跨项目/非成员指派被拒,职责与审签变更全成或全败 | | P4 文档与职责接口 | 专用文档目录、当前职责读取、统一职责服务、版本校验、变更失效及成员移除联动 | P1、P3 | 跨项目/非成员指派被拒,职责与审签变更全成或全败 |
| P5 通用选择器 | UI 仓搜索选择、单/多选、键盘操作、分页与状态;Frontend 人员/文档适配 | P1,接线依赖 P3、P4 | 三类使用场景共享交互,无自由文本误提交 | | P5 通用选择器 | UI 仓搜索选择、单/多选、键盘操作、分页与状态;Frontend 人员适配。文档职责页的文档选择器改由 r2 三视图承接 | P1,接线依赖 P3、P4 | 人员选择共享交互,无自由文本误提交。职责页交互见 r2 |
| P6 权限解释与矩阵 | RDM 项目动作目录、单人/批量解释、覆盖三态、来源与拒绝原因 | P1、P3 | 矩阵与执行规则一致,系统动作无法写入项目覆盖 | | P6 权限解释与矩阵 | RDM 项目动作目录、单人/批量解释、覆盖三态、来源与拒绝原因 | P1、P3 | 矩阵与执行规则一致,系统动作无法写入项目覆盖 |
| P7 项目设置集成 | 重构现有项目页,连接四个页面、能力状态、读取回填与保存结果 | P2—P6 | 创建者、普通成员、职责人员均有对应可用流程 | | P7 项目设置集成 | 重构现有项目页,连接设置、成员与权限页。文档职责页改为 r2 的三视图,不再包含整文审签 | P2—P6 | 创建者、普通成员、职责人员均有对应可用流程。职责页验收以 r2 为准 |
| P8 迁移与组合验收 | 旧配置处置、真实数据库与浏览器验收、精确组件组合验证、证据回填 | P2—P7 | 需求到证据闭合,无越权、隐私泄露或数据丢失 | | P8 迁移与组合验收 | 旧配置处置、真实数据库与浏览器验收、精确组件组合验证、证据回填 | P2—P7 | 需求到证据闭合,无越权、隐私泄露或数据丢失 |
前端主要改动落在现有 `ProjectSettingsModal`、`adminRdmSections`、`rdmManagement`、`api` 和 `store`;按业务拆分成员、职责及权限组件,避免继续扩大一个管理组件文件。 前端主要改动落在现有 `ProjectSettingsModal`、`adminRdmSections`、`rdmManagement`、`api` 和 `store`;按业务拆分成员、职责及权限组件,避免继续扩大一个管理组件文件。
@@ -0,0 +1,108 @@
# 分层 Python 环境方案 r1
状态:待评审(收录不是批准)。编制:2026-10-15。
触发:dev 8788 会话 `cnv_7936c0a799ff` 中,智能体无法把已有 Markdown 摘要渲染成 docx,并向用户报告「没有 Python 对应的包」。
## 1. 已核实的故障(不是「缺包」本身)
8788 的 `run_python` / `run_shell` 跑在 bwrap 沙箱里(只读根、`--tmpfs /home`、`--unshare-net`)。同一台宿主机的 `~/.local` 里其实已经有 python-docx、lxml、openpyxl、python-pptx。失败来自四件事叠在一起:
1. **依赖层没有接线。** 代码已有 `--exec-deps-dir`(F3),但 `scripts/svc.sh` 与 8788 的启动参数都没有传入它。沙箱把 `/home` 遮掉之后,`~/.local` 不可见。
2. **解释器解析到会被遮掉的路径。** 服务进程的 `PATH` 里 linuxbrew 在 `/usr/bin` 之前,`python3` 被解析成 `/home/linuxbrew/.linuxbrew/bin/python3`。沙箱里这条路径不存在,`run_python` 得到 `exit=127`。
3. **工具说明指向一条走不通的安装路径。** `run_python` 描述和 `base.deliverables` 都写「缺库先 `pip install --user`」。沙箱断网、根只读、家目录是空 tmpfs,这条命令必然失败。
4. **没有向系统申请包的通道。** 智能体只能探测、报错、让用户选择,再派一个后台任务去轮询一个永远不会出现的依赖。
同一次会话里还有多次模型网关 `401 invalid_api_key`。那是密钥问题,不在本方案范围内。
## 2. 目标
每个工作区和沙箱都能直接使用系统提供的 Python 能力(解释器 + 办公与数据处理基础包),不必各自新建虚拟环境。某个工作区需要额外的包时,向系统申请;系统决定装不装,并只把结果挂给这个工作区。
成功标准:
- 沙箱内 `import docx, openpyxl, pptx` 成功,`python3 -m housestyle.build` 能产出通过结构自检的 docx。
- 两个工作区要同一包的不同版本时,互不影响,基础层版本不变。
- 沙箱仍然断网。安装只发生在宿主侧的构建器里,并且只接受带哈希的预编译 wheel。
- 白名单内的包自动批准;白名单外、要改基础层版本、体积超限、用户上传的 wheel,弹审批卡。sdist 与黑名单直接拒绝。
## 3. 不采用的两条路
- **每个工作区一个 venv。** 贵的是重复下载、解析和安装,不是 venv 目录本身。同样的包会被装很多遍。
- **所有包装进一个可变的系统环境。** 一个工作区的需求会改变所有工作区的行为,版本冲突无法隔离,也无法复现「当时用的是哪一套包」。
## 4. 采用的结构
所有环境层不可变,按内容哈希命名,按会话挂载。系统只新增层,不改已经发出去的层。
```text
<envroot>/ 默认 runtime/envs/,各服务实例共享
python/cpython-<ver>/ 系统托管的 CPython(只读)
python/current -> 上述目录
layers/base-<hash>/site-packages
layers/x-<hash>/site-packages 扩展层:相对基础层的增量闭包
layers/iso-<hash>/site-packages 完整隔离层:仅在审批通过「覆盖基础层版本」时使用
wheelhouse/ 按 sha256 去重的 wheel
locks/<hash>.json
catalog.json 白名单、黑名单、单包体积上限
current -> layers/base-<hash>
bin/pip 垫片:提示改用 python_env,不以安装成功退出
```
层键 = 锁文件内容 + Python 标签 + 平台的哈希。同一份需求在任何工作区都命中同一层。
基础层由系统策划,首批为:python-docx、openpyxl、python-pptx、lxml、Pillow、numpy、matplotlib、pypdf、reportlab、markdown、pdfplumber,以及它们的传递依赖。名单可以在评审时增减;锁文件在第一次 `env ensure` 时生成并应入库,之后构建按锁复现。
解释器优先使用托管前缀(python-build-standalone 的 install_only 包)。下载失败时,退化为用系统 `python3 -m venv` 做一份唯一的托管前缀,并在 `python/SOURCE` 里写明这是退化,不是每个工作区各做一份。沙箱里的 `python3` 永远是这个前缀的绝对路径;找不到托管前缀时才用 `/usr/bin/python3`,不再走会落到 `/home` 下的 `PATH` 查找。
## 5. 一次执行如何看到这些包
沙箱参数在 `--tmpfs /home` 之后,只读挂载:托管解释器前缀(如果它位于会被 tmpfs 遮住的路径上)、基础层、该会话绑定的扩展层。`PATH` 固定为 `<托管 bin>:<envroot>/bin:/usr/local/bin:/usr/bin:/bin`,不再继承宿主 `PATH`。`PYTHONPATH` 是这些层再加上 house-style。`PIP_NO_INDEX=1`。
扩展层与基础层来自同一次以基础层为约束的解析,每个发行名只有一个版本,所以叠放顺序不影响导入。隔离层例外:它替换基础层,而不是叠在上面,用来满足「这个工作区必须要 numpy<2」这类与基础层冲突的需求。
## 6. 申请(工具 `python_env`)
动作:`status`、`request`、`wait`。
- `status` 返回基础层包清单、本会话已绑定的层、未完成的申请。
- `request` 带包规格或工作区内的 `.whl`。解析以基础层锁为约束(等价于带 constraints 的 `pip install --dry-run --report`)。分级:
- 全部在白名单内、纯 wheel、未超体积:自动批准并构建。命中已有层时只是多挂一个目录。
- 白名单外、要覆盖基础层已固定的版本、超体积、用户上传的 wheel:写入 `exec_env_requests`,发一张选择卡(批准 / 拒绝;覆盖基础层版本时多一个「建隔离层」)。系统管理员或该会话的属主可以批。决定写入 `audit_events`。
- 只有 sdist、命中黑名单、解析失败、哈希不符:拒绝,并说明原因。
- 构建在宿主侧进行:`--only-binary=:all:`,校验 sha256,只用解包 wheel,不执行 setup.py。这是唯一有网络的步骤,并且不在沙箱里。
- 构建完成后把层 ID 写进 `exec_env_bindings`。下一次 `run_python` / `run_shell` 挂上这些层。`wait` 在短超时内轮询申请状态。
## 7. 三个顾虑如何被挡住
- **成本。** 基础层覆盖常见办公和数据场景。wheel 与层按哈希缓存,第二个工作区要同一套包时不再下载、不再解析。
- **冲突。** 不存在共享的可变环境。冲突需求要么被拒绝并说明卡在基础层的哪一个版本,要么经审批得到一份只属于该会话的隔离层。基础层哈希不变。
- **包都堆进系统环境。** 基础层只放策划过的包。扩展层按会话绑定,其他会话看不见。升级基础层生成新的 `base-<hash>` 并移动 `current`;已经绑定旧基础层的会话保持不动,直到显式 rebase。
## 8. 安全
- 沙箱断网、根只读、家目录遮蔽,这些都不放宽。
- 不在宿主上执行第三方构建脚本。
- 只挂当前会话绑定的层。
- 申请记录含会话、包、wheel 哈希、批准人。
- 任务封存时应能读到基础层哈希与层 ID(绑定表就是这份清单)。
## 9. 实施切片
- **P0** 解释器与 `PATH` 不再指向会被沙箱遮住的 linuxbrew;`svc.sh` 在环境根存在时传入 `AGENT_SYSTEM_EXEC_ENV_ROOT` 与基础层 `AGENT_SYSTEM_EXEC_DEPS_DIR`;工具说明与提示词改为 `python_env`,去掉 `pip install --user`;配置了依赖层时启动做真实导入探针。
- **P1** 环境根、锁、层、wheelhouse、托管解释器,以及 `agent-system env ensure|lock|gc|doctor|rebase|python`。
- **P2** 表 `exec_env_requests`、`exec_env_bindings`,工具 `python_env`,分级审批,pip 垫片,按会话挂载。
- **P3** 管理区「Python 环境」页(层、申请、批准/拒绝、rebase、gc、上传 wheel)。
## 10. 验收
- `sandboxArgv` 覆盖多层只读挂载、固定 `PATH`、`PIP_NO_INDEX`。
- 离线解析夹具:冲突、白名单、sdist 拒绝、哈希不符。
- 有 bwrap 时:沙箱内能导入层里的模块,`pip` 垫片给出申请指引,外网不可达。
- 两个会话分别要 `foo==1` 与 `foo==2`,各得一层,基础层哈希不变。
- 在基础层可用时,`housestyle.build` 产出的 docx 通过既有 OOXML 结构自检。
## 11. 已定与未定
已定(2026-10-15 对话):白名单内自动批准,其余弹审批卡;解释器由系统托管,而不是长期绑死宿主 `/usr/bin/python3`。
未定,留在评审:基础层最终包名单是否增减;审批人除系统管理员和会话属主外,是否还要接项目角色。本实施先只认系统管理员与会话属主,避免在基座里发明第二套项目角色判断。
@@ -0,0 +1,48 @@
---
title: 文档职责矩阵整改
date: 2026-10-15
type: feature
execution: code
artifact_contract: rdm-duty-matrix/v1
product_contract_source: legacy-requirements
---
# 文档职责矩阵整改 r2
负责人:weichen;编制日期:2026-10-15。
本记录是文档职责整改的唯一主记录。它取代
[r1 增量方案](2026-10-13-rdm-settings-members-duties-perms-increment.md)
第四节,以及该方案 P5、P7 中“文档职责页”的交互;r1 的设置归属、成员、权限矩阵与其余工作包继续有效。
候选分支 `feature/rdm-settings-completion` 里的文档职责界面暂停合入。系统设置、成员选择、权限矩阵和已落地的后端安全能力不在本暂停范围内。本任务从当时的 `origin/main` 另起兄弟分支 `feature/rdm-duty-matrix`,不把该候选当作父分支。
## 四项领域裁定
1. 职责只到文档级。项目设置不再新增章节级职责;历史章节审签只读保留。
2. 项目设置只分配已有受控文档的编制、审核、批准职责。不创建文档、不从模板生成、不提交审核、不审核通过、不驳回、不终批。
3. 每份文档恰好一名编制、至少一名审核、恰好一名批准。同一人在同一文档上只担一个职责。审核可以有多人。
4. 与文档职责完全一致的旧章节覆盖可以归并为文档级。同一文档下章节人员不一致的,列出清单,由项目负责人逐文档确认,不自动覆盖。
项目负责人可以分配职责,但不因负责人身份自动成为编制、审核或批准人。当前职责与已冻结的审签名单分开保存;修改当前职责不改写已批准版本和历史名单。
姓名来源仍按 r1 评审补充第 3 条待证。本页用账号标识展示,不把未证实的姓名字段写进契约。
## 契约
读:`rdm.duty.matrix`。`view` 为 `member`、`document` 或 `matrix`。筛选在分页之前。文档页上限 20。响应给出文档完整性、`dutyVersion`、章节覆盖数、在途轮次、成员资格、单元格 `none|author|reviewer|approver`,以及当前操作人是否可分配。单元格只投影当前文档级职责。没有 `duty.assign` 的调用直接拒绝,避免矩阵列头泄露不可见文档。
写:唯一入口仍是每份文档的完整目标,`rdm.review.assign.doc` 与 `rdm.review.assign.doc.batch`(1–20 项,整批原子)。带 `expectedDutyVersion` 与 `confirmInvalidation`。`rdm.review.assign` 只返回“章节级职责已停用,请在文档级设置”。
预览:`rdm.duty.preview` 与写载荷相同,只读返回替换对象、在途失效和缺人原因,不写数据。保存时服务端重新校验。
迁移:`rdm.duty.legacy.scan` 只读;`rdm.duty.legacy.apply` 只清除与文档职责完全一致的章节覆盖。
## 三视图
按人员、按文档、成员×文档矩阵共享同一份服务端数据和同一份未保存草稿。单元格由文档三权反推。把唯一编制或批准改成其他值可以继续编辑,但在指定接替人前不能保存。替换已有编制或批准时提示“将替换某某”,保存时一次替换。窄屏不压缩整张矩阵,改走前两个视图。一次保存最多 20 份文档。请求带递增序号,过期响应丢弃。写入结果未知时重读,不自动重放。
页面顶部写明:本页只分配已有文档的职责,不创建或生成文档。
## 验收
单文档三权恰好、多审核人、一人一责、三视图草稿一致、替换提示与原子替换、缺人禁止保存、成员失效保存被拒、版本冲突、批量整批失败不写、影响预览与历史不变、无私密文档列头泄露、无创建/生成/审签按钮、迟到响应不覆盖、design-guard、`make test` 与 `make build`。部署和真实账号浏览器验收另行授权。
+7 -2
View File
@@ -4,7 +4,8 @@
本索引负责导航与差异提示,规划正文、批准范围和验收条件仍以链接的主记录及其批准版本为准。 本索引负责导航与差异提示,规划正文、批准范围和验收条件仍以链接的主记录及其批准版本为准。
合入授权不批准新方向、不调整里程碑范围、不启动新的业务任务。 合入授权不批准新方向、不调整里程碑范围、不启动新的业务任务。
待评审(收录不是批准):[svc 插件组合部署(--with)方案 r1](2026-10-14-svc-plugin-compose-deploy.md)。 待评审(收录不是批准):[svc 插件组合部署(--with)方案 r1](2026-10-14-svc-plugin-compose-deploy.md);
[分层 Python 环境方案 r1](2026-10-15-layered-python-env.md)(8788 无法生成 docx 的环境层;白名单自动批准,其余审批)。
## 先看哪一份 ## 先看哪一份
@@ -182,7 +183,11 @@ RDM 总案把库分期作为支撑与依赖,不覆盖库分期的原始范围
- [最终验证与合入调度实施计划 r1](2026-10-13-merge-queue-implementation-plan.md):阶段 5 已于 2026-10-13 经用户「批准」确认,原生逐项实施;U1–U3 源码与自检在 Dev 任务分支推进,U4 待启用记录及规则已准备,U5 平台所有者操作与 U6 真实三任务 CI 试行仍 NOT_RUN。实际对象、证据和进度回链 Dev 任务卡,不把本索引当第二进度权威。 - [最终验证与合入调度实施计划 r1](2026-10-13-merge-queue-implementation-plan.md):阶段 5 已于 2026-10-13 经用户「批准」确认,原生逐项实施;U1–U3 源码与自检在 Dev 任务分支推进,U4 待启用记录及规则已准备,U5 平台所有者操作与 U6 真实三任务 CI 试行仍 NOT_RUN。实际对象、证据和进度回链 Dev 任务卡,不把本索引当第二进度权威。
- [RDM 设置归属、成员、文档职责与权限矩阵完善增量方案 r1](2026-10-13-rdm-settings-members-duties-perms-increment.md):承接总案 U3/U4/U6(衔接 U5)的完整增量——设置作用域与受管项、可搜索人员选择器、文档清单+职责分配、单成员/多人权限矩阵与三态项目覆盖;含服务端一致性修复(职责目标成员校验推翻 G1-5 旧裁定、职责变更与审签失效原子化)与 P1–P8 工作包。**2026-10-13 用户评审通过并授权实施**(两批推进;正式验收与清理回收保留人工节点);P1 契约随本稿固定,P2 基座契约扩展按总案发版顺序排队。 - [RDM 设置归属、成员、文档职责与权限矩阵完善增量方案 r1](2026-10-13-rdm-settings-members-duties-perms-increment.md):承接总案 U3/U4/U6(衔接 U5)的完整增量——设置作用域与受管项、可搜索人员选择器、单成员/多人权限矩阵与三态项目覆盖;含服务端一致性修复。**2026-10-13 用户评审通过并授权实施**。第四节及 P5/P7 的文档职责页交互已被下方 r2 取代,其余部分继续有效。
## 2026-10-15 规划补充
- [文档职责矩阵整改 r2](2026-10-15-rdm-duty-matrix-rework.md):项目设置只分配已有文档的编制、审核、批准;按人员、按文档、成员×文档三视图共享一份草稿。章节级新指派停用,有歧义的旧章节职责逐文档确认。2026-10-15 按实施方案执行;部署与真实账号验收未授权。收录不把其余未完成增量自动标成已验收。
## 2026-10-12 规划补充 ## 2026-10-12 规划补充