19 KiB
19 KiB
RUNTIME GUARDRAILS
1. 目的
- 本文档承接 PMFlow 的长运行边界、跨链路守门规则与已知运行假设。
AGENTS.md保留必须立即遵守的摘要规则;本文件提供更细的运行时约束与环境边界。CLAUDE.md只保留当前架构摘要、关键入口和高价值提醒;长清单统一收口到这里。- requirement-plan、Feishu reply/thread、AdaptiveRAG、runtime semantic routing 等详细守门细则以本文档为真源,
AGENTS.md只保留摘要。
2. 同步规则
- 任何影响运行边界、守门策略、失败语义、已知环境假设的改动,都必须同步更新:
AGENTS.mddocs/architecture/RUNTIME_GUARDRAILS.md
- 任何影响目录结构、模块归属与关键入口的改动,还必须同步更新:
CLAUDE.mddocs/architecture/ARCHITECTURE_INVENTORY.md
- 任何影响主链路由、函数名、运行时流向的改动,还必须同步更新:
docs/architecture/DATAFLOW.mdbackend/.control_plane/pmflow-routing-rules.json
3. 核心运行边界
3.1 平台与写路径
- 数据库写操作必须通过 Alembic migration,禁止直接
ALTER TABLE。 - 运行期禁止 DDL;仅迁移路径允许执行
CREATE/ALTER/DROP/...。 - 运行环境数据库仅允许 PostgreSQL(
postgresql+asyncpg),禁止回落 SQLite。 - 新增接口必须遵循响应包络:
{code, message, data}。 - 禁止在 API 层写业务逻辑;业务逻辑归属
services/。 - 禁止在前端组件内直接调用
fetch,必须通过frontend/src/api/封装层。 - 飞书回复必须经过
feishu_reply_outbox,禁止同步直接发送。 - 飞书回执发送仅允许
main.py的 drain loop 作为消费者,禁止在业务路径即时派发发送任务。 - 所有写接口必须落审计日志(
operation_logs),至少包含trace_id/interface_path/caller。 created_at_beijing为计算属性返回,禁止新增数据库物理列。
3.2 核心业务零兜底
- 模型失败、超时、空响应、结构化解析失败时,必须显式返回真实失败原因。
- 禁止使用固定兜底文案、模板句子、占位字段或 stub 数据冒充成功结果。
- 核心业务完成态不得仅按字段非空判定;必须能区分“真实生成 / 人工填写 / 模板占位 / 生成失败”。
- 技术层 fallback 仅允许用于重试、缓存、解析修复、传输兼容等基础设施环节,禁止上浮为用户可见业务结论。
- AI Steward 与其它生成链的成功/失败判定必须优先使用结构校验、字段完整性和证据一致性。
3.3 业务动作归因主链
- 运行时业务动作归因必须优先走:
- 对象/上下文绑定
SemanticContextPacketSemanticDecision- gatekeeper
- 用户前台允许以内置 AI 会话作为主入口,但该入口必须绑定正式业务上下文与业务对象,优先服务于
query.read_only / requirement_plan / project.create / signal.create / followup.*等主链,禁止演化为脱离 PMFlow 业务对象的泛化聊天产品。 - 新增 AI 前台能力时,必须优先接入“消息/上下文 -> 语义识别 -> 业务对象/草稿 -> 审计/幂等/确认 -> 入库/执行”链路;不得只停留在对话文本层或仅新增孤立聊天能力而不进入正式业务闭环。
backend/app运行时代码不得再沉淀会直接拍板project.create / signal_source.onboard / followup.* / query vs execute的中文关键词、正则、looks_like_*、*_HINTS/*_KEYWORDS规则仓。- 协议级锚点(
reply_to_message_id/button/work_item_id)、租户权限、幂等等确定性规则可以保留,但展示反馈、草稿确认/修改/取消、followup 动作归类、query vs execute不能再由关键词最终拍板。 - 若问题根因属于“动作路由错误 / 上下文劫持 / 独立业务流误触发”,主修法必须优先落在 ingress 分流、active topic/draft 检测、
SemanticContextPacket组包、SemanticDecision结构化判断与 gatekeeper 放行条件。 workflow_semantic_planner当前职责是 packet / bundle 组装、兼容层收口与冷启动接入,不再作为新的关键词仓。
3.4 LLM 与模型路由
llm_service运行时路由必须显式传入routing_meta,至少统一:tier_aliasresponse_contractfallback_policyexecution_mode
- 禁止再通过函数名片段、hint 常量或模板词在底层推断 tier、结构化输出或 fallback 策略。
- 所有 LLM 调用禁止静默兜底与 stub 假成功;low 失败时必须优先强制升级到 high 重试并保留低/高两段日志,high 仍失败时才显式报错。
- 用户可见问答链路(
function_name含answer/reply/qa)禁止使用reasoning_content回退,避免思考过程外漏。 integrations(type='model_routing')的 runtime tier override 不得把adaptive_rag_answer_normal/adaptive_rag_answer_deep这类用户可见 QA 主函数降级到low。- 模型默认值与 provider/tier 映射以
backend/.control_plane/pmflow-routing-rules.json为唯一配置源。
3.5 Requirement Plan / Draft / Followup
requirement_plan必须是多轮状态机,不得退回单轮模板问答。MountedTopicWorkspace.plan_status必须显式落库区分idle / collecting / options_ready / plan_ready / awaiting_execute_confirm / suspended。requirement_plan的 A/B/C 可以固定为用户可见骨架,但业务选项、推荐项、理由和代价必须走“上下文包 -> 模型结构化决策 -> gatekeeper -> 渲染”。- 正在收敛中的
requirement_plan必须支持碎片化回复,不能因缺少新的semantic_bundle回落到普通 query。 - 同一
conversation_scope一旦存在 active requirement workspace,线程即进入 requirement mode lock:除显式“退出需求模式”外,后续消息只能走需求澄清、A/B/C/D 协议、补一句、出草稿、重出这轮等 requirement-plan 动作;闲聊或其它问答必须显式提示“当前正在需求模式”,禁止再落回casual_chat / business_review / query.answer。 - 用户显式说“聊个新需求 / 另一个需求 / 跟上一个无关”时,必须先清掉继承的旧
current_project_id。 - 裸
A/B/C/确认/你自行推荐这类低信息量回复,如果没有命中当前 active requirement session 或待确认草稿,必须明确提示当前没有进行中的收敛轮次或草稿。 draft_pending_confirm草稿确认链只允许由显式锚点进入:reply/thread、卡片按钮或显式work_item_id。无锚点普通消息、闲聊、新需求或独立事实问句禁止再按“同群/同人”回捞旧 pending draft。- 同一
conversation_scope一旦存在 activedraft_pending_confirmworkspace,命中上述显式锚点的后续消息必须优先回到当前草稿确认链处理,支持确认/修改/重出/取消与展示反馈;即使动作未识别,也必须显式提示“当前正在处理待确认草稿”,禁止再新开 topic 或落回query.answer。 - 当同一
conversation_scope内的旧requirement_plan/draft_pending_confirm已被判定为污染且当前消息不再显式锚定该线程时,ingress 必须先把 scope 内 active plan/draft topic 与待确认 work item 终止为suspended / cancelled,并把会话回退到query.answer;禁止残留 plan topic 继续吸收普通问句。 - 用户显式
reply/thread某条已绑定回复并要求“基于当前信息出草稿”时,主链必须先尝试从该 reply 命中的 mounted context 升格生成 requirement-plan 草稿;若上下文不足,必须显式失败,禁止回落到query.answer冒充“草稿已生成”。 - 用户在显式
reply/thread的同一需求线程里已经完成A/B/C选项收敛后,后续碎片化追问必须先尝试把该 reply 命中的 chat context 升格成 requirement-plan workspace,再走requirement_plan主链;禁止继续落到通用query.answer并把代码路径、内部函数名或工程证据泄漏到用户可见答案里。 - 用户对 requirement-plan 轮次回复
A/B/C协议时,识别范围必须覆盖裸A/B/C、我选C、选C、就C吧、先按C等显式选项回复;这些协议消息必须优先使用上一轮真实选项表(round_option_maps)解释该选择。 - requirement-plan 的选项协议识别属于协议层,不属于业务语义拍板;运行时代码必须复用单点协议解析器输出结构化
choice + remaining_text,禁止在各入口重新散落正则或关键词规则来解释这类协议回复。 - requirement-plan 在飞书前台应优先渲染为交互式卡片按钮;按钮动作必须携带
work_item_id与结构化动作码(如plan_choice / plan_continue / plan_reroll),由按钮回调回写到当前 requirement-plan 主链,文本协议只作为兼容兜底。 - 若后续需要在任何运行时模块新增正则/关键词驱动的协议或业务语义判断,必须先经 Host 明确确认;未经确认禁止新增。协议层优先使用单点结构化 parser、state machine、上下文快照或显式 option map,若证据不足必须显式失败,禁止再用扩词表、补正则或前缀枚举做“最小修补”。
- requirement-plan 低信息量选项回复若缺少上一轮真实选项表,只能显式失败或重新发起该轮次,禁止回退到通用 IT 项目默认映射误译用户选择。
- AI PMO ingress 的 mixed sidecar 预检查不得拦截显式
reply/thread下的低信息量协议回复(如A/B/C、我选C、就C吧);这类消息必须优先交给 active-context / requirement-plan 主链处理,禁止先生成[回答]...[已收到需求]的 mixed 拼接回复污染主结果。 - orphan requirement-plan followup 在显式
reply/thread存在时,必须先尝试从 reply 命中的 chat context 恢复或升格 requirement workspace;只有恢复失败时才允许回“当前没有进行中的 A/B/C 收敛轮次”。 - Feishu 显式
reply/thread到机器人消息时,ingress 与 mounted runtime 必须先通过feishu_reply_outbox.sent_message_id -> source_message_id归一化root_message_id/reply_to_message_id,并在后续 active-context / requirement-plan / draft 主链里复用同一份 canonical thread context;禁止直接用机器人sent_message_id新开 chat topic,导致 requirement-plan / draft 线程分叉。 - requirement-plan 的唯一业务真源固定为
MountedDraftWorkspace.requirement_card:收敛轮次、已确认字段、round_option_maps、last_round_options、source_material等业务状态只能从 draft 或结构化requirement_plan_context恢复;mounted_topic_workspaces.facts_json只允许保留线程索引级最小字段(当前限定为title / plan_profile),work_items.execution_result与mounted_conversation_runs.final_reply仅作审计/回放,禁止再从 assistant prose、topic facts 或 run 文案反推需求字段。 - requirement-plan 的运行时路由命名也必须单独收口:收敛轮次统一写
requirement_plan.collect,草稿确认前的结构化草稿统一写requirement_plan.draft;query.answer只保留给通用问答,禁止在 requirement-plan 主链里继续借用旧 query route 记账。 - 冷启动
WorkflowSemanticPlanner/pmflow_semantic_context_decision若因 provider 异常、空结构化结果或网络抖动失败,_resolve_intent不得直接把首轮线程打成error_template;必须集中降级为带semantic_planner_degraded=true审计标记的受控 requirement consultation query scene,让后续 requirement-plan 主链继续接管。 - 飞书历史队列协议已停用:卡片动作与文本 followup 只允许走
work_item_id + work_item.resume/draft_confirm主链。 - AI PMO 写操作默认先生成草稿并进入
draft_pending_confirm,未确认前禁止自动执行入库。 project_create.create与 requirement draft confirm 的任务拆解是从属子步骤,不再允许阻塞项目、主信号、来源挂载与宪章的确定性创建。任务生成链必须先按routing_meta(tier_alias=low, response_contract=structured, execution_mode=local_planner)尝试,并在结构质量不足、空任务、不可映射技能或 provider 失败时升级high;若高阶仍失败,运行时必须显式写回task_generation.status=pending与真实失败原因,保持draft_pending_confirm可重试,禁止返回默认任务、模板任务或把整条确认入库伪装成成功/失败错态。
3.6 AdaptiveRAG / Query 主链
POST /rag/ask在命中business_review/correction_escalation时,必须强制留在query.read_only主链,禁止误送到写操作草稿链。- Feishu 新消息即使被低阶 LLM 先判成写动作,只要统一语义规划层命中
requirement_plan/business_review/correction_escalation,就必须在 ingress 阶段强制拉回受控问答主链;其中 requirement-plan 收敛轮次必须落到requirement_plan.collect / requirement_plan.draft,不得再回写为query.answer。 - 飞书群聊
query/followup同步直答只允许显式触发:@PMFlow、显式reply_to_message_id、卡片动作或显式work_item_id;无显式触发时不得同步直答,也不得写入 followup QA 桶。 - Feishu
query/followup会话键在命中reply/thread锚点时必须优先使用 thread key;仅在没有显式锚点时才回落到默认的chat + senderscope key。 - AdaptiveRAG 命中显式
reply/thread锚点后,问题改写必须优先使用该锚点;session_state.last_subject / last_entity_ids只允许在没有显式锚点时参与续写,禁止旧会话主题覆盖显式引用上下文。 - 飞书与 AI PMO 入口(含
message_intent=mixed)问答链路必须绕过 deterministic/snapshot 快路径,统一落到场景化 Prompt 生成。 - 通用行业趋势/外部品牌模型 freshness 问答,禁止把项目图谱、Feature Catalog、内部文档或用户历史冒充成“外部事实”;若命中 live external
url/http(s)证据,必须优先基于外部结果回答;若实时外部检索为空或不足,才允许显式返回“当前未接入实时外部数据/暂无法确认最新结论”。 - 涉及模型事实的聊天问答,只有用户显式询问系统配置、路由、接入状态、运行时参数或
ai-config等内部对象时,才允许落入ai_pmo / snapshot identity / 内部模型配置场景;否则禁止把通用“最新/当前/模型/版本”问题内化成系统配置问答。 - 用户对上一条行业/外部趋势回复的事实性纠错追问,必须优先留在聊天问答链路;若锚定上一轮
industry_trend/external_trend,禁止切入ai_pmo_correction裁决文风。 - 外部“最新/目前/截至现在”等 freshness 问答,只有命中显式外部来源(如
url/http(s)证据)时才允许记为 grounded;仅凭项目图谱、Feature Catalog、系统快照或内部资料时,必须降级为insufficient_evidence并明确说明当前未接入实时外部数据。 - 外部 freshness 问答的后续一句话跟进(如“继续核实”“联网查一下”“接入外部来源继续核实”)若锚定上一轮
insufficient_evidence + External Freshness Guard回复,必须优先留在query.answer问答链,并先尝试 live external 检索;只有当实时外部检索仍为空或失败时,才允许继续返回 freshness guard。只有用户显式点明系统/项目/配置等内部对象并提出接入动作时,才允许继续落入signal_source_flow / internal onboard / draft等内部执行链。 - 飞书聊天可见答案禁止泄露内部函数名、文件路径、代码行号、模块名或调试字段;prompt 护栏与出站文本清洗必须同时满足该约束。
- mixed 场景回复必须强制两段格式输出:
[回答]与[已收到需求] ...,已入库处理。
3.7 Signal / Project / SSTC / Briefing
SignalSourceRegistry仅作为信号源接入/幂等内部表;用户可见的项目“信号源/信号”统一落到正式Signal。create_project_from_natural_language必须支持透传requested_member_user_ids,草稿确认时必须把推荐负责人并入项目创建事务。- AI Steward
project-from-text归一化阶段必须优先走人员能力图谱,禁止绕过能力图谱直接拍脑袋分配。 - AI PMO
signal.create在用户显式要求“先分析再入库 / 自行分析”时,若批量结构化分析失败,必须返回失败安全态。 - SSTC 宪章 AI 预填充必须输出并持久化
field_status/field_evidence/readiness/derived_artifacts;总确认前必须校验readiness。 - SSTC 发布验证清单必须优先消费
derived_artifacts.verification_metrics,禁止回退默认验收项。 - 老板晨报链路只允许
BOSS/ADMIN访问;snapshot/live语义必须分离。 daily-briefing-v2必须复用同一份租户级简报内核,禁止老板晨报与每日简报各自维护独立统计口径。- 晨报/日报导出首版只允许前端“当前所见”打印导出,禁止新增后端二进制 PDF 生成服务。
3.8 Feedback / Training / Prompt Registry
- 只读问答链路的 prompt 读取优先级固定为:
- prompt registry manifest 校验
- active prompt release
- 代码 seed prompt fallback
- 回复质量迭代与训练管线的原始反馈入口统一复用
feedback_center_records / qa_records / ai_call_logs。 - 训练/微调 artifact 必须先进入
trained_model_artifacts -> trained_model_deployments候选链路,再绑定到low/high逻辑槽位。 - training deployment 的
accepted决策默认受 acceptance gate 约束。
4. 已知运行边界与假设
- 飞书回调字段可能缺失文件名/大小,仅保证
attachment_id/key/type可用。 - 真实飞书网页 E2E 依赖本机已登录的 Chrome/Feishu 会话。
- 真实飞书网页 E2E 只负责浏览器发消息与页面诊断,结果校验统一走数据库探针。
- 显式命名的新项目请求不得仅因正文出现历史项目标题就自动绑定已有
project_id。 - 项目创建返回的
signal_sources仅作为 AI Steward 创建结果区的内联展示;项目看板与 SSTC 信号阶段统一只读正式Signal。 - 老板晨报首版的
external_metrics只返回占位区块,不接 CRM / BI / 收入系统。 daily-briefing-v2与老板晨报当前只做同会话内snapshot/live同步,不引入 WebSocket 推送。- 飞书长连接 websocket 在本地/CI 环境默认使用
certifiCA bundle 作为信任链。 - 飞书长连接状态分为两层:
last_received_*表示 SDK 已收到事件,last_event_at表示 worker 完成处理。 - LLM 主链按
CONTROL_PLANE_ROUTING_ENABLED走 PMFlow 本地路由层 路由规则;请求超时统一以LLM_REQUEST_TIMEOUT环境变量为准。 - 路由配置唯一真源固定为
backend/.control_plane/pmflow-routing-rules.json。 - World Model 静态层已接入 Redis 缓存(
wm:static:{tenant_id}:{project_id},TTL 600s),写操作后主动 invalidate,动态层不缓存。 - 本地
ollama仅允许知识库问答链路使用,且必须通过llm_engine.settings.enable_local_kb_qa显式开启。 - IT 五轮 requirement plan 现以
MountedDraftWorkspace.active_work_item_id + latest_*_message_id锚定当前 active draft;历史未绑定这些字段的旧草稿不会自动认领。
5. 维护建议
- 想看“必须立即遵守的规则”:先看
AGENTS.md - 想看“当前架构说明和关键入口”:看
CLAUDE.md - 想看“长运行边界、守门规则和已知环境假设”:看本文档