PMFlow/docs/architecture/RUNTIME_GUARDRAILS.md

200 lines
39 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RUNTIME GUARDRAILS
## 1. 目的
- 本文档承接 PMFlow 的长运行边界、跨链路守门规则与已知运行假设。
- `AGENTS.md` 保留必须立即遵守的摘要规则;本文件提供更细的运行时约束与环境边界。
- `CLAUDE.md` 只保留当前架构摘要、关键入口和高价值提醒;长清单统一收口到这里。
- requirement-plan、Feishu reply/thread、AdaptiveRAG、runtime semantic routing 等详细守门细则以本文档为真源,`AGENTS.md` 只保留摘要。
## 2. 同步规则
- 任何影响运行边界、守门策略、失败语义、已知环境假设的改动,都必须同步更新:
- `AGENTS.md`
- `docs/architecture/RUNTIME_GUARDRAILS.md`
- 任何影响目录结构、模块归属与关键入口的改动,还必须同步更新:
- `CLAUDE.md`
- `docs/architecture/ARCHITECTURE_INVENTORY.md`
- 任何影响主链路由、函数名、运行时流向的改动,还必须同步更新:
- `docs/architecture/DATAFLOW.md`
- `backend/.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/` 封装层。
- MCP 模板接入中心只允许保存模板参数、命令预览、runtime probe 和手动确认状态;`backend_direct` 模板允许由 PMFlow 后端直连校验/调用,包括远程 `streamable_http` MCP 与后端内建 `backend_adapter` runtime;本地 `stdio` 模板只能通过 PMFlow Local Bridge 或兼容 MCP host 在客户本机承载。服务端不得直接写宿主机 `~/.codex/config.toml`、不得代替客户执行本机命令。GitHub 类模板只允许保存 env var 名称或占位符,禁止落明文 token。
- 飞书回复必须经过 `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 业务动作归因主链
- 运行时业务动作归因必须优先走:
- 对象/上下文绑定
- `SemanticContextPacket`
- `SemanticDecision`
- 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` 不能再由关键词最终拍板。
- `query.answer` 相关运行时模块同样禁止换皮回流业务语义拍板:`AdaptiveRAG / external_query_service` 内不得维护 `_INTERNAL_ROUTE_OBJECTS / _EXTERNAL_ROUTE_OBJECTS / _SEMANTIC_QUERY_OBJECT_TYPES` 这类对象集合、`*_probe_is_strong / *_route_probe` 这类强判 helper、或 `query_kind(weather/news/company/market/model)` 这类对象到路由/类型的硬映射。若上游 `SemanticDecision / query_profile / source_policy_hint` 仍不足以唯一确定来源,必须显式保留 `uncertain` 或直接澄清,禁止执行层二次夺权。
- 若问题根因属于“动作路由错误 / 上下文劫持 / 独立业务流误触发”,主修法必须优先落在 ingress 分流、active topic/draft 检测、`SemanticContextPacket` 组包、`SemanticDecision` 结构化判断与 gatekeeper 放行条件。
- `workflow_semantic_planner` 当前职责是 packet / bundle 组装、兼容层收口与冷启动接入,不再作为新的关键词仓。
### 3.4 LLM 与模型路由
- `llm_service` 运行时路由必须显式传入 `routing_meta`,至少统一:
- `tier_alias`
- `response_contract`
- `fallback_policy`
- `execution_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`。
- 已绑定 active requirement context 时,显式“退出需求模式”必须在 active-context followup 阶段直接把当前 requirement topic 挂起为 `status=suspended / plan_status=suspended / pending_actions=['resume_requirement_plan']`,禁止先掉进普通 `query.answer` 再靠后续 session/route 猜退出。
- 同一 `conversation_scope` 内同时存在 collecting requirement topic 与后续普通 query 产生的 idle topic 时,runtime 选择 active requirement workspace 必须优先命中仍带 active draft 的 live requirement topic;禁止因为新 topic `updated_at` 更近就把 idle query topic 误当成当前 requirement context。
- 用户显式说“聊个新需求 / 另一个需求 / 跟上一个无关”时,必须先清掉继承的旧 `current_project_id`。
- 裸 `A/B/C/确认/你自行推荐` 这类低信息量回复,如果没有命中当前 active requirement session 或待确认草稿,必须明确提示当前没有进行中的收敛轮次或草稿。
- `draft_pending_confirm` 草稿确认链只允许由显式锚点进入:`reply/thread`、卡片按钮或显式 `work_item_id`。无锚点普通消息、闲聊、新需求或独立事实问句禁止再按“同群/同人”回捞旧 pending draft。
- 同一 `conversation_scope` 一旦存在 active `draft_pending_confirm` workspace,命中上述显式锚点的后续消息必须优先回到当前草稿确认链处理,支持确认/修改/重出/取消与展示反馈;即使动作未识别,也必须显式提示“当前正在处理待确认草稿”,禁止再新开 topic 或落回 `query.answer`。
- 当 `draft_pending_confirm` 命中显式 `reply/thread` 锚点时,mounted draft / pending draft 的候选集必须先通过该锚点精确命中;同群、同 scope、同人但锚点不匹配的历史草稿不得继续参与打分、布尔探测或 fallback 回捞,避免 requirement-plan 的 `A/B/C` 回复被旧 draft confirm 链劫持。
- 当同一 `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 主链,文本协议只作为兼容兜底。
- `requirement_plan_followup` 一旦由 `query` 主链产出,`ReplyRenderer` 与 capture/render 链必须原样保留该 `reply_template_key`,禁止被通用 `action_succeeded` 覆盖后退回纯文本发送。对 active requirement follow-up 这类尚未绑定专属 work item 的收敛轮次,允许临时复用 mounted topic id 作为卡片按钮 round-trip target,但该 target 只用于按钮回流与追踪,不得冒充真实业务 work item。
- Feishu requirement-plan 卡片按钮回流时,若来自飞书卡片消息,必须按 `source_system=feishu` 重入并带上 `thread_context.reply_to_message_id/root_message_id`;ingress 与 mounted runtime 必须先通过 `feishu_reply_outbox.sent_message_id -> source_message_id` 归一化 canonical thread context,再继续绑定当前 requirement-plan topic。禁止按钮动作以无锚点 `ai_pmo_ui` 会话重入,导致 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 文案反推需求字段。
- `POST /ai-pmo/process-text` 与 `GET /ai-pmo/work-items` 对 requirement-plan 的前台可见状态必须直接投影 `plan_mode / plan_status / requirement_plan_context_summary`;Inbox 与其它前端入口不得再靠 `reply_template_key`、草稿 prose 或 stage 文案自行猜测当前是否仍在需求模式。
- 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` 审计标记的中性 `query.answer` 场景。后续运行时必须优先重试 semantic backfill;若命中显式 active requirement context / reply anchor,仍留在 requirement-plan 主链,否则继续按普通 QA 处理,禁止无锚点把事实问句硬降级成 requirement consultation。
- 飞书历史队列协议已停用:卡片动作与文本 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 + sender` scope key。
- AdaptiveRAG 命中显式 `reply/thread` 锚点后,问题改写必须优先使用该锚点;`session_state.last_subject / last_entity_ids` 只允许在没有显式锚点时参与续写,禁止旧会话主题覆盖显式引用上下文。
- 飞书与 AI PMO 入口(含 `message_intent=mixed`)问答链路必须绕过 deterministic/snapshot 快路径,统一落到场景化 Prompt 生成。
- `query.answer` 在进入 AdaptiveRAG 检索前必须先产出单一 `source_policy`(`internal / external / uncertain`)审计字段;来源判断只允许消费上游明确锚点与单次结构化语义结果,禁止再新增基于“问题长相”的本地关键词/正则拍板层。若上游合同仍是 `uncertain`,执行层只能保持 `uncertain` 或消费上游显式给出的 `effective_source_policy`,不得私自默认 external-first。v1 禁止同一轮 query 同时混搜内部知识库与外部网页,必须先定来源再检索。
- non-plan `query.answer` 的来源裁决统一由 `Query Route Gateway` 执行,输出必须至少包含 `route_mode / decision_origin / reply_contract / probe_snapshot(contract audit)`;回复正文必须遵守显式来源合同(`内部知识库查询:` / `外部实时查询:`),`uncertain + effective_source_policy=uncertain` 必须直接澄清,禁止混合答案。
- query-route 澄清协议也属于受控 state machine:若线程上仍挂着 `pending_clarification(kind=query_route_selection)`,但当前短消息通过 `WorkflowSemanticPlanner` 给出显式 `topic_switch=new` 或命中新话题 workflow,ingress 必须先让旧澄清立即失效,再回到新的 `query.answer` 主链;禁止因为“短句”条件成立就继续消费旧 option map。
- `Project Operating Context` 是 non-plan `query.answer` 的统一上下文基线:`/rag/ask`、`/ai-pmo/process-text` 与 kernel ingress 至少要透传 `current_project_id / current_repo_scope / page_anchor / thread_anchor / fit_scope / decision_strategy`;`Query Route Gateway` 只能在此基础上产出单次 `execution_recipe(primary_lane / fit_brief_required / external_evidence_required / plan_handoff_mode)`,external 主链若命中 `fit_brief_required=true` 必须先补 customer-safe `fit_brief`,回答 payload 只允许继续暴露 `fit_brief / external_recommendation / recommended_next_step / can_enter_plan / handoff_mode`,禁止在 presenter 或下游 helper 再靠问题文本重判 “要不要进 plan”。
- external presenter 与 payload 必须显式保留系统态 `retrieval_status` 区分:`verifier_blocked / no_relevant_results / retrieval_failed / evidence_found` 不能折叠成单一“暂无外部变化”;若 `retrieval_status != evidence_found`,必须强制 `impact_status=no_direct_impact`,并清空 `external_summary / external_impact / affected_signal_sources / external_action`。
- external recommendation 只有在 verified external evidence 与 `fit_brief.signal_source_anchors` 这类 formal current-project signal-source 锚点建立直接映射时,才允许 `impact_status=direct_match`;`current_capabilities`、feature catalog 名称或 recommendation focus 文案都不得直接触发 `direct_match`。若证据只支持背景相关性,必须显式标记 `indirect_only`,禁止冒充“已命中当前项目推荐”。
- `/rag/ask`、QA session detail 与 session state replay 对前台必须显式暴露 `route_decision / clarification_code / clarification_candidates / answer_mode / grounding_status / evidence_pack / project_operating_context / execution_recipe / fit_brief / external_recommendation / handoff_mode / can_enter_plan / recommended_next_step / session_state(last_subject, pending_clarification...)`;QA session detail 必须与即时回答共用同一份 `routing_snapshot.response_payload` 归档,禁止历史回放丢失 handoff 元数据;AI Steward UI 只能消费这些结构化字段展示当前对象、来源模式、仓库/执行通道、项目画像、外部推荐状态与下一步,禁止再从回答正文、来源标签文案或按钮文案反推 route mode。
- Feishu QA 直出文本必须消费同一份结构化 handoff 字段,但呈现层必须先收成 analysis plan 再允许自然化改写:`mixin_receive_routing.py` 先基于 `project_operating_context.current_project_id` 补当前项目实体快照,再用结构化 planner 只选择 1-2 个最相关的当前项目实体,固定产出 `conclusion / focus_entities / missing_mapping / next_step`,之后才允许自然化改写最终文本。自然化阶段禁止新增 analysis plan 之外的项目实体;运行时必须同时拒绝 fixed opener、`当前项目:/外部判断:/下一步:` 标签摘要、项目实体清单平铺以及 blocked entity 泄漏。若结构化 planner、自然化输出或校验失败,必须 fail-closed 回退到 analysis-plan deterministic 文本;`draft_pending_confirm / requirement_plan_followup / pending_manual` 这类显式模板键仍优先走 action card,且 `verifier_blocked / no_relevant_results / retrieval_failed / indirect_only` 必须保留为可区分文案,禁止重新折叠成统一空兜底句。
- 飞书客户可见验收基线必须看“后端最终格式化输出”而不是内部 payload:非交互 QA 看 `FeishuReceiveRoutingMixin._build_feishu_qa_direct_reply_text()` 产出的 `qa_direct` 文本;强交互 requirement / draft / pending-manual 看 `FeishuCardActionMixin._build_action_card_from_capture_result()` 产出的 action card payload。禁止只根据 `rag_result.fit_brief / external_recommendation / recommended_next_step` 是否存在就宣称飞书前台验收通过。
- unified handoff 运行时必须支持独立 rollback guard,且关闭后不需要回退 ingress/context 真源:`PMFLOW_ENABLE_UNIFIED_EXECUTION_RECIPE=0` 仅把 recipe 退化为 lane-only 合同、关闭 `fit_brief_required / offer_after_answer`;`PMFLOW_ENABLE_FIT_BRIEF_EXTERNAL_RECOMMENDATION=0` 只跳过 `fit_brief / external_recommendation` 构建,不影响 external 主检索;`PMFLOW_ENABLE_DEFAULT_PLAN_HANDOFF_RENDERING=0` 只关闭默认 `offer_after_answer` 的 `recommended_next_step` 呈现,显式 `explicit_plan_now` 锚点仍必须继续生效。
- 网页 `query.answer` 入口的显式锚点 v1 只允许消费稳定强锚点:项目页路径里的 `project_id`,以及 URL query 中已经显式存在的 `project_id / source_chat_id`;全局浮窗与项目页入口必须原样透传这些字段到 `/rag/ask`,禁止在前端或运行时新增“猜测型 source_chat_id 推断器”。
- `统一 Project Operating Context + 三路 handoff` 的实现验收必须同时通过 `docs/superpowers/specs/2026-04-17-feishu-problem-inventory.md` 中的黄金样例与对应回归测试,不能只看 architecture contract 是否对齐。
- This work is not allowed to introduce new keyword routing, regex routing, or hard-coded semantic split helpers.
- `Query Route Gateway` 只能汇总上游显式语义、审计锚点与执行结果,不得先并行跑 internal/external 语义探针再做“strong/weak/probe_conflict”裁决。internal / external 的执行分叉必须发生在来源合同已经确定之后;若合同不确定,只能停在 `uncertain/clarify`,禁止先执行双探针再回写路由结论。
- internal `query.answer` 在 `route_mode=internal` 后必须继续经过受控内部查询主链:`rag_query_semantics -> Operation Contract -> Target Resolver -> Query DSL Plan -> InternalContextPacket -> DSL normalizer -> 白名单执行器 -> semantic facts 优先(可用时)-> bounded fallback retrieval -> answer verifier`。`Operation Contract` 只负责回答合同与对象 mention,`Target Resolver` 只负责对象仲裁;planner 只允许输出结构化计划,禁止让 LLM 直接写 SQL、决定自由 join 或直接输出未取证的内部结论。
- `InternalContextPacket` 是 internal-only 运行时单一真源,至少固定携带 `packet_version / question / scope / route_decision / operation_contract / target_resolution / query_plan / executor_summary / verifier_summary / uncertainties`。`query_semantics["operation_contract"] / ["target_resolution"] / ["query_plan"]` 只允许作为上游 scratchpad 或同请求兼容镜像,不得再被 internal executor、internal verifier 或 runtime summary 注入链路当作真源读取。
- internal 主链在真正进入 fast path / bounded executor / retrieval 前,必须先完成 `InternalContextPacket` 预检;若 packet 缺失、`operation_contract.query_type` 缺失、`target_resolution.resolution_mode=clarify` 或 `query_plan.answer_contract` 缺失,只能显式返回 `clarify / explicit_insufficient_evidence`,不得继续执行 internal fast answer、deterministic query 或 retrieval。
- `query_semantics` 对 `operation_contract / target_resolution / query_plan` 的镜像写回只允许出现在单点兼容适配层;禁止在多个 internal helper 里散落回写这些字段再互相读取,避免 packet 真源再次漂移回多真源。
- `rag_query_semantics` 的内部只读 `query_type` 基线统一收口为 `existence / count / list / status / explain / diagnose / compare / unknown`;`A/B/C`、`确认`、`退出需求模式`、`继续核实` 等协议/模式/执行动作不属于 `query_type`,必须在 ingress / followup gate 提前处理,禁止掉进 `unknown` 后再误入内部查询。
- `Query DSL Plan` 必须显式携带 `query_type / entity_type / answer_contract / filters / scope / retrieval_policy / verifier_checks`。执行层只能消费该结构化计划,不得再在下游根据“问题长相”二次拍板。
- `target_resolution.resolution_mode=clarify`、`query_plan.answer_contract` 缺失或 `InternalContextPacket` 缺关键字段时,internal 路径只能显式返回 `clarify / explicit_insufficient_evidence`,禁止掉回自由问答或靠 answer 文本倒推合同。
- `semantic_facts` 是内部查询的辅助读模型,不是业务写入真源;当事实数据可用时,内部查询必须优先查 facts,再决定是否回退到受控文本/图谱/配置检索。facts 必须带 `confidence / evidence / extract_version / tenant_id`,证据不足时禁止包装成确定性内部结论。
- `semantic_facts` 自动抽取是内部查询的必经数据基线:`project / task / signal / document / user / requirement(charter) / release / review` 八类对象的 create/update 必须统一经 ORM 提交钩子收集变更,并 upsert `ingest_events(channel=semantic_fact_extract, event_key={entity_type}:{entity_id})`;禁止在各路由、controller 或零散 service 里继续手工 enqueue。
- `semantic_facts` 的 delete/archive/disable 场景只能走 `operation=deactivate` 失活旧 active facts;extract 重跑前也必须先失活旧 facts,再写入新 facts,禁止保留脏 active 数据继续参与内部查询。
- `semantic_facts` 的 manual retry 与 backfill 必须复用同一 `semantic_fact_extract` 队列和同一 worker;默认 backfill 只补 `only_missing=true`,禁止另开旁路写表或直接同步抽取。
- answer verifier 至少要校验“问法合同、证据合同、来源合同”三件事;若发现 existence/status/compare 被答成 total count、或引用证据与执行结果不一致,必须拒绝出站并显式失败或重试,禁止静默放过。
- `query.answer` 的客户可见回答必须再经过 `Answer Presentation Policy`:运行时证据统一拆为 `customer_safe` 与 `admin_debug` 双视图。客户视图只允许消费中文化 `display_label/display_summary`,禁止直接暴露 `raw_source_label`、表名、chunk id、tool trace 或 `Project database / Semantic facts / Knowledge Graph / Feishu history` 等机器/内部术语。
- 通用行业趋势/外部品牌模型 freshness 问答,禁止把项目图谱、Feature Catalog、内部文档或用户历史冒充成“外部事实”;若命中 live external `url/http(s)` 证据,必须优先基于外部结果回答;若实时外部检索为空或不足,才允许显式返回“当前未接入实时外部数据/暂无法确认最新结论”。
- external `query.answer` 在 `route_mode=external` 后必须继续进入受控外部查询主链:`External Query Planner -> External Query Gateway -> External Provider Registry -> MCP adapter 优先 -> bounded fallback live search -> external answer verifier`。AdaptiveRAG 运行时必须通过 `backend/app/services/external_query_service/` 统一执行,external probe / freshness fetch / external route retrieval 不得再绕回直接 DuckDuckGo HTML 抓取。大模型只允许产出结构化 `ExternalQueryPlan` 与 grounded answer,不得自由联网、自由调用工具或在无证据时直接给外部事实结论。
- external `query.answer` 在 verifier 之后必须继续生成 `ExternalContextPacket`,并由 `ExternalAnswerPresenter` 负责最终回答生成;presenter 只能消费问题文本、计划摘要、经 verifier 通过的外部证据摘要与外部来源摘要,禁止重新注入 `system_snapshot / user_snapshot / project_context / 内部 context_blocks`,也不得回流 `industry_trend / external_trend` 旧 scene prompt 混答。
- `query_route_memories` 的 manager-only summary/list/detail 治理接口只允许做只读审计和人工排查:可以暴露 `reply_contract / probe_snapshot / query_profile / feedback_outcome` 等调试快照,但不得在线自动修改 route decision、阈值或 prompt。
- 若 `ExternalContextPacket` 内 `verified_evidence` 为空,或 verifier 未通过,外部回答必须显式返回“证据不足/需要澄清”语义;禁止为了给出完整回答而退回 legacy external trend prompt、内部检索结果或项目上下文补写结论。
- `External Query Planner` 的 fallback 只允许补齐 `search_queries / preferred_domains / location_hint / time_range_hint / result_limit` 等执行参数,不得再根据 `referenced_objects / subject_focus / needs_freshness` 在运行时把问题硬分成 `weather/news/company/market/model` 等语义类别;对象归类必须来自上游单次结构化语义或显式用户对象,若没有就保持通用 external 计划并把不确定性显式带入 verifier。
- `scripts/semantic_lint.py` 必须把上述“对象词表 / probe helper / object->query_kind 映射”视为运行时违规形态;默认扫描范围至少覆盖 `backend/app/services/ai_pmo`、`backend/app/services/adaptive_rag_service`、`backend/app/services/external_query_service`、`backend/app/services/integrations`、`backend/app/services/signal` 与 `backend/app/api/ai_pmo_api`。新增或改名的同义写法也必须纳入 lint 规则,禁止只防 `*_HINTS/*_KEYWORDS/looks_like_*` 这种旧形式。
- 涉及模型事实的聊天问答,只有用户显式询问系统配置、路由、接入状态、运行时参数或 `ai-config` 等内部对象时,才允许落入 `ai_pmo / snapshot identity / 内部模型配置` 场景;否则禁止把通用“最新/当前/模型/版本”问题内化成系统配置问答。
- 内部模型配置问题(如“我们系统当前接的是哪个模型配置”)必须优先走 `integrations(llm_engine/model_routing)` 的确定性读取链,禁止再回落到 `System Snapshot / 功能目录` 类快答。
- 用户对上一条行业/外部趋势回复的事实性纠错追问,必须优先留在聊天问答链路;若锚定上一轮 `industry_trend/external_trend`,禁止切入 `ai_pmo_correction` 裁决文风。
- 外部“最新/目前/截至现在”等 freshness 问答,只有命中显式外部来源(如 `url/http(s)` 证据)时才允许记为 grounded;仅凭项目图谱、Feature Catalog、系统快照或内部资料时,必须降级为 `insufficient_evidence` 并明确说明当前未接入实时外部数据。
- 外部来源合同必须 fail-closed:若 external source filter 过滤后为空,只能返回空 sources 或 freshness guard,禁止把 `Feishu history / doc / pmflow / graph` 等内部来源兜回 external 回答的 `来源摘要`。
- prompt context hygiene 也属于展示契约的一部分:生成式回答 prompt 的 `context_blocks` 只能喂 `display_label`,不得再把 `raw_source_label` 直接喂给模型,避免模型正文复述英文机器标签或内部术语。external answer presenter 的 prompt 也必须遵守同一规则,只允许消费 external-only 的展示字段和证据摘要。
- 外部 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`。
- `query_route_memories` 是独立的路由审计/离线评估样本表:记录 `qa_record_id / route_mode_predicted / route_mode_effective / probe_snapshot / query_profile / feedback_outcome / question_embedding`;v1 只允许沉淀与离线评估,禁止在线自动调阈值或自发改路由策略。
- `QAFeedback` 与 `FeedbackCenterRecord` 写入后必须同步回灌对应 `query_route_memories.feedback_outcome`,便于 route precision/recall 离线评估。
- 训练/微调 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 环境默认使用 `certifi` CA 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` 显式开启;但 embedding 允许独立回退到本机 `OLLAMA_HOST + OLLAMA_EMBED_MODEL`(默认 `nomic-embed-text:latest`)获取真实向量。
- embedding 生成失败时必须显式返回空向量,禁止再回退伪向量或哈希向量冒充“可检索”。
- IT 五轮 requirement plan 现以 `MountedDraftWorkspace.active_work_item_id + latest_*_message_id` 锚定当前 active draft;历史未绑定这些字段的旧草稿不会自动认领。
- semantic facts 治理页与管理接口(overview / objects / detail / reextract / backfill)只对 `BOSS/ADMIN` 开放;非管理员不得看到队列、facts 内容或手动治理操作入口。
- semantic facts 自动抽取、治理页和 internal existence/facts-first 查询都不以前置向量库为依赖;向量检索可作为 bounded fallback,但不得取代 facts 基线。
- 当前 repo 已接入两类可复用 backend 外部检索 bridge:`microsoft_learn` 通过 `backend/app/services/mcp_config/runtime.py` 以 `streamable_http` 由 PMFlow 后端直连;`duckduckgo` 通过同文件内的 `backend_adapter` runtime 由 PMFlow 后端直接执行搜索。其余模板若无 backend-direct runtime,仍必须显式降到 bounded fallback live search,禁止静默冒充 MCP 成功。
- MCP 模板接入中心当前区分两类状态:后端直连模板的 runtime probe 只代表 PMFlow backend 对远程 MCP 或内建 backend runtime 的可达性;Local Bridge 模板的“已确认”仅表示用户手动确认客户本机已承载,不代表后端完成宿主机探活,也不负责探测客户真实文件系统或本机 host 进程状态。
## 5. 维护建议
- 想看“必须立即遵守的规则”:先看 `AGENTS.md`
- 想看“当前架构说明和关键入口”:看 `CLAUDE.md`
- 想看“长运行边界、守门规则和已知环境假设”:看本文档