diff --git a/.task/fix-pal-component-delivery-pins.md b/.task/fix-pal-component-delivery-pins.md new file mode 100644 index 00000000..1d873398 --- /dev/null +++ b/.task/fix-pal-component-delivery-pins.md @@ -0,0 +1,202 @@ +# fix/pal-component-delivery-pins 任务卡 + +任务主记录:;状态:进行中;owner:weichen + +- 权威仓:ssh://git@192.168.3.2:2222/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= a496ea0f0249b2b412354677ef97612ccd692d25 +- 工作区:/home/weichen/projects/Agent-System-Dev-wt-fix-pal-component-delivery-pins(worktree);分支:fix/pal-component-delivery-pins +- 分支类型:standalone;root_target:main;immediate_target:main;accepting_requirements:false +- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=5bd167003a0df76cc4ce5252be7b24ce28dbcc9614493a978e3e1b7a8e864dcc;triage_receipt=/tmp/pal-pins-triage.json;receipt_sha256=0f53fa4aab99a9d10ebac3f76c9be1308b4b84b1066a59230f1497bff05e917c + +- 授权与交付终点:<本次允许的动作与终点;未授权事项写明> +- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进) +- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md) +- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入) +- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位) + +## 目标与非目标 + +- 预期结果:把 PR #634 已合入 Dev main、但未进入交付件的组件内容补齐——Backend 与 RDM 各自合入 main,Dev 推进对应 pin,使 U1–U5 真正进入可部署制品。 +- 已核实基线(2026-10-21 建任务时点):Dev main 钉 `modules/backend=dfb31da`(不含生命周期内容)、`modules/frontend=113103f`(即 U6 交付头,随 Dev 交付但未入 Frontend main)、RDM pin `c6304224`(2026-10-13,早于角色权威切到 Backend 的 #454)。上述取值均为时点快照,精确落后量不作依据。 +- 非目标:不改 U1–U5 的规格语义;不部署(C16 另起,需 pin 就位后进行);不处理 `feature/rdm-two-trees-followup`(PR #635)的范围。 + +## 决策记录 + +- **D1(role cap 是否受 R3 carve-out 约束)——用户裁决 2026-10-21,选 A1。** RDM 的 `evalPerm` 有两层不同的覆盖:role cap(`switch` 的 `RoleReasonCapDenied` 与 legacy 的 `!defined || !capAllowed`)与项目覆盖层(末尾 `ps.OverrideFor`)。计划 R3 原文只约束后者(原文用词为 per-action member/project **overrides**)。 + - 裁决内容:**只让项目覆盖层不再撤销创建者权威本身授予的权限**;role cap 维持现状、继续阻断创建者。覆盖层的「授予」方向也不变。平台上限、账号停用、职位停用、Linked.Conflicts、归档/结项状态守卫、对非创建者的拒绝全部不变。 + - 实现:`internal/rdmapp/perms_api.go` 的 `evalPerm` 末尾,`creatorGranted := base && relation == perms.RoleOwner && p.CreatedBy == actor && isManagementAction(act)`;`if set && (override || !creatorGranted)`。 + - 该裁决曾以「Decision A1」写进 `plugins/rdm/system_projects_test.go` 的注释,但当时未在任何仓内决策记录中留痕——这是本卡补记的原因。 +- **D2(archive/restore 授权门不得被 R3 收敛吞掉)——由计划原文直接决定,非新决策。** U2 第 219 行:「Do not change archive/restore, which remains a separate lifecycle.」故 `canManageProject` 按 act 分流:`ActProjectArchive` 沿用 main 的「创建者或显式授权」门,其余走 R3 的 `requireProjectManagement`。 +- **D3(ArchivedAt 守卫必须还原,ClosedAt 不设)——由计划原文与 R6 共同决定。** 归档属 Out of scope,main 的只读守卫必须恢复(含创建者);结项属 U4/R6,R6 明文「The creator can still use project-management actions needed to reopen or administer the project.」,故 ClosedAt 刻意不设守卫。 +- **D4(平台上限对创建者同样生效)——由领域规则与 SR-G9 决定。** 「system.grants 与平台上限写入门禁保持 system.permissions.manage,不得因 R13 放宽」;`perms.SetCap` 注释「所有业务主体均受约束」;SR-G9 创建者「仍受有效角色与平台 cap」。故 `requireProjectManagement` 带 act 参数并恢复 `CapAllows`。 + +## Agent 实施收据 + +路由与 fail-stop 规则见根目录 AGENT-EXECUTION.md 与 policy/delivery.md;每次尝试一行,原始日志留在源码外收据路径。 + +| 单元 ID | 预期范围 | 配置摘要 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 | +|---|---|---|---|---|---|---|---|---|---|---| +| dev-advance-rdm-and-dm-pins | `tests/integration/lifecycle/rdm.pin` + `deps/development-manager` 指针 | AGENT-EXECUTION digest ccceb3bf | implementation | cursor→agy→pi-glm→pi→codex | 1 | cursor(session not-observable) | success | b5a0abf(refs/agent-exec…),已 apply 快进入分支 | never | /tmp/dev-pin-run.json | + +## 同步记录 + +| 节点 | sync_base_sha | tested_head_sha | checked_at | +|---|---|---|---| +| 启动 | a496ea0f0249b2b412354677ef97612ccd692d25 | a496ea0f0249b2b412354677ef97612ccd692d25 | 2026-10-21T03:47:24Z | + +## 证据(Evidence) + + +| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) | +|---|---|---|---|---|---| + +## 组件交付结果(2026-10-21) + +| 组件 | 状态 | 依据 | +|---|---|---| +| Backend | ✅ 已进 main(`7158bea`) | 生命周期工作已由 PR #234 合入;Dev 的 backend pin `f084d10` 已含该提交(他人推进,已核实祖先关系) | +| RDM | ✅ 已进 main(`bc8db88`) | PR #460,五轮独立 Review 终判 PASS,CI 双作业绿 | +| Frontend | ✅ 随 Dev 交付 | pin `113103f` 即 U6 交付头 | + +### 交付前的状态 + +**可核事实**:Dev 的门禁从未消费交付分支。`Makefile` 的 `test` 目标只测**各组件钉住的检出**(`test-backend` 测 `modules/backend` 的 pin),`rdm.pin` 仅被 `test-lifecycle` / `test-regulations-kb` 消费,而真实生命周期门禁需要真实 PostgreSQL 与 RDM 源仓。因此「Dev 门禁全绿」与「交付分支本身有缺陷」可以同时成立。 + +**SELF 观测(非本仓可复核,2026-10-21 时点)**:我在组件仓的临时 worktree 上检出交付分支顶端提交并运行其自带测试,观察到失败—— +- Backend `bd640df`:单跑 `TestConversationWorkErrorCategorization` 失败,同一用例在 `origin/main` 通过。 +- RDM `301cf56`:全量 `go test ./...` 有 4 个用例失败,同一运行中 `internal/rdmapp` 绿、`plugins/rdm` 红。 + +这两个观测随后被下面的六项缺陷所印证与闭合。若需复核,请在对应组件仓按上述提交检出并运行其自带测试;本仓无法复现,故**不得把本段当作 GATE 证据引用**。 + +**勘误**:提交 `537bf66` 的信息中写有「red-at-tip finding」,该表述把上述 SELF 观测说成了既定发现;本条以本节为准。`537bf66` 另写的「差 27 文件/1379 行」「落后 RDM main 918 提交」为当时点的粗略量测,与任何自然口径都不精确对应,现予作废,不作为依据。 + +### 修复过程中发现并闭合的授权缺陷 + +| 编号 | 内容 | 性质 | +|---|---|---| +| B1 | `canManageProject` 被整体替换,archive/restore 授权门被吞;两个 main 测试被反向改写成「获授者也拒绝」并注释「新旧一致」 | 越界 + 伪装成延续 | +| B2 | 已归档项目只读守卫丢失,改名/成员增删/override 全放行 | 越界(计划禁止改 archive) | +| B3 | **平台上限失效**:管理员 `SetCap` 关闭后创建者管理写入全部成功,而 member add 被拒、remove 放行 | **安全天花板被绕过** | +| F1 | 已结项项目上命令面 member-add 拒绝创建者,直接 API 却放行 | 自相矛盾(违反 R6) | +| F2 | role cap 只挡 add 不挡 remove/suspend/reactivate | 口径不一致 | +| F3 | render-profile 族允许非创建者凭 owner 标签或显式覆盖行使 `project.settings` | 违反 R3 | + +结构根因:R3 把管理路径从 `evalPerm` 迁到 `requireProjectManagement` 时**逐项丢门**(先丢归档,再丢平台上限)。最终形态是两个独立维度——`managementLifecycleDenial`(归档拒绝、结项按 R6 不设)与 `managementCeilingDenial`(平台上限、role cap、联动冲突、停用、有效访问)。 + +### 顺带落地的治理修复 + +Development-Manager PR #32(`2c2e372`)为 `admit` 增加「权威基线内容认可」:暂存路径若与权威基线**逐字节相同**即免 transport。已实测生效——原本 65 个暂存路径全被拒,修复后仅 5 个需 transport,其余 60 个自动认可;最终以空合并提交记录祖先关系时 `admit: ok`,全程无 transport 妥协。 + +## 结果与验证 + +- 结果:RDM pin 与 dm pin 均已推进并推送(PR #682);**CI `test-pg` 红,当前 blocked。** + +### test-pg 失败(唯一阻塞) + +`svc-realcombo` success、`test` 通过,`test-pg` 在「Clone Agent-System-RDM with nested pins」步骤失败:组合二进制编译报 `missing go.sum entry for module providing package agent-document-renderer/{render,markdown,model,profile,profiles,word}`。 + +已核实的成因:RDM `bc8db88` 的 `go.mod` 用本地路径 replace `agent-document-renderer => pins/agent-document-renderer`,因此其 `go.sum` 中**没有任何** agent-document-renderer 条目(实测计数 0)。Dev 侧构建会把 RDM 的 backend replace 重写到 `../backend`(即 Dev 的 `modules/backend`,当前 `f084d10`),而该 backend 直接 import document-renderer 的上述包,于是 RDM 的模块图无法提供对应条目。另注:RDM 自身钉的 backend 是 `bd640df`,与 Dev 的 `f084d10` 已分叉。 + +这正是「只有真实组合门禁才能发现」的那一类不兼容——`make test` 全绿(exit 0)也照样漏掉。 + +### 根因(已定位,非制品缺陷) + +同一份 RDM 在本地跑 `scripts/build-product.sh` **成功**(产物 `9ea3fcc8cef0df8a`),说明 RDM 制品无缺陷。报错只出现在 CI,原因是 **RDM 的 pins 布局从 4 个变成 6 个**(新增 `pins/agent-document-renderer`、`pins/agent-system-kb-regulations`): + +| 提交 | pins 数量 | +|---|---| +| `legacy_sha` 72bb1fec | 4 | +| 旧 `prev_sha` 3484ec2 | 4 | +| 旧 `sha` c6304224 | 4 | +| 新 `sha` bc8db88 | **6** | +| bc8db88 的第一父 59b3624 | 6 | + +CI 步骤逐个检出并构建三个 pin,依赖三者布局一致。新 `sha` 是 6-pin,而 `prev_sha`/`legacy_sha` 仍是 4-pin,布局不再一致;本次 fail-loud 断言直接点名:`rdm pin c6304224 的 pins/agent-system-frontend 未落地:缺少 go.mod`。 + +我先前把 `prev_sha` 设成旧 `sha`(c6304224)是错的——它是 4-pin 布局,且我在单元包与注释里都未核对布局一致性,这是本次返工的直接原因。 + +### 进展(run 4714 / job 7830) + +CI 物化修复**已生效**:三个 pin 全部通过 fail-loud 断言并各自构建成功,`missing go.sum entry` 不再出现。`svc-realcombo` 与 `test` 均绿。 + +失败因此推进到下一道门禁——真实组合门禁 `make test-lifecycle`,三个用例红: + +| 用例 | 失败点 | +|---|---| +| `test_prev_and_current_pin_switch_and_back` | `svc.sh` 的 `git fetch(独立 RDM 源仓:rdm)` 退出 1 | +| `test_mixed_batch_updates_forward_and_deploy_reverses` | 同上,更新检测失败 | +| `test_phase_interrupt_reconciles_on_real_artifacts` | 同上,退出码 86 | + +即:CI 里 `rdm/` 是 `--depth=1` 克隆 + 对三个 pin 的 `--depth=200` 取,`svc.sh` 物化 RDM 提交时要对该源仓做 `git fetch`,在浅克隆/对象边界下失败。这属于 `scripts/svc.sh` 的 RDM 源仓取用方式与 CI 浅克隆之间的新问题,**不在本 PR 的 pin 推进范围内**,且我未继续深挖。 + +### 我的两处失误(均已修正) + +1. 选 `prev_sha` 时未核对 pins 布局一致性,把 4-pin 的旧 sha 当成 prev(已改为 6-pin 区间内最老的提交)。 +2. CI 断言写成「每个 pin 必须有 go.mod」——pin 集合混有 Go 仓与非 Go 仓(前端仓根无 go.mod),产生假失败(已改为「HEAD 等于 gitlink 且工作树有已跟踪文件」)。 + +### 未决(需决策) + +- `prev_sha` 应取 bc8db88 的第一父 `59b3624`(6-pin、与新 sha 布局一致、紧邻交付);但这样 `prev_sha` 与 `sha` 仅隔一个合并,生命周期套件的「来回部署身份稳定性」覆盖力度下降。 +- `legacy_sha` 必须保持「无身份」语义,因而必然是老提交(4-pin)。构建循环是否应继续要求三个 pin 都可构建?若否,则该步骤对 `legacy_sha` 应放宽断言或单独处理——这属于 CI 步骤语义的设计取舍,不宜由实现侧默定。 + + +### 其余验证 + +- PASS|pin 取值自洽:`sha=bc8db88` 含交付内容(`managementCeilingDenial`、`managementLifecycleDenial`、`txProjectManaged`、`MemberAddResolveFailure` 均在其树内);`prev_sha` 为原 pin,供生命周期套件来回部署;`legacy_sha` 未动。 +- PASS|`make test` 在 `98d794e` 上 exit 0、无 FAIL。 +- PASS|独立 Review 首轮判 FAIL(任务卡把会话内观测写成既定结论),已按其要求改写为可核表述 + SELF 观测 + 勘误,复审通过项见上文。 +- NOT_RUN|精确 HEAD 三作业 GATE(`test-pg` 红)。本地 SELF 不可替代,不得合入。 + + +- 结果: +- 验证:<结论摘要 PASS/FAIL/SKIP/NOT_RUN 逐项;逐条证据由 make evidence 写入上方证据表> +- 影响与剩余项: + +## 合入与清理 + +- Review 记录:NOT_RUN(审阅智能体/平台身份、base/head、结论、问题闭合及重放依据) +- 冲突记录:NOT_RUN(最新目标同步、冲突处置、组合兼容核验及复审/补测) +- CI 记录:NOT_RUN(当前 HEAD 完整 SHA、全部必需检查、运行链接、执行身份及 GATE 结果) +- 合入记录:NOT_RUN(交付授权范围、PR、被核验 HEAD、合入 SHA、目标分支及内容核验) +- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置) + + +```json +{ + "summary_schema": 1, + "source": "SELF", + "timestamp": "2026-10-21T03:46:26.935822+00:00", + "command": "make precheck", + "exit_code": 0, + "cwd": "/home/weichen/projects/Agent-System-Dev", + "before_head": "a496ea0f0249b2b412354677ef97612ccd692d25", + "after_head": "a496ea0f0249b2b412354677ef97612ccd692d25", + "branch": "main", + "target_branch": "main", + "target_head": "a496ea0f0249b2b412354677ef97612ccd692d25", + "root_target": "main", + "immediate_target": "main", + "before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "output_tail": [ + "make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev'", + "[repo] branch=main head=a496ea0f02", + "[remote] origin/main=a496ea0f02 ahead=0 behind=0", + "[tree] clean submodules_drift=0 uninit=0", + "[worktrees] linked=5", + "[cards] 已合入未闭合任务卡:feature-project-access-lifecycle.md——make task-close 回填归档(主检出运行)", + "[initiatives] local cards (not authoritative): none", + "[hooks] core.hooksPath=scripts/hooks(pre-commit/post-merge 实际接线)", + "[facts] policy/facts.md 6 条事实均在有效期内", + "[required-reading] core/baseline.md, workflows/delivery.md §1, policy/delivery.md", + "[R0] a496ea0f02(完整:a496ea0f0249b2b412354677ef97612ccd692d25)", + "[worktree] before-sync: recursive component checks passed", + "[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch", + "make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev'" + ], + "output_sha256": "d63eb6dfcf96743449b73edabd63a126308f731b7528b1e249ec5a7f4ce8aae4", + "receipt_sha256": "b659e67e444244c0f70ec7f71c89044666ba229581bab6ccca200bbf491cd24c", + "receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/b659e67e444244c0f70ec7f71c89044666ba229581bab6ccca200bbf491cd24c.json" +} +``` +| 同步(记录前对象) | ccb6dfaa9cdf7e69eb15d7df024dee55f37b8df1 | 2af80d6a24bcde0a6da1f091acdb25c7e1e9a1f4 | 2026-10-21T13:32:30Z | +| 同步(记录前对象) | a736d5a420370cff052bd946f6d6397d4c354547 | e8dbbe001ae12048217c0a763ab7699d183f5b1f | 2026-10-21T13:57:35Z | diff --git a/deps/agent-command b/deps/agent-command index fe7987dc..4f583ca3 160000 --- a/deps/agent-command +++ b/deps/agent-command @@ -1 +1 @@ -Subproject commit fe7987dc03e96d59705a547e2099cdea13affcd2 +Subproject commit 4f583ca3eeeb07a56a714c5086de84dcd6ad2980 diff --git a/deps/agent-intent b/deps/agent-intent index 765a7e71..651a2e1e 160000 --- a/deps/agent-intent +++ b/deps/agent-intent @@ -1 +1 @@ -Subproject commit 765a7e717737dcbe0d684ece3b7e2b38923c53d5 +Subproject commit 651a2e1e03c4326888ef9f742ce592140ae30ab8 diff --git a/deps/agent-native b/deps/agent-native index ac91b843..2fc66be6 160000 --- a/deps/agent-native +++ b/deps/agent-native @@ -1 +1 @@ -Subproject commit ac91b8436ea9f5c80861bb4b1b1534ede0b9918f +Subproject commit 2fc66be65201232ea38ba64d457efad5565d869d diff --git a/deps/agent-squad b/deps/agent-squad index 0f1daa8b..c7121bda 160000 --- a/deps/agent-squad +++ b/deps/agent-squad @@ -1 +1 @@ -Subproject commit 0f1daa8b89b158cc4a0fe85d33050f48cedf129a +Subproject commit c7121bda2a681dc46078350f7929e56e142db57f diff --git a/deps/development-manager b/deps/development-manager index 1e5ee55a..2c2e3725 160000 --- a/deps/development-manager +++ b/deps/development-manager @@ -1 +1 @@ -Subproject commit 1e5ee55a2881dc9ed210ced48338c4d75697aa9c +Subproject commit 2c2e37255807ce94c945759925d6361e72977807 diff --git a/modules/backend b/modules/backend index b6141800..f084d10a 160000 --- a/modules/backend +++ b/modules/backend @@ -1 +1 @@ -Subproject commit b6141800cc8b4239ea03d4f1e7edc5486fc31116 +Subproject commit f084d10aa5ea2e4ad2ab4e6eb1268d3e83c6e991 diff --git a/modules/documents b/modules/documents index 75e43e1a..2e9c3bc1 160000 --- a/modules/documents +++ b/modules/documents @@ -1 +1 @@ -Subproject commit 75e43e1adf03f7ec64e6eb5c183715bdde08b468 +Subproject commit 2e9c3bc1d8be6079832dcc8a26ac1a0c01826e90 diff --git a/tests/integration/lifecycle/rdm.pin b/tests/integration/lifecycle/rdm.pin index 0469f7b1..03c178f7 100644 --- a/tests/integration/lifecycle/rdm.pin +++ b/tests/integration/lifecycle/rdm.pin @@ -1,6 +1,11 @@ # RDM 制品钉扎。三行都是 40 位 hex。升级走 PR,不在 CI 里执行候选文件。 -# legacy 没有 version --json。prev 是身份能力合入(#291)。sha 与 prev 钉同一 -# backend(0f192a4),schema 兼容,但产品树不同,切换能在 release 名上看到。 -sha=c6304224f995747ea3ffcb8d0e81f3ad46a96546 -prev_sha=3484ec225b0087a9065466ed436ea97a768691ef +# sha:生命周期套件的目标版本(6-pin 布局)。 +# prev_sha:来回部署身份稳定性测试的起点。选取受两条硬约束——与 sha 的 pins 布局一致, +# 且两者之间无跨 schema 迁移(scripts/svc.sh 的 schema 兼容闸会在停旧服务前拒绝不兼容切换)—— +# 而非追求版本跨度。取 sha 在 RDM 主线上的第一父提交(交付合入前的 main);代价是 prev 与 sha +# 仅隔一次合并,版本跨度小,往返部署覆盖的版本距离有限。 +# legacy_sha:承载「无身份」语义(没有 version --json),必然早于 6-pin 布局。 +# 三者的 pins 布局可能不同;CI 按每个 pin 自身的 gitlink 清单物化并逐个断言,不要求布局统一。 +sha=bc8db886606e88201e7f7210a1357d22dc84124b +prev_sha=59b3624325fe132ef92ccee83dd9ddc6c3fcc521 legacy_sha=72bb1fec79d64c2af5e49416640712320816c3b4