# DATAFLOW ## Signal Planner Flow (Post-Commit Async) 1. `AIPMOKernelService` creates signal (`signal.create`) in transaction. 2. Transaction commits. 3. Background task triggers `SignalPlannerService.analyze(signal_id, tenant_id, ...)`. 4. Planner service opens isolated `AsyncSessionLocal` and loads context: - signal content/project context - project members (`user_projects -> users -> user_workloads -> user_skill_bindings -> skill_tags`) 5. Planner calls `llm_service.generate_structured_object(function_name="signal_planner_analyze")` with hard wait timeout (`25s`). 6. Structured success: - `SignalStrategicAnalysisService.merge_and_save(...)` - update `signals.planner_status=completed` - write planner payload into `strategic_analysis.ai_planner` 7. Structured invalid / timeout fallback: - build degraded planner payload (`fallback_mode=true`) - still `merge_and_save(...)` and mark `signals.planner_status=completed` 8. Hard failure (DB write / unexpected exception): - `SignalStrategicAnalysisService.mark_failed(...)` - update `signals.planner_status=failed` - try enqueue compensate reply via `FeishuOutboxService.enqueue(...)` ## Model Routing Flow 1. Frontend `ModelRoutingConfigPage` reads current mapping via `/model-routing/functions/{function_name}`. 2. Manager updates mapping via PUT API. 3. Backend persists override into `integrations(type='model_routing')`. 4. `LLMService` resolves function-level override at runtime before default control-plane rules. ## Query Route Gateway Flow 1. `AIPMOKernelService.process_ingress()` 先完成 `plan_mode` gate;命中 `reply/thread`、`work_item_id`、active requirement context、draft/workspace lock 时继续留在 requirement/draft 主链。 - 若已绑定 active requirement context 且用户显式说 `退出需求模式`,必须先把当前带 active draft 的 live requirement topic 挂起,再回到普通 `query.answer`;同 scope 下后续 idle query topic 不得抢走这次绑定。 2. 非 `plan_mode` 的 `query.answer` 进入 `TypedExecutor._execute_query_intent()`,在调用 `AdaptiveRAG.answer_question()` 前先执行 `preview_query_route_decision(...)`。 3. `AdaptiveRAGQueryRouteGatewayMixin` 产出单次结构化 `query_profile`(`needs_private_context / needs_freshness / referenced_objects`),并分别运行: - `InternalProbe`:`config_hit_count / private_object_hit_count / private_scope_hit / vector_top1_score / vector_topk_support / graph_fact_hit_count` - `ExternalProbe`:`freshness_required / trusted_domain_hit_count / answerable_page_hit_count / cross_source_agreement / external_entity_hit` 4. Gateway 结合 `query_route_memories` 的相似样本先验,输出 `route_mode / effective_source_policy / decision_origin / reply_contract / probe_snapshot`。 5. 若 `route_mode=internal`,内部只读查询必须先生成 `Query DSL Plan`:统一收口 `query_type=existence/count/list/status/explain/diagnose/compare/unknown`、`entity_type`、`answer_contract`、`filters`、`scope` 与 `retrieval_policy`;协议短回复、模式控制、执行动作必须在此之前就被 gate 掉,不得混入 DSL 规划。 6. `Bounded Executor` 只按白名单模板执行内部查询: - 优先查 `semantic_facts` - facts 不足时再做 `db/graph/doc/config` 的受控 fallback retrieval - 全程自动绑定 `tenant_id` - 不接收自由 SQL 7. `Answer Verifier` 在出站前检查“问法合同、证据合同、来源合同”是否一致;若发现 existence/status/compare 被答成 total count、或证据与结果不符,必须重试或显式失败。 8. `AdaptiveRAG.answer_question()` 只消费已经收口好的 route 决策和对应结果:`internal` 只走受控内部查询主链;`external` 统一走 `External Query Planner -> External Query Gateway -> External Provider Registry -> MCP adapter 优先(当前已接通 Microsoft Learn backend-direct runtime)-> bounded fallback live search -> external answer verifier -> ExternalContextPacket -> ExternalAnswerPresenter`,禁止再直接混入内部检索结果,也禁止回流旧的 `industry_trend/external_trend` scene prompt;`uncertain` 仅允许 `external-first` 或 clarification。 9. external presenter 只读取 external-only 输入: - question - plan summary - verified external evidence - source summaries 若 verifier 未通过或 evidence 为空,则直接返回“证据不足/需澄清”,不得混入 `system_snapshot / user_snapshot / project_context / internal retrieval` 补答案。 10. 回答完成后: - `QARecord.routing_snapshot`、`citations`、`sources_used` 继续落盘 - `query_route_memories` 追加或更新该次样本 - `QAFeedback` / `FeedbackCenterRecord` 后续会把 route feedback 回写到 `query_route_memories.feedback_outcome` ## Task Brief Flow 1. Frontend chooses template / trigger generate. 2. Backend `task_brief_service` stores template and run records in `integrations(type='task_briefs')`. 3. Generation run writes summary + artifact path. 4. `/task-briefs/center` aggregates latest generated cards for sidebar center.