diff --git a/.evozeus-wrapper/docs/designs/2026-09-22-approved-publish-identity-routing.md b/.evozeus-wrapper/docs/designs/2026-09-22-approved-publish-identity-routing.md new file mode 100644 index 0000000..6e05d29 --- /dev/null +++ b/.evozeus-wrapper/docs/designs/2026-09-22-approved-publish-identity-routing.md @@ -0,0 +1,39 @@ +# Design Doc: Approved Publish Identity Routing + +## Related issue + +- Issue: #10, #11 +- What was unsatisfactory: The execution-card rules covered evidence boundaries and person-led task content, but approved publication did not define how to select a sender identity for an external group. A valid user profile could be denied while a bot identity in the same profile could publish successfully. +- Expected behavior: Before publishing, resolve the destination and probe the configured profile's user and bot capabilities. Prefer the user identity, fall back once to an in-group bot on the same profile when the user route is denied, and persist the actual sender and fallback reason in the receipt. + +## Optimization goal + +Make approved publication deterministic across private chats and external groups, while preserving the existing content approval, idempotency, and no-Base-mutation boundaries. + +## Direction + +Keep `METAINFLOW_FEISHU_PROFILE` as the only default profile. Add sender routing at the approved-publish boundary: user first, same-profile bot fallback when membership and readiness are confirmed, otherwise a blocked result with the exact reason. Keep the execution-card content contract person-led and require direct task/cell links only for registered deliverables. + +## Implementation plan + +- Skill sections to change: approved publish routing, execution-card structure, publication receipt contract. +- Files to update: `SKILL.md`, `references/daily-operations.md`, `tests/test_business_contracts.py`, `.evozeus-wrapper/CHANGELOG.md`. +- Backward compatibility: Scheduled runs remain `proposal_only` and `private_draft`; no automatic publish, Base mutation, status change, acceptance, or baseline change is added. + +## Verification plan + +- Source discovery check: verify the configured profile, destination chat, and both identity readiness states before publish. +- Manual checks: user-denied/bot-available publishes once as bot; user-available publishes as user; both unavailable returns blocked; receipt records sender and fallback. +- Regression cases: duplicate idempotency key does not resend; changed card fingerprint or destination invalidates approval; unregistered collaboration item has no fabricated link. +- Preflight command: `python3 .evozeus-wrapper/scripts/evozeus_wrapper_preflight.py doctor --repo MetaInFLow/metainflow-dev-tasks`. + +## Release plan + +- Changelog entry: Unreleased patch for approved-publish identity routing and person-led card contract. +- Release tag: next patch release after review and merge. +- Release description summary: closes the publication gap observed while delivering the 2026-09-22 execution card. + +## Risks and rollback + +- Risk: Some external chats may permit neither sender identity; the Skill must report a blocked publication without trying unrelated profiles. +- Rollback plan: revert the focused Skill, reference, test, changelog, and design-doc changes; retain the existing Issue #10/#11 behavior. diff --git a/SKILL.md b/SKILL.md index 37c6c2d..eab48ae 100644 --- a/SKILL.md +++ b/SKILL.md @@ -142,7 +142,7 @@ description: 通过 lark-cli/LarkSuite CLI 处理「源子技术部管理系统 - 工时或日报:新建 `03-工作日志`,绑定 `所属子任务`,填写日期、记录人、工作内容、投入工时、完成百分比和阻塞情况。 - 早会或日计划评估:先解析相关任务所属项目并读取项目任务安排,再读取会议纪要、会前日计划、上一工作日项目相关聊天和相关 Base 记录,按“项目范围、里程碑、计划覆盖、优先级、负责人、时间节点、验收口径、阻塞风险、系统同步”逐项核对;输出已对齐项、冲突/缺口和建议同步动作。 - 状态、排期或负载询问:读取 `01-需求池`、`02-子任务`、`03-工作日志`、`13-团队成员` 的相关记录;涉及当前或当天执行时同时读取会前日计划。回答时给出标题、状态、负责人、优先级、日期/截止日期和关联对象,并说明是否只读取了分页样本。 -- 消息卡片或群消息:“生成/做一个”只生成私下草稿;只有用户对最终内容和目标群/聊天给出明确发布授权时才发送。修改后重新确认,发布后返回发布回执。 +- 消息卡片或群消息:“生成/做一个”只生成私下草稿;只有用户对最终内容和目标群/聊天给出明确发布授权时才发送。卡片草稿按人员组织,每人的可验收产出单独列出;已登记产出必须使用对应任务记录/单元格直链。`approved_publish` 发送前先用配置 profile 核对目标会话和可用身份:优先用户身份;用户身份因权限或外部群策略失败时,在同一 profile 检查并尝试已在群内的机器人身份一次。成功后回执必须记录实际发送身份、回退原因、目标会话、消息标识和幂等键;用户与机器人均不可用才返回阻塞。 ## 最低写入信息 diff --git a/references/daily-operations.md b/references/daily-operations.md index dafd5c6..41d5517 100644 --- a/references/daily-operations.md +++ b/references/daily-operations.md @@ -106,7 +106,11 @@ checkpoint_path: optional consumer-workspace path - 明确的目标会话; - 本次发送 `idempotency_key`。 -发布后记录 `publication_receipt`,至少包含目标、发布时间、消息标识和可用链接。卡片实质修改、目标变更或批准已撤回时,旧授权立即失效。 +发送前先用配置的 profile 查询或核对目标会话,并分别确认用户身份与机器人身份的可用性和群成员关系。默认优先用户身份;若用户身份返回权限、外部群策略或不在群内错误,且同一 profile 的机器人身份已在目标群内,则只回退一次到机器人身份。不得因为用户身份失败直接判定目标群不可发,也不得无依据切换到其他 profile。 + +发布后记录 `publication_receipt`,至少包含目标、发布时间、消息标识、可用链接、`sender_identity`、`delivery_mode`、`fallback_reason` 和 `idempotency_key`。用户身份失败后的机器人回退沿用同一内容指纹和幂等键,避免重复发布。卡片实质修改、目标变更或批准已撤回时,旧授权立即失效。 + +执行卡草稿采用“人 -> 今日动作 -> 交付物 -> 截止 -> 交接/验收”的主结构;项目只作为任务上下文,不把不同成员机械均分成同级项目区块。需要形成产出物的事项必须附已登记任务的记录/单元格直链;没有任务登记的协同事项明确标记为待同步,不伪造链接。 ## 日终收口 diff --git a/tests/test_business_contracts.py b/tests/test_business_contracts.py index 0e8182b..73ac994 100644 --- a/tests/test_business_contracts.py +++ b/tests/test_business_contracts.py @@ -55,6 +55,28 @@ def test_capacity_and_publication_gates_are_defined(self): for term in ["WIP", "请假后容量", "草稿", "明确发布授权", "目标群", "发布回执", "重新确认"]: self.assertIn(term, self.contract) + def test_approved_publish_routes_sender_identity_and_preserves_receipt(self): + for term in [ + "配置的 profile", + "用户身份", + "机器人身份", + "同一 profile", + "sender_identity", + "delivery_mode", + "fallback_reason", + "同一内容指纹和幂等键", + ]: + self.assertIn(term, self.skill + self.daily_operations) + + def test_execution_card_is_person_led_and_links_registered_outputs(self): + for term in [ + "人 -> 今日动作 -> 交付物 -> 截止 -> 交接/验收", + "任务的记录/单元格直链", + "待同步", + "按人员组织", + ]: + self.assertIn(term, self.skill + self.daily_operations) + def test_skill_routes_recurring_management_to_daily_loop(self): self.assertIn("references/daily-operations.md", self.skill) self.assertIn("每日项目管理闭环", self.skill)