merge: candidate member-permissions-doc-land-2026-09-26 into dev

This commit is contained in:
weichen
2026-09-25 20:22:16 +00:00
2 changed files with 231 additions and 2 deletions
@@ -0,0 +1,212 @@
# 项目成员权限总览(对话 / 执行任务 / 补充信息 / 文档编制与修改)
> **文档定位**:本文是对"项目成员在各协作动作中拥有什么权限"的**只读梳理与整合**,权威实现以代码为准(每节标注 `文件:行号`)。
> **口径来源**:系统角色与能力矩阵见 [authz/fallback.go](../../internal/authz/fallback.go);三权与阶段判定见 [deny-only-submit 经验](../ops/lessons/2026-09-24-deny-only-submit.md) 与 [非编制成员访问整改](../audit/2026-09-24-non-author-member-access.md);路由负例见 [authorization-matrix-v3-full](../audit/authorization-matrix-v3-full.md);能力成熟度见 [FEATURE-MATRIX `iam-authz` / `workflow-gov` / `docgov` 行](../status/FEATURE-MATRIX.md)。
> **本文不新增第二套门禁**,也不改变上述权威结论;仅把它们按"成员能做什么"重新组织,供协作与验收对照。
> **状态**:research/overview(可审产物,不含实施授权)。
---
## 一、三层权限模型(先厘清概念,再看动作)
系统对"谁能做什么"由三个**正交**维度共同决定,任何一个单独看都会误判:
| 层 | 取值 | 权威来源 | 决定什么 |
|---|---|---|---|
| **系统角色** | `role-admin` / `role-director` / `role-tech-lead` / `role-engineer` / `role-guest` | `users.role_id` + DB `user_role_bindings` → `system_role_permissions`;无 DB 时回落 [FallbackCapabilitiesByRoleID](../../internal/authz/fallback.go#L3) | 系统级能力(建项目、指派负责人、管理台读写、成员管理权限键) |
| **项目成员角色** | `owner` / `member` / `viewer` | `project_members.project_role`(+ 创建人 `projects.creator_user_id`);[authorizer.go](../../internal/authz/authorizer.go#L22) | 能否进入某项目、能否管成员、能否终止他人任务 |
| **文档职责(三权)** | `author`(编制)/ `reviewer`(审核)/ `approver`(批准) | `project_members.document_duty` 为**权威指派**,落到 `document_records` 三槽位;[docduty/resolve.go](../../internal/docduty/resolve.go#L106) | 能否对该文档送审 / 审核 / 批准 |
`★ Insight ─────────────────────────────────────`
**三层是分离而非叠加的**。Phase 0 术语冻结明确:`author/reviewer/approver` 是"文档职责",绝不能写进 `project_role`([authz/service_test.go](../../internal/authz/service_test.go#L82) 有回归拒绝 `project_role="author"`)。这意味着"是 owner"和"是该文档的 reviewer"是两回事——owner 若未被指派为某文档 reviewer,也不能替 reviewer 点"审核通过"。
`─────────────────────────────────────`
### 1.1 系统角色的能力矩阵(服务端 fallback,与 IAM seed 对齐)
| capability 键 | admin | director | tech-lead | engineer | guest |
|---|:--:|:--:|:--:|:--:|:--:|
| `project:create` 建项目 | ✓ | ✓ | ✓ | | |
| `project:assign_lead` 指派文档负责人 | ✓ | ✓ | ✓ | | |
| `project:manage_members` 管理项目成员 | ✓(含 `perm:manage`) | | | | |
| `perm:manage` 系统权限管理(全量) | ✓ | | | | |
| `system:overview`/`kb:read`/`features:read`/`settings:read`/`audit:read` | ✓ | | | | |
| `system:settings:write` 改系统设置 | ✓ | | | | |
| `workflow:config_visibility` / `doc:override_visibility`(仅登记,见 §6.2) | ✓ | ✓ | ✓ | | |
| `doc:export` 导出 | ✓ | ✓ | ✓ | ✓ | ✓ |
| `workflow:view_all` | ✓ | ✓ | ✓ | ✓ | |
> 数据源:[fallback.go](../../internal/authz/fallback.go#L3)、[roles.go defaultSystemRoles](../../internal/authz/roles.go#L46)。`role-guest` 只有 `doc:export`,是"最小权限查阅"角色。
### 1.2 项目成员角色:owner 与非 owner 的真实差异
**关键事实**:服务端读取项目内绝大多数业务对象时,只判定"是不是 active 成员",**不区分 `member` 与 `viewer`**——[RequireProjectAccess](../../internal/authz/authorizer.go#L128) → [IsProjectMember](../../internal/authz/authorizer.go#L107) 的 SQL 条件只有 `status='active'` 或"是创建人"。
真正区分的是 **owner/creator** 这一档:
| 能力 | 判定函数 | 谁满足 |
|---|---|---|
| 进入项目 / 读项目对象 | `IsProjectMember` | owner、member、viewer、creator 全部 |
| 管理成员(增删改/移出) | [CanManageProjectMembers](../../internal/authz/service.go#L115) | owner 或 creator、系统管理员、持 `project:manage_members` |
| 终止 / 续跑他人任务 run | [assertTaskRunAccess](../../internal/server/task_run_auth.go#L16) 的 cancel/resume | run 发起人本人 **或 project owner**(member/viewer 不行) |
| 改派文档职责(PATCH duties) | [duty_reassign_handlers.go](../../internal/server/duty_reassign_handlers.go#L29) | creator 或持 `project:assign_lead` |
| 工作流规划/激活/推进/终止 | 各 `projectinstance` 服务 `!isCreator → ErrForbiddenNotCreator` | **仅项目创建人** |
> 也就是说:`viewer` 在**服务端**能读、能进对话、能发起自由查询;把"查阅者"降为只读主要靠**前端隐藏写按钮**(见 §5.4)。文档若要严格区分 member/viewer 的服务端写门禁,属尚未实施的缺口(如实标注,见 §6.1)。
---
## 二、请求进入系统的第一道闸:认证与路由分层
`★ Insight ─────────────────────────────────────`
路由不是按"权限组"分组挂载的,而是**全部 `/api/v1/*` 统一过 `authMiddleware` 要求登录**,成员/管理员/职责判定下沉到每个 handler。这样"公开面"极小且可枚举,代价是每个 handler 必须自觉调门禁函数——所以本仓用负例测试(authorization-matrix-v3)逐路由兜底。
`─────────────────────────────────────`
- **中间件链**:`cors → accessLog → bodyLimit → authMiddleware → mux`([server.go:371](../../internal/server/server.go#L371))。
- **匿名可访问**([auth_middleware.go](../../internal/server/auth_middleware.go) `isPublicRoute`):`/health`、`/ready`、`/api/v1/vault/status`、`POST /auth/login`、`POST /auth/register`、`GET /auth/public-config`,以及所有非 `/api/`(SPA 静态页)。
- **principal 唯一可信**:登录主体只来自 `Bearer`/`X-Session-Token` → `principalFromContext`;**禁止** `X-User-ID` 头或 body `user_id` 覆盖(Phase 0 红线)。handler 一律 `req.UserID = user.ID`,不信请求体。
- **fail-closed**:生产/DB 模式下授权依赖异常默认拒绝([failClosedAuthz](../../internal/server/auth_helpers.go#L15));dev 内存模式才允许 legacy fallback。
三级门禁函数:`requireAuthenticatedUser`(401)→ `requireProjectAccess`(非成员 403 / 不存在 404,管理员直通)→ `requireAdmin` / `requireSystemPermission`(管理员判定 [IsSystemAdmin](../../internal/authz/service.go#L107))。
---
## 三、四类核心协作动作的权限矩阵
这是用户最关心的部分,逐动作给出"谁可以 + 代码位置"。
### 3.1 发起对话 / 进入项目会话
| 情形 | 判定 | 结论 |
|---|---|---|
| 账号名下无任何项目 | [enforceChatRequiresProject](../../internal/server/stage_access_helpers.go) | **禁止对话**,返回 `ERR_NO_PROJECT` |
| 会话绑定了项目 | [enforceChatProjectAccess](../../internal/server/stage_access_helpers.go) → `RequireProjectAccess` | **必须是该项目 active 成员**(owner/member/viewer 均可,管理员放行);SSE 在 Flush 前拒绝 |
| 成员进入后的自由对话 | [allowFreeLaneChatInitiation](../../internal/server/free_lane.go#L41) | **成员确认后总是放行发起**("自由车道",见 §3.2) |
| 读他人会话/消息 | [assertSessionOwnedByUser](../../internal/server/auth_helpers.go#L79)、[chatlog authorize](../../internal/app/chatflow/chatlog.go) | `owner_id != 当前用户` → 403,**读不到别人的私有会话** |
| 看同项目他人阶段消息 | [MessageRecordVisible](../../internal/projectinstance/message_scope.go) | 按阶段作用域过滤,跨阶段/私有消息对同项目其他成员不可见 |
**要点**:项目成员(含 viewer)都能进项目对话并发消息;会话的**所有权隔离**保证看不到别人的个人会话;阶段消息可见性另有一层作用域收窄。
### 3.2 自由协作通道(chat / 上传 / 总结 / 查询 / 影响分析 / 补充)
来自 [free-collab-claim-notify-design §3](2026-09-24-free-collab-claim-notify-design.md) + [free_lane.go](../../internal/server/free_lane.go#L12):
- **准入 = 项目成员**(`RequireProjectAccess`),**不查阶段 / duty / 实例状态**。
- **适用动作**:`chat`、`help`、各类 `query`、`impact.analyze`、`supplement`、材料上传、总结——共 14 个成员级自由意图键([freeLaneIntentKeys](../../internal/server/free_lane.go#L14))。
- **红线**:自由车道只放开"发起与查询",**受控文档的写动作仍走 duty + 阶段 + 认领**(见 §3.4)。
### 3.3 执行任务 / 阶段动作
| 动作 | 端点 | 权限 |
|---|---|---|
| 创建/运行 task run | `POST /api/v1/tasks/run*`、`/projects/{id}/workflows/{key}/run` | 需 `RequireProjectAccess`(成员);run 走 [CheckDocTaskAccess(run)](../../internal/projectinstance/duty_action.go#L48) → **成员级放行**;幂等键归属校验 |
| 查看 run / 事件流 | `GET /tasks/runs/{id}`、`/events` | admin ∥ run 发起人 ∥ project owner ∥ **任意项目成员**([view](../../internal/server/task_run_auth.go#L35)) |
| 取消 / 续跑 run | `POST /tasks/runs/{id}/cancel`、`/resume` | 仅 run 发起人 **∥ project owner**([cancel/resume](../../internal/server/task_run_auth.go#L46)),普通 member/viewer 不可终止他人任务 |
| 阶段推进 / 激活 / 终止实例 | `/workflow-instances/{id}/stages/{stage}/advance`、`/terminate`、activate | **仅项目创建人**(`isCreator`);推进还需门禁就绪(`CanAdvance`,未就绪 409) |
### 3.4 文档的发起编制、修改与三权审批
这是权限最细的部分。受控文档动作统一走 [CheckDocTaskAccess](../../internal/projectinstance/document_access.go#L35) → [classifyAccess](../../internal/projectinstance/duty_action.go#L48),遵循 **`deny_only_submit`** 原则:
| 动作 | 谁能做 | 拒绝码 |
|---|---|---|
| **view** 读 | 任意项目成员(view 豁免阶段收窄,[TaskKeyVisible](../../internal/projectinstance/stage_access.go#L119));正文读还要 `authorizeControlledRead` | 无项目归属文档仅管理员 |
| **edit / run** 编辑·跑 | **任意项目成员**(deny_only_submit:run/edit 降为成员级) | 实例未激活 → 202-blocked |
| **submit** 提交送审 | 仅该文档 **author** | `DOC_DUTY_FORBIDDEN` |
| **review** 审核 | 仅该文档 **reviewer** | `DOC_DUTY_FORBIDDEN` |
| **approve** 批准 | 仅该文档 **approver** | `DOC_DUTY_FORBIDDEN` |
| DutyMode=**partial**(职责未配全) | 除 view 外全部拒绝 | `DOC_DUTY_FORBIDDEN` |
| DutyMode=**none**(未纳管审批) | run/edit 成员可,但 submit/review/approve 全拒 | `DOC_DUTY_NOT_MANAGED` |
`★ Insight ─────────────────────────────────────`
`deny_only_submit` 是 2026-09-24 整改的核心([lesson](../ops/lessons/2026-09-24-deny-only-submit.md)):过去把 run/edit 也绑到 author,导致"非编制成员连草稿/上传/总结都 403"。修正后**放写、只deny审批链**——编辑成员级,但 submit/review/approve 三者仍严格绑定各自单一职责,创建人也不隐式越权。角色一律 [resolveDocGovRole](../../internal/server/auth_helpers.go#L182) 服务端按三槽位解析,绝不信客户端自报。
`─────────────────────────────────────`
**认领与提案(非作者如何"发起修改")**:
- 非模板文档被 author 查看/编辑 → `author_claimed=true`([free_lane maybeAutoClaimOnView](../../internal/server/free_lane.go#L50) 开关);已认领文档,非作者不能直改,须走**变更提案** [handleDocGovProposeModification](../../internal/server/handlers_docgov.go)(成员即可提,triggeredBy 强制 `user:{id}`)。
- 提案由谁拍板:仅该文档 **author**([engine_proposal.go](../../internal/docgov/engine_proposal.go) 校验 `AuthorID`,否则 `ErrUnauthorizedActor`→403)。采纳后以作者身份 auto-apply。
- 前端"修改"意图只在 `isClaimed && currentDocRole==='author'` 才路由到 propose([useSendMessage](../../web/src/hooks/useSendMessage.ts))。
### 3.5 补充信息 → 影响 → 确认卡
来自 [supplement_impact_handlers.go](../../internal/server/supplement_impact_handlers.go) + supplementimpact 服务:
| 环节 | 权限 |
|---|---|
| 查看影响批次 | [userCanAccessSupplementBatch](../../internal/server/supplement_impact_handlers.go#L146) = **项目成员或创建人** |
| 确认 / 取消批次 | **仅发起该补充的 initiator 本人**([service.go](../../internal/supplementimpact/service.go) `ActorUserID != InitiatorUserID` → "only initiator" 403),且需 `nonce + digest + expected_revision` CAS;过期 410 |
| 已认领文档落地 | 以 initiator 身份走 `ProposeModification`(回到 §3.4 作者拍板);未认领 → 通知作者信息卡 |
### 3.6 自由私密文档(个人 → 项目共享)
来自 [freeform_doc_api.go](../../internal/server/freeform_doc_api.go) + [internal/freedoc](../../internal/freedoc/service_share.go):
- **创建**:需登录;建到 `my_private` 空间必须带 `project_id` 且过 `RequireProjectAccessOrAdmin`——非成员不能向该项目挂私密文档。
- **读**:`my_private` 仅 owner;`project_shared` 经项目共享后对成员可读。
- **改 / 共享 / 撤回 / 删除**:仅 `owner_user_id == 当前用户`([service_share.go](../../internal/freedoc/service_share.go)),越权 403"仅文档所有者可共享"。
---
## 四、管理台权限(/api/v1/admin/*)
两类 gate([admin_system_handlers.go](../../internal/server/admin_system_handlers.go)、[principal_context.go](../../internal/server/principal_context.go)):
1. **粗粒度 requireAdmin**(= `role-admin` ∥ `perm:manage`):用户 CRUD、改角色/状态、[重置密码](../../internal/server/auth_handlers.go)(一次性临时密码、不落日志)、角色/工作流/模板管理、workspace 运维。
2. **细粒度 system:\***(`/admin/system/{overview,kb,features,settings,audits}`):各自 `requireSystemPermission(PermSystem*)`。**Phase-2 现状**:系统管理员拥有全部 `system:*`,非管理员对 `system:*` **fail-closed 一律 false**([HasSystemPermission](../../internal/authz/service.go#L91))——细粒度键当前是"管理员 all-or-nothing",拆分留待后续。
**两个"任何登录用户可读"的例外**(立项选人/权限目录展示用):`GET /admin/permissions`、`GET /users/directory`(轻量 active 目录)。
---
## 五、前端如何消费权限(能力 ≠ 唯一权威,服务端才兜底)
`★ Insight ─────────────────────────────────────`
前端权限是**体验层**,不是安全边界。Phase 0 术语冻结已声明 `hasPermission`/localStorage 属 UI 层;真正的对象级授权永远在服务端 middleware。所以前端"隐藏按钮"被绕过也没关系——后端各 handler 仍会独立 403。
`─────────────────────────────────────`
1. **capabilities 获取与缓存**:登录成功后 `fetchMe()` 取 `/auth/me` 的 `capabilities`,存 localStorage 会话;启动时先用快照渲染再被 `/auth/me` 覆盖,**拉取失败即清会话登出**([useAuthenticatedWorkspaceSync](../../web/src/hooks/useAuthenticatedWorkspaceSync.ts))。
2. **fail-closed**:[rbac.ts hasPermission](../../web/src/engine/rbac.ts#L86) 在 `capabilities === undefined` 时**直接返回 false**;`perm:manage` 视为全权。
3. **按职责显示审批按钮**:[docGovActionVisibility.ts holdsDocDuty](../../web/src/lib/docGovActionVisibility.ts) 直接比对 userId 与 author/reviewer/approver;三槽全空(unmanaged)则不显示任何审批动作([DocGovActionBar](../../web/src/components/doc/DocGovActionBar.tsx))。
4. **成员/角色 UI**:[ProjectMembersModal](../../web/src/components/project/ProjectMembersModal.tsx) 添加下拉只给 `member`/`viewer`,owner/creator 归一不可降级([normalizeEditableRole](../../web/src/components/project/ProjectMembersModal.tsx));改职责下拉也只"项目成员/查阅者"。文档职责(author/reviewer/approver)通过 [UserProjectRightsModal](../../web/src/components/user/UserProjectRightsModal.tsx) 的 `resolveCurrentDocRole` 匹配,**未知身份 fail-closed 为 viewer**。
5. **对话/任务**:[filterProjectSessionsForUser](../../web/src/data/projectsStorage.ts) 让非成员完全看不到项目会话,exited 成员只读留痕(输入框禁用);task run 无独立前端权限 gate,靠"进不去会话/退出即禁用"间接限制。
---
## 六、边界与已知缺口(如实标注,勿当已实施)
1. **member vs viewer 服务端不区分写动作**:§1.2 所述,viewer 的"只读"目前主要由前端隐藏写按钮保证;服务端 `IsProjectMember` 对 member/viewer 一视同仁。若需服务端级"viewer 禁写",是待实施的授权收窄。
2. **`doc:override_visibility` / `workflow:config_visibility` 仅前端消费**:这两个 capability 在服务端只做登记(fallback + catalog),**没有 handler 用 `HasSystemPermission` 检查它们**;服务端实际文档可见性走 `ResolveStageAccess` 的 `TaskKeyVisible` + 实例快照。配置结果落入 plan/实例后由 `CheckDocTaskAccess` 执行,但"覆盖规则写鉴权"未在服务端单独 gate(见子代理调研结论)。
3. **`system:*` 细粒度未拆分绑定**:Phase-2 现状 admin all-or-nothing,非 admin fail-closed(§4)。
4. **无 DB 时 authz 降级**:`Authorizer.enabled()==false`(stub/dev 内存)时 `IsProjectMember` 返回 `userID>0` 即放行——**仅 dev/stub,生产 fail-closed**(Phase 0 已知 gap)。
---
## 七、权限决策函数清单(速查)
| 函数 | 文件 | 语义 |
|---|---|---|
| `isPublicRoute` | [auth_middleware.go](../../internal/server/auth_middleware.go) | 匿名白名单 |
| `requireAuthenticatedUser` / `requirePrincipal` | [auth_helpers.go](../../internal/server/auth_helpers.go) | 需登录(401) |
| `requireProjectAccess` | [auth_helpers.go:115](../../internal/server/auth_helpers.go#L115) | 项目成员可访问(管理员直通) |
| `requireDocGovDocAccess` | [auth_helpers.go:140](../../internal/server/auth_helpers.go#L140) | 受控文档 = 所属项目成员 |
| `resolveDocGovRole` | [auth_helpers.go:182](../../internal/server/auth_helpers.go#L182) | 服务端按三槽解析 author/reviewer/approver |
| `IsSystemAdmin` / `HasSystemPermission` / `CanManageProjectMembers` | [authz/service.go](../../internal/authz/service.go) | 系统权限核心判定 |
| `IsProjectMember` / `IsProjectOwner` / `RequireProjectAccess(OrAdmin)` | [authz/authorizer.go](../../internal/authz/authorizer.go) | 项目成员/owner 判定 |
| `UpsertProjectMemberSpec` / `SetProjectMemberStatus` | [authz/authorizer.go:314](../../internal/authz/authorizer.go#L314) | 成员 + 独占 duty 写入(advisory lock + 清槽);退出清槽 |
| `CheckDocTaskAccess` / `classifyAccess` | [document_access.go](../../internal/projectinstance/document_access.go) / [duty_action.go](../../internal/projectinstance/duty_action.go) | deny_only_submit 六动作矩阵 |
| `Resolve` / `HealBinding` | [docduty/resolve.go](../../internal/docduty/resolve.go) | 以 document_duty 为权威解析三权 |
| `ResolveStageAccess` / `TaskKeyVisible` | [stage_access.go](../../internal/projectinstance/stage_access.go) | 阶段级可见/可运行集 |
| `assertTaskRunAccess` | [task_run_auth.go](../../internal/server/task_run_auth.go) | run view/cancel/resume 门禁 |
| `authorizeDocRevision` | [document_revision_access.go](../../internal/server/document_revision_access.go#L61) | 版本账本读=成员;写=drafting 期 +(受控)author 本人或管理员 |
| `userCanAccessSupplementBatch` + `Decide` initiator | [supplement_impact_handlers.go](../../internal/server/supplement_impact_handlers.go) | 补充批次查看=成员,确认=仅 initiator |
| `freedoc.Share/Unshare/Delete` | [freedoc/service_share.go](../../internal/freedoc/service_share.go) | 私密文档 owner 独占 |
---
## 附:相关权威与证据
- [Phase 0 API 授权矩阵](../audit/2026-09-12-phase0-api-authz-matrix.md) · [Phase 1 IAM 实施计划](../remediation/2026-09-12-phase1-iam-authz-implementation-plan.md)
- [authorization-matrix-v3 全路由盘点](../audit/authorization-matrix-v3-full.md)
- [deny-only-submit 经验](../ops/lessons/2026-09-24-deny-only-submit.md) · [非编制成员访问整改](../audit/2026-09-24-non-author-member-access.md) · [重验报告](../test-reports/2026-09-24-non-author-member-access-test-report.md)
- [自由协作与认领设计](2026-09-24-free-collab-claim-notify-design.md)
- 能力成熟度:[FEATURE-MATRIX](../status/FEATURE-MATRIX.md) `iam-authz` / `workflow-gov` / `docgov` / `web-sysadmin` 行
+19 -2
View File
@@ -20,7 +20,7 @@
| 项 | 链接 |
|-----|------|
| 主报告(SSOT) | [../remediation/2026-09-22-t20-hardening-design.md](../remediation/2026-09-22-t20-hardening-design.md) |
| 主报告(SSOT) | [./2026-09-22-t20-hardening-design.md](./2026-09-22-t20-hardening-design.md) |
| 本目录迁址桩 | [2026-09-22-t20-hardening-design.md](2026-09-22-t20-hardening-design.md) |
| 任务 | [../ops/short-term/2026-09-22-t20-design-items.md](../ops/short-term/2026-09-22-t20-design-items.md) |
| 一句话总结 | XFF/锁拆分/statement_timeout/turn 补偿/shutdown/SSE POST/前端 generation/密码与 Cookie/容器与备份等设计决策;F5/I8 见 lowrisk 批 |
@@ -182,6 +182,22 @@
---
### 10. 项目成员权限总览
| 项 | 链接 |
|-----|------|
| 主文档 | [2026-09-24-member-permissions-overview.md](2026-09-24-member-permissions-overview.md) |
| 一句话总结 | 三层模型(系统角色 / 项目成员角色 / 文档三权)下,对话、执行任务、补充信息、文档编制与修改各动作的服务端+前端授权整合 |
**核心要点**:
- 三层**正交**:系统角色定能力、`project_role` 定入项目、`document_duty` 定送审/审核/批准;author/reviewer/approver 不得写进 `project_role`。
- 服务端读项目对象只看"是否 active 成员",**不区分 member/viewer**;真正差异在 owner/creator(管成员、终止他人任务、改派职责、激活/推进/终止实例)。
- 受控文档动作走 `deny_only_submit`:view/edit/run 成员级,submit/review/approve 绑单一职责,创建人不隐式越权。
- 前端 capabilities 仅体验层,`undefined` 即 fail-closed;硬拒绝永远在服务端 handler。
---
## 🏗️ 在整体架构中的位置
```
@@ -248,6 +264,7 @@
├── 2026-09-20-module-development-standards.md ← 开发者入口:契约 / 接口 / 故障隔离
├── 2026-09-20-stage-backtrack-and-impact-loop-design.md ← 阶段回溯与影响闭环
├── 2026-09-22-t20-hardening-design.md ← 迁址桩 → remediation T20 设计 SSOT
├── 2026-09-24-member-permissions-overview.md ← 项目成员权限总览(对话/任务/补充/文档三权)
.tmp/ ← 中间分析文件
├── intent-recognition/
@@ -272,7 +289,7 @@
| 文档 | 说明 |
|------|------|
| [../remediation/2026-09-22-t20-hardening-design.md](../remediation/2026-09-22-t20-hardening-design.md) | T20 W4 设计决策 SSOT(本目录仅留迁址桩);配套 [任务](../ops/short-term/2026-09-22-t20-design-items.md) |
| [./2026-09-22-t20-hardening-design.md](./2026-09-22-t20-hardening-design.md) | T20 W4 设计决策 SSOT(本目录仅留迁址桩);配套 [任务](../ops/short-term/2026-09-22-t20-design-items.md) |
## 🔗 相关资源