Technical Design 2A - jiale-li-orion/SecFusionAgent GitHub Wiki
SecFusionAgent Technical Design 2A
中文 · Application Backend & Product Interface | Technical Design 1 | Technical Design 2 | Technical Design 3
本文补齐 Technical Design 1 与 Technical Design 2 之间此前没有独立 owner 的 Application Backend / Product Interface。TD1 已冻结 M1–M3 Data Plane,TD2 已冻结 M4–M8 Task / Context / Perception / Capability / Policy / Decision Runtime;当前实现进一步证明,中间仍需要一层稳定的 application composition:用户的一次产品操作如何进入已有 domain runtime、哪些步骤同步完成、哪些步骤创建 durable TaskRun、HTTP 返回什么、前端读取什么、长任务如何继续更新。
本设计不修改 M1–M8 ownership,不重做 Agent Runtime,也不把 HTTP / UI 语义下沉到 domain package。本文只冻结 Presentation → Application → Domain Runtime → Infrastructure 四层边界,并定义第一版 Product API、Use Case、Read Model、错误、幂等、SSE、健康检查与测试 contract。
设计状态 — 2026-10-04
本文在 TD2 已进入实现后补充,优先解决已经出现的 integration friction,而不是提前设计未来产品。第一版以 FastAPI + REST + OpenAPI + SSE 为产品接口基线;WebSocket、GraphQL、BFF、多租户 IAM、复杂 API Gateway 不作为当前前置条件。内部 Task Event Plane 继续使用 PostgreSQL durable log + Redis Streams;前端产品接口不直接复用内部 TaskEvent schema。
早期实现 checkpoint(2026-09-29):Slice A / Slice B 已进入 executable 状态,Slice C 的第一版 Product QA routing 已闭环。apps/api/dependencies.py 已统一 request-scoped database session 与 RequestContext;HTTP edge 生成/回传 X-Request-ID,Product validation / Application failure 已映射为 RFC 9457 风格 ProblemDetail;/health/live、/health/ready、/health 已分离。StartInvestigationUseCase 已完成 target resolve → Case/EvidenceNeed → Task admission → Context/Budget/Execution/TaskRun → queue 的组合,InvestigationQueries 输出不泄漏内部 runtime schema 的 InvestigationView。
Slice C 当前实现为 POST /api/v1/questions → AskQuestionUseCase → shared Task admission。显式 LOOKUP / RETRIEVE 进入 read-only DecisionRole,创建真实 TaskRun / Budget / Execution coordinate,以 current Knowledge/Evidence 构造 lightweight state 后调用同一套 M6 ModelDecisionPlanner → DecisionService;confirmed claim/relation 继续携带稳定 EvidenceRef,bounded RETRIEVE 只把检索 passage 放入 tentative context,不提升为 confirmed fact。Product Question 的 canonical fact projection 已覆盖 claim 与 relation:claim 使用稳定 subject predicate = value 并在 source-specific / temporal identity 必要时保留 compact semantics;relation 使用共享 deterministic renderer 保留 state / source_semantics / version or scope / CSAF status / compact component+platform / justification / necessary NVD configuration coordinates,同时丢弃 source/vocabulary provenance 字段与巨大的 NVD root_snapshot,避免 applicability/VEX 语义在进入 M6 前被压扁。Question context 现在还支持有界 depth-2 development expansion:只对 root 的 references-development-object 目标继续读取下一跳,且只纳入 merged-as / head-commit / belongs-to-repo / has-parent-commit / release-contains-commit 等 closed development edges,并限制 target/edge 数量;不会把任意 Knowledge graph 无界展开进 prompt。对于没有显式 cve_id/object_id 的 generic RETRIEVE,检索结果中的 canonical RetrievedCandidate.object_id 会进入 bounded InvestigationState.targets,而 chunk ID、URL、passage 只保留为 retrieval/evidence coordinate;若 M6 请求 continuation,它只能从这些 durable targets 中显式选择对象,DecisionService 继续阻止 target escape,且 Application 只有在恰好选择 1 个稳定 object 时才允许复用 StartInvestigationUseCase 升级 durable Investigation,0 个或多个 target 都 fail closed。VERIFY / INVESTIGATE / WATCH 则直接走 durable async seam 并返回 202 Accepted。同步 Question 的 Recorded ModelRequest 绑定真实 task_run_id / execution_id / budget_ref,synthetic question:* lightweight state 不写入 Case FK,因此 TD3 可以直接量真实交互延迟而无需制造假 Case。
M6 另新增 immutable DecisionResultStore:它只持久化已经通过 M6 invariant 的 typed result,为没有 durable Case 的 DIRECT/RETRIEVE 决策提供稳定 decision_id 读取;M4 仍独占 durable Case 上“哪个 decision 是 current”的 authority。GET /api/v1/decisions/{decision_id} 已可读取该 store,并兼容读取此前 M4 DecisionCommit event。数据库已增加 20260929_0026_decision_results。Product follow-up 现有第一版 durable owner:question_sessions / question_session_turns 只保存 principal、turn order、user input、carried canonical targets、Knowledge/context coordinate 与 immutable decision_ref / investigation_ref,不复制 Decision/Evidence/M4 state;迁移 20260930_0027_question_sessions 已在真实 PostgreSQL 执行。follow-up 可只带 session_id,单一 stable target 自动 carry,上一轮 ContextManifest.context_id 成为下一轮 parent_context_id;旧 Decision 通过 ref 重读后只作为 conversation/co-reference context,M6 prompt 明确禁止把它当 evidence/current truth。generic RETRIEVE continuation 的 durable target binding 也已闭环。跨 turn RETRIEVE 现在还有独立 RetrievalInvocation owner:20260930_0028_retrieval_invocations 已在真实 PostgreSQL 执行;每个 RETRIEVE 记录 operator/revision、query/request digest、Knowledge revision、limit/source scope、ordered chunk refs 与 executed/reused disposition,并通过 ContextManifest.retrieval_invocation_refs 进入 Task provenance。同 session 的后续 RETRIEVE 只有在 exact request digest 与 world coordinate 完全一致时才允许重读上一轮 chunk refs 并跳过 lexical search;任一 ref stale/missing 自动回退 fresh search。Investigation-class session follow-up 也已接到 durable Case:ContinueInvestigationUseCase 只复用仍为 active/waiting 的最新 investigation_ref,在当前 Case revision 新增 EvidenceNeed 并通过现有 InvestigationTaskLauncher 启动下一 episode;若同 Case 已存在 non-terminal InvestigationRole TaskRun,则在写 need 之前 fail closed,避免 Product session 引入并发 Case writer。resolved/cancelled/closed Case 不静默 reopen。LOOKUP/RETRIEVE 现也有显式 Case-read profile:同 session 的最新 investigation_ref 仍指向 active/waiting Case、且本轮未显式重绑 cve_id/object_id 时,DecisionRole 直接读取该 Case 的 durable M4 InvestigationState;TaskRun、ContextManifest 和 ModelRequest 保留真实 Case/State revision coordinate,但 Product DecisionResult 不写回 M4.current_decision。M4 raw EvidenceLink ID 只在 ephemeral Product projection 中规范成 evidence:<id> 供 M6 citation gate 使用,不修改 durable Case state。Case-read RETRIEVE 要求 InvestigationState.last_world_revision == current Knowledge revision,禁止把 stale M4 state 与 fresh retrieval passage 混在同一个 read context;若 M6 返回 continuation,EvidenceNeed 继续追加到同一 Case,而不是新建第二个 Case。当前仍未完成的是 public idempotency、cancel/resume、ProductEvent/SSE、更完整 Product read surface、live Case-read / long-Investigation 的更广 frozen denominator,以及 retrieval failure 在 Context/TaskRun 建立前的独立 durable attempt 记录。正式 single-turn Product QA 与普通 multi-turn/session retrieval reuse denominator 已闭环,不能再与这些扩展项混写成“Product QA 尚未执行”。
2026-10-03 formal closeout:同一 deployment:0e16e1b574d5b6383434e7fc80f64cc4 下,AskQuestionUseCase 的 14 个 live single-turn Product QA case 与 2 个 two-turn Product session 已全部进入 durable BenchmarkRun。single-turn 的 answer accuracy / groundedness / citation correctness / citation completeness / completion / multi-hop / unknown 均为 1.0,interactive latency 平均 2.517s、最大 4.032s;session context chain / target carry 均为 1.0,RETRIEVE reuse case 的 invocation coverage / reuse rate 均为 1.0。这证明 Slice C 的产品路径已经从“可执行”升级到“同 deployment 可测且可追溯”。当前 Alembic single head 为 20261002_0029。
当前代码已经存在三类 surface,本文首先把它们分轨:
- Product API:面向最终用户和比赛产品,要求稳定 DTO、Use Case、错误和版本 contract。
- Runtime Workbench:面向开发、测试和比赛复验的内部观察面,允许查看 TaskContract、ContextManifest、TaskEvent、M7 coordinates 等内部状态,但只在 dev/test + feature flag 下开放。
- A2A Adapter:面向 Agent-to-Agent interoperability,遵循 A2A 协议,不等价于 Product API。
三类 surface 可以读取同一套 TD1/TD2 runtime,但不共享 transport contract。
1. 当前实现基线与问题定位
本设计直接基于 2026-09-27 本地代码状态,而不是从空白系统推演。
1.1 已经正确形成的边界
当前 apps/api/main.py 保持较薄,只负责 FastAPI lifespan、数据库 session factory、router 注册和 dev/test 静态 Workbench 挂载。apps/worker 负责 Celery worker / scheduler;TD2 Investigation / Enrichment 的真实执行已经进入统一 TaskRun / ExecutionRun / Role Runtime,而不是由 HTTP request 持有长任务。
顶层 apps/ 下已经存在一批 composition module:
- task_admission.py:把 Enrichment / Investigation compiler 与 Runtime Policy 组合成统一 TaskContractService;
- investigation_runtime.py:组合 ModelProvider、ContextMaterializer、PerceptionRuntime、Delegation、Budget、Execution;
- decision_runtime.py:组合 M6 DecisionService 与 M4 DecisionCommit / Continuation gate;
- enrichment_runtime.py、perception_execution.py、investigation_delegation.py、watch_runtime.py:完成对应 runtime wiring。
这些模块已经承担“把多个 domain package 组合成可运行能力”的职责。2A 不重新制造另一套 Runtime,只在其上增加产品 Use Case owner。
1.2 当前 Workbench 为什么会变重
apps/api/routes/workbench.py 当前约 700 行,同时承担:
- Pydantic request / response model;
- 直接 SQL aggregation 和 list query;
- Case / EvidenceNeed 创建;
- Task admission;
- ContextManifest 构造;
- Budget / ExecutionEnvelope 创建;
- TaskRun queue transition;
- Celery enrichment trigger;
- M6 DecisionRuntime wiring;
- citation source assembly;
- HTTPException 映射。
这些代码多数没有绕过 TD1/TD2 domain gate,因此不是“业务规则写错了”;问题是 Application Use Case 没有独立 owner,导致 route 被迫同时承担 transport、query composition 与 workflow orchestration。随着 Product API 增加,继续沿这个模式扩展会让 route 成为新的 god layer。
1.3 当前 Workbench 不是 Product API
现有 apps/web 明确是 operator/test frontend。它故意展示:
- TaskRun / TaskContract / ContextManifest;
- TaskEvent;
- Case / InvestigationState / EvidenceNeed;
- M7 trajectory / snapshot coordinates;
- raw Decision runtime output。
这些信息对工程复验有价值,不应为了“产品化”全部隐藏。本文只规定:Product Frontend 不依赖这些 internal schema;Runtime Workbench 可以继续存在并直接观察内部状态,且不承诺 public compatibility。
1.4 当前 Product Read Path
GET /api/v1/vulnerabilities/{cve_id} 已经通过 packages.intelligence.knowledge.read.get_vulnerability_by_cve 读取 Evidence-rich KnowledgeObjectView,并保持 read-only。该 route 是当前最接近 Product API 的稳定 read seam,应保留,不因 2A 重构而打断。
2. 四层架构与 Ownership
系统产品路径固定为四层:
Presentation
HTTP / SSE / OpenAPI / A2A transport adapter
validation / serialization / request context / public error
↓
Application
Use Case / Command / Query / Read Model / ProductEvent
product workflow / sync-async boundary / idempotency
↓
Domain Runtime
TD1 Evidence/Knowledge + TD2 Task/State/Agent/Decision
business truth / runtime state / policy / capability
↓
Infrastructure
PostgreSQL / Redis / Celery / S3 / Model / External Provider
physical persistence / delivery / provider implementation
2.1 Presentation
Presentation 持有 HTTP method/path、query/path/body validation、request/response serialization、authentication bootstrap、request correlation、OpenAPI、SSE framing 与 public error mapping。
Presentation 不持有:
- 漏洞、Incident、Evidence 的业务判断;
- EvidenceNeed 创建/关闭条件;
- Task state transition;
- Capability / Policy 规则;
- Knowledge / Case 的数据库查询策略;
- Agent planning。
2.2 Application
Application 持有“一个稳定产品行为如何编排现有 domain runtime”。
例如 StartInvestigation 负责:
resolve target
→ build TaskIntent
→ Task admission
→ create/bind Case
→ bind ContextManifest
→ create TaskRun / Budget / Execution
→ queue run
→ return InvestigationView
其中每一步的业务 invariant 仍归原 domain owner;Application 只持有顺序、产品语义、sync/async boundary、public idempotency 和 read model projection。
2.3 Domain Runtime
TD1 / TD2 owner 不变:
- Knowledge / Evidence:M1–M3;
- InvestigationState / EvidenceNeed:M4;
- InvestigationRole / Perception:M5;
- DecisionResult:M6;
- Replay / Evaluation:M7;
- Capability / Policy / Budget / Sandbox / Telemetry:共享 runtime / M8。
Application 可以调用这些 port,但不能复制其规则。
2.4 Infrastructure
Infrastructure 持有 SQLAlchemy/PostgreSQL、Redis、Celery、S3、ModelProvider、external source、sandbox substrate 和网络实现。Infrastructure exception 先翻译成可归属的 failure,再进入 Application / Presentation;原始 SDK exception 不成为 public API contract。
2.5 依赖方向
Presentation
↓
Application
↓
Domain Port
↓
Infrastructure Port
↓
Infrastructure Implementation
禁止:
- domain import FastAPI / HTTP status;
- repository 返回 HTTP response;
- Product route 直接写 ORM query;
- Product frontend 依赖 ORM row / TaskEvent / StatePatch;
- Application 重写 M4/M5/M6 invariant;
- provider error 原样泄漏到客户端。
3. 三类 API Surface 分轨
3.1 Product API
目标:稳定、可版本化、可供正式前端和外部 client 使用。
要求:
- stable DTO / read model;
- OpenAPI;
- 统一 error contract;
- idempotency;
- pagination;
- authorization seam;
- request / task trace linkage;
- sync / async 明确。
3.2 Runtime Workbench
路径继续使用 /api/v1/workbench/*。
用途:
- 开发调试;
- 比赛复验;
- 观察 TD1/TD2 内部 state;
- 手工启动 Case / Task / Enrichment / Decision;
- 查看 TaskEvent / ContextManifest / trajectory / snapshot。
Workbench 可以:
- 直接查询内部 storage model 形成 diagnostic view;
- 暴露内部 runtime field;
- 返回 Celery task id;
- 不承诺长期 public DTO 稳定。
Workbench 不可以:
- 绕过 domain write gate 直接修改 canonical Knowledge / M4 state;
- 在 prod 默认开放;
- 成为正式 Product Frontend 的唯一 backend contract。
3.3 A2A Adapter
路径 /api/v1/a2a/* 保持协议适配职责。A2A Task / Artifact / Message / Stream semantics 与 Product Investigation / Decision UI 不共用 DTO。A2A inbound message 如果未来进入真实执行,仍必须通过 authenticated principal、TaskIntent normalization 和 shared Task admission。
4. Application Use Case 是产品行为的 Owner
Application 不建立单一 ApplicationService god object。每个稳定产品行为对应独立 command/query handler;输入是 typed request,输出是 public view 或 operation reference。
4.1 Intelligence Read
| Use Case | 类型 | Domain Owner | 输出 |
|---|---|---|---|
| GetVulnerability | Query | TD1 Knowledge / Projection | VulnerabilityView |
| SearchIntelligence | Query | TD1 Retrieval | SearchResultPage |
| GetIncident | Query | TD1 Incident | IncidentView |
| GetEvidence | Query | TD1 Evidence | EvidenceView |
| GetDocument | Query | TD1 Document | DocumentView |
普通 GET 只读取当前世界,不在 miss 时隐式触发 enrichment、资产扫描或外部搜索。
4.2 Question / Decision
| Use Case | 类型 | Domain Owner | 输出 |
|---|---|---|---|
| AskQuestion | Command-like Query | Task admission + M6 | QuestionResultView |
| GetDecision | Query | M6 / M4 | DecisionView |
AskQuestion 是 Product API 的 routing point:
Question
→ TaskIntent / admission
→ ExecutionProfile
DIRECT
→ current Knowledge / M4
→ M6
→ synchronous Decision
RETRIEVE
→ bounded Perception
→ M6
→ synchronous Decision when interactive budget allows
VERIFY / INVESTIGATE
→ durable Case + TaskRun
→ 202 Accepted
WATCH
→ durable Case
→ 202 Accepted / waiting
4.3 Investigation Lifecycle
| Use Case | 类型 | Domain Owner | 输出 |
|---|---|---|---|
| StartInvestigation | Command | M4/M5 + Task Runtime | InvestigationView |
| GetInvestigation | Query | M4 read | InvestigationView |
| ListInvestigations | Query | Application read projection | InvestigationPage |
| CancelInvestigation | Command | Task lifecycle | OperationView |
| ResumeInvestigation | Command | Task lifecycle | OperationView |
| GetInvestigationActivity | Query | TaskEvent / Trajectory projection | ActivityPage |
| StreamInvestigation | Stream | ProductEvent projection | SSE |
Product Web 通过 ListInvestigations(origin_scope=product, cursor) 连续读取账户可见的 Case 页面,并把“展开已载入”与“载入更早调查”分开。深链接先由 GetInvestigation 执行 owner check;若该 Case 不在当前列表页面,读取成功后仍把它放进可见索引。对应实现:2e131cc。
当前 Workbench 的 create_case + create_run 是工程复验用的两步操作;Product Use Case 可以把它们组合成 StartInvestigation,同时继续调用相同 CaseService、InvestigationStateService、TaskContractService、BudgetGovernor、ExecutionRunService 和 TaskRun storage gate。
4.4 Monitoring / Operations
| Use Case | 类型 | Domain Owner | 输出 |
|---|---|---|---|
| ListSources | Query | M1 | SourcePage |
| GetSourceStatus | Query | M1/M8 | SourceStatusView |
| GetSystemOverview | Query | Application aggregate | SystemOverviewView |
| GetHealth | Query | M8 / process | HealthView |
source enable/disable、credential mutation、policy revision 暂不进入公开 Product API;这些属于未来 admin/control plane。
5. Command / Query 分离
不要求引入完整 CQRS 基础设施,但所有 Product Use Case 在语义上区分 Command 与 Query。
Query
Query 只读取 projection / read port,不产生不可见副作用。页面刷新、详情读取、列表读取不能改变 Task / Case / Enrichment state。
Command
Command 创建或改变系统状态,包括:
- ask 触发长调查;
- start investigation;
- cancel / resume;
- 显式 refresh / re-investigate;
- 未来 human review。
每个 Command 必须定义:
- authorization;
- idempotency;
- expected revision;
- sync / async;
- public failure code;
- audit / trace。
禁止隐藏副作用
禁止:
- GET vulnerability miss 后自动启动外部采集;
- GET investigation 因 stale 自动创建新 TaskRun;
- 前端刷新触发 enrichment;
- 列表查询改变 Case status。
6. HTTP Request Pipeline
所有 Product route 共用统一 edge pipeline:
HTTP Request
→ Request ID / Trace Context
→ Authentication Bootstrap
→ Rate / Payload Guard
→ Path / Query / Body Validation
→ RequestContext
→ Route Adapter
→ Application Use Case
→ Public DTO
→ HTTP Response
Exception
→ Global Error Mapper
→ ProblemDetail
6.1 RequestContext
RequestContext
request_id
trace_id?
principal
client_id?
idempotency_key?
request_started_at
api_version
RequestContext 属于 HTTP/Application edge,不替代 TD2 ExecutionEnvelope。创建 TaskRun 后建立 request_id → task_run_id / execution_id trace linkage,Agent 后续 episode 不依赖原 HTTP connection。
6.2 Validation Boundary
Pydantic request model 负责 transport shape。Domain validation 仍由 domain owner 执行:
- 字符串是否像 CVE:boundary normalization;
- 某 TaskKind 是否允许 admission:Task Runtime;
- EvidenceNeed transition 是否有效:M4;
- Capability 是否允许:Policy;
- citation 是否支持结论:M6。
7. DTO、Domain Model、Persistence Model 分离
Transport DTO
服务 HTTP / OpenAPI / SSE / frontend。
Domain Model
服务 TD1/TD2 invariant,例如 Observation、Claim、Relation、TaskContract、InvestigationState、DecisionResult。
Persistence Model
服务 SQLAlchemy / Redis / S3 / migration / index。
Public DTO
↕ mapper
Application / Domain
↕ repository mapper
Persistence Model
Product API 禁止:
- response_model 直接绑定 ORM model;
- 原样 dump ContextManifest / PolicyDecision / CapabilityBinding;
- storage migration 无意改变 public JSON;
- frontend 根据内部 event / table field 推断产品状态。
当前 Workbench 可以继续暴露内部 schema,因为它明确是 diagnostic surface。
8. Public Read Model
Read Model 只定义前端真正需要的稳定语义,不复制全部 domain object。第一版可以由现有 read port 即时装配;只有 benchmark 证明需要时再物化独立 projection。
8.1 VulnerabilityView
当前 GET /api/v1/vulnerabilities/{cve_id} 的 KnowledgeObjectView 保持兼容。Product frontend 若需要更稳定的聚合字段,在 Application 层增加 VulnerabilityView mapper,不要求立即破坏现有 route。
至少覆盖:
- identity / canonical id;
- summary / severity;
- affected / fixed information;
- exploit / incident relation(可用时);
- conflict / unknown;
- evidence summary;
- revision / freshness。
8.2 EvidenceView
至少覆盖:
- evidence id;
- source / source class / authority;
- published / fetched time;
- locator;
- excerpt / artifact media type;
- revision。
内部 S3 URI、filesystem path、credential 不直接暴露。
8.3 InvestigationView
至少覆盖:
- case_id / revision;
- status / execution profile;
- target / goal;
- confirmed findings;
- conflicts;
- unknowns;
- open EvidenceNeed summary;
- current activity;
- latest decision;
- terminal reason;
- timestamps。
Progress 不使用模型自由生成的百分比。如果没有可靠 denominator,使用 phase、open/closed EvidenceNeed 和 Task terminal state。
8.4 DecisionView
至少覆盖:
- decision_id;
- answer;
- fact / inference / recommendation;
- citation;
- conflict / unknown / assumption;
- stop reason;
- created_at。
当前 DecisionView 另提供可选的 report_paragraphs,用于普通产品问答与已完成调查的自然段落研究报告。同步 Product Question 和持久调查终局的 DecisionRole 均显式启用报告提示词:在同一次结构化研判中先确定 answer_payload 与结论,再用问题的语言写出完整句子;段落只能引用该 Decision 已验证结论中的 EvidenceRef。前端优先显示段落和逐段证据,结构化字段留在可展开的审计层。正式 QA 的评分、回放及证据约束仍以结构化 DecisionResult 为准,不以报告措辞改写正确性;提示词版本从 decision-model-v2 变为 decision-model-v4,新评测须使用新的 DeploymentRevision,历史指标不能直接冒充当前版本。历史结果没有段落时保持兼容读取,以结论为主、字段可展开。
8.5 SourceStatusView
至少覆盖:
- source id / class / role;
- enabled / schedule state;
- health;
- last attempt / success;
- next due;
- degraded reason。
8.6 SystemOverviewView
面向 Product Overview 聚合:
- source health summary;
- recent intelligence;
- active investigation;
- recent decision;
- runtime degraded component;
- generated_at。
该 view 是 Application projection,不成为 canonical truth。
9. RuntimeActivityView:产品可解释性与内部 Trace 分离
比赛需要展示 Agent 自主调查过程,但 Product Frontend 不应直接 dump TaskEvent、PromptAssembly 或完整 trajectory。Application 提供脱敏 RuntimeActivityView:
RuntimeActivityView
activity_id
case_id
seq
actor_role
activity_type
summary
evidence_need?
selected_capability?
child_task_ref?
result_summary?
status
started_at?
finished_at?
允许的 activity type:
task_started
evidence_need_selected
retrieval_planned
capability_selected
external_observation
child_task_started
child_task_completed
state_updated
decision_ready
waiting
completed
failed
不暴露:
- 模型私有推理文本;
- 完整 prompt;
- secret / credential;
- raw PolicyDecision;
- 未经 redaction 的 tool output;
- sandbox filesystem path。
Workbench 仍可以查看更底层的 TaskEvent / ContextManifest。Product AGENTS 的 Task 详情读取经 owner check 的 AgentTaskDetail 投影:只展示 ContextManifest 的版本、引用数量与可追溯坐标、每次 ModelAttempt 的模型/状态/提供方用量/预算结算,以及已有的预算、事件、CapabilityInvocation;证据与对象引用跳转到 INTELLIGENCE read。页面不接收完整 prompt、模型私有推理文本、secret 或 raw PolicyDecision。对应实现:d8ddfed。
10. 第一版 Product API
Public namespace 继续使用 /api/v1。
Intelligence
GET /api/v1/vulnerabilities/{cve_id} # 保留现有 read seam
GET /api/v1/intelligence/search
GET /api/v1/incidents/{incident_id}
GET /api/v1/evidence/{evidence_id}
QA
POST /api/v1/questions
GET /api/v1/decisions/{decision_id}
QuestionResultView:
request_id
mode = completed | accepted
execution_profile
decision? # completed
investigation? # accepted
DIRECT / bounded RETRIEVE 可以 200;VERIFY / INVESTIGATE / WATCH 返回 202。
Investigation
POST /api/v1/investigations
GET /api/v1/investigations
GET /api/v1/investigations/{case_id}
POST /api/v1/investigations/{case_id}/cancel
POST /api/v1/investigations/{case_id}/resume
GET /api/v1/investigations/{case_id}/activity
GET /api/v1/investigations/{case_id}/events
events 使用 SSE。
Operations
GET /api/v1/sources
GET /api/v1/sources/{source_id}
GET /api/v1/system/overview
GET /health/live
GET /health/ready
GET /health
当前 /api/v1/workbench/* 不迁移成 Product API;后续 Product Use Case 可以复用其已经验证过的 domain composition,但 transport contract 独立。
11. Sync / Async Boundary
HTTP latency contract 与 Agent execution duration 分离。
同步
优先同步:
- exact / current projection read;
- 普通 structured / lexical read;
- 已有 Evidence World 上的 DIRECT;
- 满足 interactive budget 的 bounded RETRIEVE;
- status / evidence / read model。
Requirements 的普通 QA ≤5s 目标由这条 fast path 承担。
异步
以下 workload 默认异步:
- 需要新 external evidence 的 VERIFY;
- INVESTIGATE;
- WATCH;
- sandbox / browser / long provider chain;
- 超过 interactive budget 的任务。
返回:
202 Accepted
Location: /api/v1/investigations/{case_id}
客户端以后通过 stable resource ID + GET/SSE 继续,不暴露 Celery task id 作为 Product contract。
12. ProductEvent 与 SSE
内部 TaskEvent 是 runtime protocol,ProductEvent 是产品协议。Application 增加投影器:
TaskEvent / M4 state change / M6 Decision
→ ProductEventProjector
→ ProductEvent
→ SSE
ProductEvent:
event_id
stream_id
seq
type
resource_revision?
occurred_at
data
第一版事件:
- investigation.started
- investigation.status_changed
- investigation.progress
- investigation.finding_added
- investigation.conflict_changed
- investigation.evidence_need_changed
- investigation.decision_ready
- investigation.waiting
- investigation.completed
- investigation.failed
- investigation.canceled
SSE:
GET /api/v1/investigations/{case_id}/events
Accept: text/event-stream
Last-Event-ID: ...
Redis Streams 只承担内部实时 delivery;SSE reconnect 不能依赖 Redis 尚未淘汰的 transient message,必要状态从 durable TaskEvent / current read model 恢复。
第一版选择 SSE,因为主要是 server → client 状态更新。只有未来 computer-use、协同操作或高频双向控制出现后才重新评估 WebSocket。
2026-10-09 Product Question 补充:POST /api/v1/questions/stream 在同一请求内发送真实模型 model_delta,可选发送 provider reasoning;这些字节只是未验证草稿。React 会把已经收到的报告自然段按字符呈现,正式答案仍只来自通过 M6 证据不变量并持久化的 DecisionResult,到达 result 时立即替换草稿。完整会话默认请求 90 秒交互预算,服务端允许 1–120 秒;这只是执行上界,不人为延迟答案。终态 error 结束该幂等命令,重试生成新键。若模型 Decision 被证据门拒绝,服务端返回 decision_validation_failed 与失败 TaskRun 坐标,不持久化未通过校验的 Decision;前端保留明确标注“未完成、未校验”的部分报告,并按账户权限读取失败运行的模型/上下文/停止原因。未知异常只返回通用错误并在服务端按 request_id 记日志,不把内部异常或原始模型输出暴露给客户端。
13. 分页、过滤与排序
可能无界增长的列表默认 cursor pagination:
- intelligence search;
- incidents;
- investigations;
- activity;
- source runs;
- evidence list。
GET ...?limit=50&cursor=...
Page[T]
items[]
next_cursor?
has_more
Cursor 是 opaque token。Filter 和 sort 使用 allowlist,不把任意数据库 column 暴露成 public query language。
Workbench 当前 limit-only diagnostic list 可以保留;Product API 新增时按本 contract 实现。
14. Public Error Contract
当前 Product path 仍有简单 HTTPException(detail=...);2A 将正式 Product API 错误统一为 RFC 9457 风格 ProblemDetail,并增加稳定 code、request_id、retryable。
ProblemDetail
type
title
status
detail
code
instance?
request_id
retryable
context?
第一版 public code:
- validation_error
- authentication_required
- permission_denied
- resource_not_found
- revision_conflict
- idempotency_conflict
- task_not_cancelable
- task_not_resumable
- provider_unavailable
- capability_unavailable
- budget_exhausted
- deadline_exceeded
- rate_limited
- dependency_unavailable
- internal_error
HTTP mapping:
| Failure | HTTP |
|---|---|
| transport validation | 422 |
| unauthenticated | 401 |
| unauthorized | 403 |
| missing resource | 404 |
| revision / lifecycle / idempotency conflict | 409 |
| rate limit | 429 |
| async accepted | 202 |
| temporary dependency/provider unavailable | 503 |
| unknown server failure | 500 |
Evidence unknown 与 provider unavailable 必须区分。Public body 不返回 traceback、SQL、internal path、secret、raw SDK exception。
Workbench 可以暂时保留简单 HTTPException;Product route 使用统一 mapper。
15. Public Command Idempotency
当前 Workbench 创建 run 时使用内部随机 trigger_ref,适合人工复验,但正式 Product Command 必须支持 client retry。
以下 endpoint 第一版支持 Idempotency-Key:
- POST /api/v1/questions
- POST /api/v1/investigations
- POST /api/v1/investigations/{case_id}/cancel
- POST /api/v1/investigations/{case_id}/resume
Application 持有 IdempotencyRecord:
principal_scope
operation
key
request_digest
response_ref
status
created_at
expires_at?
相同 scope + key + 相同 request digest 返回既有结果;相同 key + 不同 request digest 返回 409 idempotency_conflict。
这不替代 TD1/TD2 内部 Observation/Event/Task idempotency,只处理 public command retry。
2026-10-09 实现进度:product_command_records(migration 20261009_0032)现在按账户、操作、客户端键保存归一化请求摘要与既有结果坐标。POST /questions、POST /questions/stream、POST /investigations 和 POST /investigations/{case_id}/cancel 已接入;同键同请求不重复调用模型、写会话回合或建立 Case,同键不同请求返回 409 idempotency_conflict。Question SSE 重放只返回既有终态结果,不伪造先前流式 token。Case/会话回合/最终响应与命令记录在一次事务中提交;同步模型调用之前的 TaskRun 是独立 durable checkpoint,进程在中途退出后 pending 键 fail closed,避免再次执行。失败模型调用把键标为 failed,下一次明确重试需使用新键。Web 对同一未完成表单请求复用键,并在成功后清理。独立 /resume Product route 仍未建立:现在的用户追问通过 Question session/ContinueInvestigationUseCase,运行时等待恢复由 Task Runtime 持有,不能把它们描述成已有的通用手工 resume。
16. Revision 与并发控制
需要基于当前状态发出的 command 携带 expected revision。Transport 可以使用 If-Match 或 body expected_revision,Application 转换成 domain revision check。
适用:
- cancel / resume;
- future human review;
- 基于 Case state 的修改动作。
revision mismatch 返回 409 revision_conflict,不静默覆盖新状态。
2026-10-09 实现进度:Product Investigation GET/POST 返回 quoted revision ETag;取消命令必须携带 If-Match(quoted 或整数形式),Application 在锁定 Case 后与 current_revision 对照。浏览器从所展示的 Case revision 发送条件写;失败返回 409 revision_conflict,旧页面不能覆盖较新的 Case 状态。会话追问的继续调查路径仍由现有 active-run 与 M4 revision gate 控制,独立 Product /resume 尚未提供。
17. Frontend State Ownership
正式 Product Frontend 把状态分成三类。
Server State
API / SSE 持有权威版本:
- vulnerability / incident / evidence;
- investigation;
- decision;
- source / overview。
UI-local State
只属于前端:
- 当前 tab;
- filter / sort;
- panel 展开状态;
- draft question;
- pagination cursor history;
- transient notification。
Durable Workflow State
只属于后端:
- TaskRun;
- InvestigationState;
- EvidenceNeed;
- ContextManifest;
- PolicyDecision;
- Budget;
- CapabilityInvocation;
- Trajectory。
Product Frontend 页面刷新后通过 case_id / decision_id 恢复,不把 Agent durable state 存到 localStorage。
当前 apps/web 是 Runtime Workbench,不受“不能展示内部 Task/Context”这一限制;它只是不能成为正式 Product API contract 的依赖依据。
18. OpenAPI 是 Product Contract
FastAPI 生成的 OpenAPI 作为 Product API 的机器可读 contract,至少覆盖:
- path / method;
- request / response schema;
- error schema;
- auth scheme;
- pagination;
- status code;
- example;
- SSE endpoint 说明。
前端类型优先从 OpenAPI 生成或校验,不维护平行手写 DTO。
CI 增加 Product API contract gate:
- OpenAPI 可以生成;
- schema ref 可解析;
- public response 不泄漏 persistence/internal runtime model;
- breaking change 必须显式进入 API version review。
Workbench route 可以留在同一 OpenAPI document,但标记 internal/workbench tag;如果后续需要对外发布 spec,则生成 product-only filtered spec。
19. Authentication / Authorization Seam
2026-10-08 的 Product 实现已将 principal 绑定到真实账户会话;完整契约见产品账户、会话与个性化。旧的固定 local principal 仅属于历史数据,不自动归属新账户。
Presentation:
- 从 HttpOnly Cookie 对应的服务端会话解析身份;
- 构造 RequestContext principal;
- 处理 401、Origin/CSRF 与跨标签账户变化。
Application / Domain:
- 资源级 access;
- command permission;
- TD2 Policy / Capability execution authorization。
前端隐藏按钮不能替代 authorization。X-Principal 不能作为 Product 身份来源;会话、Case、Decision、Task、SSE 和 A2A 读取必须在服务端按 durable owner 判定。公共 Evidence/Knowledge 与明确纯系统来源的只读 Case 引用另设边界,不泄漏私有 Task 或会话。
退役的 Workbench 不进入 Product 路由或导航。Nginx Basic Auth 可作为外围保护,但不能代替应用账户。生产 Cookie 需要 HTTPS、精确允许的浏览器 Origin 和可撤销的服务端 session。
20. Health、Readiness 与 Degraded State
当前只有 /health/live。第一版补:
/health/live
只表示 process 活着。外部 provider 失败不影响 liveness。
/health/ready
表示 instance 是否能承接核心请求。至少检查:
- PostgreSQL;
- 必要 migration;
- required runtime configuration。
optional source / asset / model provider 不应默认让整个 API unready。
/health
聚合:
overall = healthy | degraded | unhealthy
components[]
component
status
checked_at
detail_code?
典型语义:
- PostgreSQL down → unhealthy;
- Redis Task Event delivery degraded,但 direct read 可用 → degraded;
- 单个 source 403 → degraded;
- optional model provider 未配置且系统可 lexical-only → degraded / disabled;
- optional provider 无 credential → disabled,不伪装成核心系统故障。
21. Logging、Trace 与 Audit
HTTP edge 创建 request_id / trace context。创建 TaskRun 后形成:
request_id
→ task_run_id
→ execution_id
→ capability_invocation_id
→ evidence / decision
Structured log 至少包含:
- request_id;
- route / use_case;
- case_id / task_run_id;
- status;
- latency;
- public error code;
- trace_id;
- 可记录时的 principal_id。
Audit 与 debug log 分离。Cancel / Resume / future human review 记录谁对哪个 revision 做了什么动作。Secret / credential 不进入日志。
跨运行的 ModelAttempt、token / context 评测归因留给 TD3;单次 Task 的已持久化用量与 context 坐标由 Product read projection 呈现。
22. Transaction Boundary
Application 表达 workflow intent,但不持有跨所有 subsystem 的超级事务。
保持:
- TD1 KnowledgeChange + outbox 的既有 transaction;
- TaskRun / TaskEvent 的既有 durable boundary;
- M4 State transition / DecisionCommit 的既有 transaction;
- S3 / Redis / Celery 使用各自可靠性 contract。
跨 subsystem workflow 依靠 durable state + idempotency + event / retry / compensation,不引入分布式数据库事务。
StartInvestigation 的产品逻辑顺序:
admit TaskContract
→ create/bind Case
→ open/bind EvidenceNeed when required
→ bind Context
→ create TaskRun / Budget / Execution
→ transition queued
→ dispatch
→ return InvestigationView
当前 workbench create_investigation_run 已经验证了其中大部分步骤;2A 的任务是把这段编排从 route-level implementation 提升为 reusable Product Use Case。
23. Repository / Query Ownership
Product route 不直接查询 ORM。Application Query 调用:
1.已有 domain read service;或 2.明确的 Application read repository / query service。
当前 workbench 的 overview、task list、case list 直接 SQL 可以保留,因为它是 diagnostic surface;同样 SQL 不复制到 Product route。
Repository 持有:
- persistence query;
- mapping;
- pagination;
- transaction-local data access。
Repository 不持有:
- 产品策略;
- task admission;
- policy;
- “CVSS 高就自动调查”一类业务动作;
- provider fallback policy。
24. 代码映射:尽量补 seam,不搬家
现状已经存在 apps/*.py composition module,不进行大规模移动。第一阶段只新增 Product Application 子层:
apps/
├── api/
│ ├── main.py
│ ├── routes/
│ │ ├── knowledge.py # existing compatibility read
│ │ ├── workbench.py # dev/test diagnostic surface
│ │ ├── a2a.py # interoperability
│ │ ├── questions.py # Product API
│ │ ├── investigations.py # Product API
│ │ ├── sources.py # Product API
│ │ └── health.py
│ ├── dependencies.py
│ └── errors.py
│
├── application/
│ ├── commands/
│ │ ├── ask_question.py
│ │ ├── start_investigation.py
│ │ ├── cancel_investigation.py
│ │ └── resume_investigation.py
│ ├── queries/
│ │ ├── intelligence.py
│ │ ├── investigations.py
│ │ ├── decisions.py
│ │ ├── sources.py
│ │ └── overview.py
│ ├── views/
│ ├── events/
│ ├── idempotency/
│ └── errors.py
│
├── task_admission.py # existing composition
├── decision_runtime.py # existing composition
├── investigation_runtime.py # existing composition
├── enrichment_runtime.py
├── perception_execution.py
├── investigation_delegation.py
└── watch_runtime.py
Application Use Case 可以依赖现有 apps-level composition module;后续如果这些 module 自然形成稳定 application runtime package,再统一移动。当前不为了目录纯度制造大范围 churn。
packages/ 下的 TD1/TD2 owner 不因 2A 重排。
现有 tests/test_architecture_dependencies.py 已把 packages 之间的依赖方向变成 executable invariant,并明确禁止 package code 反向 import apps。将 Product Application 放在 apps/application 下可以保持这一约束:Application 作为顶层 composition 层允许组合多个 package,而任何 domain package 都不需要认识 Product Use Case。若未来把 Application 下沉到 packages/application,则必须重新设计依赖矩阵,不能仅为目录命名修改 architecture test。
25. Workbench 重构边界
workbench.py 当前变重,但不要求立即重写为 Product API。收敛原则:
保留
- internal DTO;
- direct diagnostic SQL;
- TaskContract / Context / Event inspection;
- source coverage;
- M7 coordinates;
- dev/test mutation;
- raw runtime detail。
逐步抽取
凡 Product API 也需要的 workflow,优先抽成 Application Use Case:
- 创建 Investigation;
- 启动 Investigation Task;
- 运行 Question / Decision;
- source / overview product projection;
- 可复用 citation/evidence mapping。
之后:
Workbench Route
→ Application Use Case / Domain diagnostic port
Product Route
→ same Application Use Case
→ Product DTO
两类 route 可共用 Use Case,但 response model 可以不同。
不追求
不为了把 workbench.py 变短而把所有 SQL 包一层无语义 service。只有可复用的产品行为和稳定 query 才获得独立 owner。
26. Frontend Contract Mapping
当前 apps/web 继续作为 Runtime Workbench。正式 Product Frontend 至少需要以下 surface:
| Product View | Backend View |
|---|---|
| Overview | SystemOverviewView |
| Intelligence Search | SearchResultPage |
| Vulnerability Detail | VulnerabilityView + EvidenceView |
| Incident Detail | IncidentView |
| Investigation | InvestigationView + Activity + SSE |
| Ask / QA | QuestionResultView + DecisionView |
| Operations | SourceStatusView + HealthView |
Product Frontend 不直接消费 TaskContract、原始 ContextManifest、StatePatch、PolicyDecision、CapabilityBinding 或 Budget row;AGENTS/QUESTIONS 使用 Application 层经过授权和裁剪的审计投影展示 context refs、model attempts 与预算状态。
比赛如果需要“展示 Agent 在干什么”,使用 RuntimeActivityView;需要专家调试时进入 Workbench。
27. Testing Strategy
现有 apps/api/tests 已经在做 FastAPI component test,并验证 Workbench 创建真实 Case / EvidenceNeed / policy-admitted TaskRun。这一层保留。
2A 增加四类测试。
27.1 Application Use Case Test
用 fake / test domain port 验证编排:
- DIRECT 不创建 TaskRun;
- VERIFY / INVESTIGATE 创建 durable Investigation;
- duplicate Idempotency-Key 不重复创建;
- stale revision 返回 conflict;
- cancel/resume 只通过 Task lifecycle owner。
27.2 Product API Component Test
通过 ASGITransport 验证:
- validation;
- status code;
- ProblemDetail;
- request_id;
- DTO serialization;
- sync / async response。
27.3 Infrastructure Integration Test
使用真实 PostgreSQL / Redis / object-store test profile 验证:
- StartInvestigation durable path;
- idempotency;
- cursor;
- SSE reconnect;
- health degraded state。
SQLite component test 可以继续承担快速 HTTP contract 检查,但不替代依赖 PostgreSQL transaction / locking 语义的 integration test。
27.4 Product E2E
第一版固定:
Lookup vulnerability
→ Ask direct question
→ synchronous Decision
→ Ask verification question
→ 202 Investigation
→ observe Activity / SSE
→ terminal Decision
→ open Citation / Evidence
以及一个 degraded flow:
Start Investigation
→ provider unavailable
→ explicit degraded / partial state
→ retry or fallback
→ terminal result
E2E 验证产品 contract,不重复 M7 的模型质量 benchmark。
28. Health / Product / Workbench 的测试分层
- /health/live:进程级 smoke;
- /health/ready:必要 dependency readiness;
- /health:聚合 degraded semantics;
- Product API:稳定 contract;
- Workbench:内部 runtime observability;
- M7:Task / Agent replay 与质量评测。
不使用 Workbench test 数量代替 Product API completeness,也不使用 Product E2E 代替 M7 benchmark。
29. 第一版实现切片
2A 以减少当前后端 coding friction 为目标,不要求一次重构完。
Slice A — Edge Baseline
- shared database/session dependency;
- RequestContext / request_id;
- global Product error mapper;
- health/live/ready;
- Product OpenAPI tag / schema boundary。
Slice B — Application Skeleton
- apps/application;
- StartInvestigationUseCase;
- Get/List Investigation Query;
- Product View mapper;
- 复用现有 task_admission / CaseService / StateService / Budget / Execution。
Slice C — QA Routing
- AskQuestionUseCase;
- DIRECT / RETRIEVE sync seam;
- VERIFY / INVESTIGATE / WATCH async seam;
- QuestionResultView / DecisionView;
- immutable DecisionResult identity +
GET /api/v1/decisions/{decision_id}; - generic RETRIEVE continuation 的 bounded canonical target resolution;
- Product multi-turn session / follow-up target + context binding;
- TD3
QASessionCaseevaluation(per-turn QA + durable context/target trace); - cross-turn retrieval chunk-overlap baseline metric;
- retrieval invocation provenance + exact-query/session result reuse;
- pre-context failed retrieval attempt 独立 durability(2026-10-09);
- semantic/non-identical-query reuse policy;
- serialized Investigation-class follow-up on the same durable Case;
- LOOKUP / RETRIEVE 直接读取 active Case M4 state。
Slice D — Investigation Lifecycle
- cancel / resume;
- idempotency;
- revision conflict;
- activity projection。
Slice E — Product Event / SSE
- TaskEvent / State → ProductEvent;
- SSE;
- Last-Event-ID reconnect;
- terminal decision notification。
Slice F — Product Read Surface
- source / system overview;
- evidence;
- intelligence search;
- 必要的 Vulnerability product mapper。
Slice G — Contract Gate
- OpenAPI validation;
- component tests;
- real DB integration;
- canonical Product E2E。
Workbench 在上述过程中继续可用,不作为重构 blocker。
30. API Review Checklist
每个新增 Product endpoint 必须回答:
- Query 还是 Command?
- Use Case owner 在哪里?
- 是否有隐藏副作用?
- sync 还是 async?
- 是否需要 Idempotency-Key?
- 是否需要 expected revision?
- DTO 是否泄漏 ORM / TaskEvent / ContextManifest?
- collection 是否有 pagination / bound?
- failure 是否有稳定 public code?
- request_id 是否能追到 TaskRun / Execution? 11.长任务为什么用 SSE / 为什么不需要 SSE? 12.页面刷新后是否只凭 stable resource ID 恢复? 13.是否存在 component / integration test?
- OpenAPI 是否同步?
31. 与 TD1 / TD2 的边界
TD1 不变
2A 不重新拥有 Source、Acquisition、Evidence、Knowledge、Incident、Projection、Retrieval、Artifact、M1–M3 reliability。
TD2 不变
2A 不重新拥有 TaskIntent、TaskContract、TaskRun、ContextManifest、InvestigationState、EvidenceNeed、Perception、Skill、Capability、Policy、Budget、Sandbox、Agent loop、DecisionResult、Replay、Telemetry seam。
2A 新增稳定 owner
仅新增:
Product Use Case
Product Command / Query
Public DTO / Read Model
Product Error Contract
Public Idempotency
ProductEvent / SSE
Product Health / Overview
Frontend server-state boundary
32. 设计原则摘要
2A 的目标不是“再加一层抽象”,而是消除三类已经出现的耦合。
HTTP 不侵入 Domain
Route 负责 transport,Use Case 负责产品编排,TD1/TD2 Runtime 持有业务 invariant。
Domain 不直接泄漏 Product Frontend
正式前端读取 Product View;内部 Task / Context / Event 留在 Workbench 或脱敏 RuntimeActivityView。
Product 行为必须有 owner
跨多个 domain service 的稳定产品动作不能长期散落在 route、worker 和前端。
最终稳定链路:
HTTP / SSE
→ Application Use Case
→ TD1 / TD2 Domain Port
→ Infrastructure
Domain State / Result
→ Application Read Model
→ Public DTO
→ Product Frontend
长任务:
Product Command
→ durable Case / TaskRun
→ 202 Accepted
→ internal TaskEvent / State Change
→ ProductEvent projection
→ SSE
→ frontend refreshes stable Read Model
Runtime Workbench 则保留另一条明确的工程观察链:
Workbench
→ diagnostic query / existing domain gate
→ internal Task / Context / State / Replay detail
这两条链共享真实系统,但不共享产品 contract。
33. 参考
以下资料用于补充 application/backend engineering practice,不覆盖 SecFusionAgent 自身 ownership:
- goldbergyoni/nodebestpractices https://github.com/goldbergyoni/nodebestpractices
- futurice/backend-best-practices https://github.com/futurice/backend-best-practices
- psenger/Best-Practices-For-Rest-API https://github.com/psenger/Best-Practices-For-Rest-API
- khasky/backend-architecture-playbook https://github.com/khasky/backend-architecture-playbook
- RFC 9457 — Problem Details for HTTP APIs https://www.rfc-editor.org/rfc/rfc9457
34. WORLD heterogeneous read projection — 2026-10-08
WORLD 的首轮重构采用以下读取边界。GET /api/v1/world/stories?limit=4..18 由 Application Query 组合既有 Document/Revision/Chunk、带 Observation 的开发对象/InternetAsset 和 durable Incident;不写 Knowledge、不启动 M4–M6、不产生新的研判。
DTO 返回原始 headline/excerpt、excerpt_origin、结构化 facts、source、对象/事件引用、published_at / happened_at / observed_at,以及 Observation / DocumentRevision / Chunk / locator。generated_at 是读取快照的测量时间。删除 prototype 的 narrative/why_it_matters、标题特判、AI 关键词评分、类别加权与 regex 摘要。类别来自 source inventory;宽泛 independent/incidents 源需要 accepted、未 supersede 的 Repo/ResearchWork 关系,或 registry 中已有 AI/model/Agent authority scope。source abstract 优先于普通 body,来源与类别交错是覆盖规则,不代表安全重要性评分。
每个文档只读最新 Revision;SQL 按来源限量,正文只读最终选中的文档。opaque SHA 和单纯身份不会伪装成有内容的变化。来源文字保持原语言,界面与类型表达由 Web 的中文/英文 presentation 持有;不把固定英文判断模板写进 Query。
WorldStoryReader 是进程内、可替换的 15 秒 read cache。冷读取由锁合并,响应深复制,测量时间保持不变。已有快照过期后立即返回原测量并用独立 session 后台更新;刷新失败保留原测量,shutdown 取消后台读取。API bootstrap 最多预热 5 秒;读取失败/超时会记录日志,其他 Product 路由继续可用。它不替代 durable Evidence authority,也不承担历史 WorldSnapshot/replay。
首屏只依赖 stories。Hot working set 后续独立读取,不能被当作已经晋升的 Knowledge;overview 与 formation 在故事首次读取后独立读取,overview 提供近 24h 的真实采集/变化/写入摘要;完整来源 health 仍在方向 inspect 中展开。DOM 叙事 + SVG 空间对象支持 reduced motion,不依赖 WebGL;邻近位置只表示共同处于观察世界,不虚构对象间关系。对象操作带既有 object/incident/CVE/question 坐标进入 dossier 或 START。技术坐标下沉至 inspect。
35. Product WORLD / START / dossier 联调收口 — 2026-10-08
WORLD 的 Hot read 保留排名窗口(64 条)并单独返回 resident_total,计数仅包含尚有 Redis payload 的驻留对象,排除排序/固定/访问等索引与过期成员。Web 每组展示八个真实对象,搜索明确限于已载入窗口;数量不是 Knowledge 留存数。来源方向、Hot 和阅读模式支持 URL 进入。
GET /api/v1/world/formation 从已有 ProcessingRun、cause Observation 与 KnowledgeRevision 读取最近富化处理;活动处理另行保留。只有存在 cause_processing_run_id 对应的 Knowledge 提交才显示“已写入知识”,success 本身不等于 canonical commit。字段属于 Application View,不新增业务 authority,不调用调查链。
Product Document read 新增最新修订第一个原始 Chunk 的 source_excerpt / excerpt_chunk_id / excerpt_locator。前端直接阅读节选,并保留原文入口;修订/索引/Observation 坐标折叠。世界来源材料可进入对象档案,再携带真实对象与可读标题进入 START。裸情报入口不再默认选择一个 CVE。
同步 QA 的逻辑模型超时在既有 Task/Execution 失败记录之后转为可重试 deadline_exceeded ProblemDetail,携带实际 run_id / timeout_seconds。不生成回答或异步成功状态。无目标检索若模型要求继续调查,则呈现选择目标的明确提示。
M5 对非 Vulnerability 对象采用 SourceInvestigationPlannerDecision(perceive / patch / wait / stop),不向模型开放只支持 CVE 的 EnrichmentRole v1 委派。实际能力限制同时进入受信 runtime invariant;Vulnerability 仍沿原委派协议运行。模型自行选择读取与 StatePatch,既有 M4 证据 gate 保持不变。此修复来自真实 ResearchWork 调查被误委派、因空 CVE 失败的联调记录。
Investigation Product View 另行返回 case_lifecycle(既有 durable Case owner 的状态),status 继续表示当前运行投影。回合 blocked/failed 不等于 Case 已关闭;开放 Case 的追问沿同一 Case 继续,取消权限使用真实 Case lifecycle + owner principal。真正 resolved/cancelled/closed 后的后续问题仍按原 session continuation 协议处理。这一差异来自真实 follow-up 联调,前端不再依据上一回合 failed 推断“创建新 Case”。
真实 VERIFY 联调还发现重复委派同一 EnrichmentRole 子任务时,子任务可能已经 completed,而父 InvestigationRole 再次进入 waiting_dependency,因此不会再收到可唤醒的终态事件。运行时现在读取委派结果中的子任务状态:已完成则立即读取当前 canonical Evidence 并继续本回合;失败、阻塞或取消则给出明确阻塞原因;只有仍在运行的子任务才进入事件驱动等待。子任务输出本身不被提升为事实。
2026-10-12 逻辑修正:上述失败、阻塞、取消或超时此前会直接阻塞父 TaskRun,使“工具失败改变后续动作”无法执行。现在子任务状态与停止原因作为无证据的 Percept 反馈给父规划器;可改查既有证据或其他已授权来源,重复无进展仍按上限停止。子任务失败不等于原问题已被否定,也不自动满足 EvidenceNeed。 执行环境缺少富化委派端口时也返回能力不可用的 Percept,允许同样的有界替代决策;目标越界仍是执行契约错误,不降级为可忽略的材料缺口。
同日收紧委派选择:规划器仅用调查绑定的目标对象类型决定是否开放 CVE 专用委派,关联上下文的漏洞对象不改变论文或仓库任务的 schema;混合目标任务使用不含 CVE 委派的安全路由。委派适配器再次核对目标是绑定的 Vulnerability 且 CVE 标识一致,拒绝伪造或错绑目标。
后续追查确认,旧委派 ID 包含 planner iteration 和 assembly hash,同一父任务在富化后刷新 Context 时会创建另一个语义相同的子任务。现将委派身份固定为父 TaskRun、目标对象/CVE 与标准维度集合,重放时复用已完成子任务;子任务保留创建时的 Knowledge 快照,父子 Context 修订变化不构成身份冲突。新的追问 TaskRun 仍可独立发起新一轮富化。
另一次真实 VERIFY 中,模型将 inferred reasoning_relation 的命题直接写入 confirmed,M4 State Gate 按既有规则拒绝。InvestigationRole 现在把拒绝原因作为下一轮规划反馈,受 no-progress 上限约束;模型可改写为有直接证据支撑的确认或保留为 tentative/hypothesis。拒绝本身不产生 Case 事实,也不再直接让整次 TaskRun 发生意外失败。
本轮真实论文联调进一步定位到 INSPECT 仅返回结构化投影、不返回已收录正文。已补充 document 物理读取算子:按精确 object_id 读取各文档最新 revision 的有序片段,最多 100 条,并携带该版本 Observation 对应的对象 EvidenceLink。缺失新版本片段时返回空结果,不混入旧正文;不创建新事实,也不绕过 StatePatch。真实 ResearchWork 感知已读到 20 个正文片段及 1 个持久证据引用。
2026-10-09 多轮 Bitget 调查暴露另一边界:模型把解释性长句放进 WAIT/STOP reason,超过 TaskRun stop_reason 的 128 字符存储契约,使已经确认事实的 Case 意外失败。Planner 在模型输出边界保留短机器码,对自由文本或过长原因使用有界停止/等待码;原有 Case 事实、未知项与模型调用记录仍按各自 owner 保留,终结与 M6 研判不再被存储长度错误截断。
同一会话在外部 Knowledge 已前进后继续 RETRIEVE,原路径将新检索结果与旧 M4 世界版本比较并报冲突,用户无法继续。现在 Product 在 Case-read 前检查 revision;若已过期,直接在同一 active Case 接受新的 InvestigationRole 回合,让 Perception 刷新 M4 后再做研判。查询意图规划期间发生版本变化时也落到同一续接路径。无显式目标的会话继续保留原 Case 和会话顺序;显式重绑仍走独立轻量读取。前端提交失败会清掉未保存的流式草稿,保留输入文字供重试。
该续接路径的真实运行又暴露 M6 交付缺口:M4 已确认 Chainalysis 的行动并记录 Bitget 自身措施未知,但 DecisionRole 仍返回 EvidenceNeed,用户没有报告。现在调查回合结束时,只要 M4 仍有未知项或开放 EvidenceNeed,就要求 M6 交付“已知事实 + 未知边界”的阶段性自然语言报告,并让 Case 保持 waiting 供后续追问;如果模型仍返回继续调查请求,使用仅含已确认事实和对应引用的有界报告兜底。QA 评测和权威结论仍以结构化 Decision 字段为准。
真实多轮会话还暴露历史渲染串位:所有共享同一 Case 的旧回合都从 Case 的 mutable latest_decision 读取最新报告。现在 M6 收口时通过父 InvestigationRole 的 request_id 将 Decision ID 回填至该会话回合的 decision_ref;问答记录只按此稳定引用展示对应报告和引用,Case 页面仍展示当前最新研判。旧回合无稳定引用时明确显示未单独归档,不把新报告冒充旧回答。
问答右侧审计轨迹同样按请求坐标收窄:TaskRun 摘要公开本次 Product request_id,前端将相同 request_id 的运行及其父子/前驱 DecisionRole 归入选中回合,事件随 TaskRun 过滤。Case 完整页仍保留所有回合的整体时间线。本地既有数据中可精确匹配的 9 个历史 Decision 已按父运行 trace_context 回填至所属会话回合。
36. 调查意图、关联取证与回合报告 — 2026-10-11
真实产品反馈暴露:从 Repo 档案进入问答并明确要求“调查关联证据、冲突、未知与外部上下文”,原自动路由因存在 object_id 而直接 LOOKUP;M6 将仓库语言、许可证和热度计数包装成“调查完成”。现由 Application 在已有稳定 object/CVE 或会话目标时识别明确的调查请求,携完整原问题进入 InvestigationRole。普通属性问题和“调查报告是什么”仍是读取;无稳定目标的自然语言问题仍先 RETRIEVE。正文重复当前 Case 的 CVE 可以继续同一 Case,真实换目标以及显式 API 重绑仍受既有生命周期约束。
M5 非漏洞规划指导升级为 investigation-model-v4-source:按问题需要追查双向关系、读取相关对象、检索简短项目名,批量写入相关事实,未覆盖维度写入 unknown,不能用元数据完成关系或安全调查。perception-planner-v2 在 TRACE/EXPAND 的 graph 步骤后追加依赖式证据读取;只沿此次返回的至多 20 条关系读取真实 EvidenceLink。读取额度按关系分配,在 SQL 限制候选行数并报告截断及实际读取次数;Percept 保留关联端点供后续导航。该动作不创建事实、不晋升候选、不绕开 M4 StatePatch gate。SEARCH 仍是本地索引搜索,不能被描述为实时外网检索。
M6 使用 decision-model-v6(不要求报告的调用使用 decision-model-v6-core),按完整问题判断证据充分性;报告首段说明重大覆盖缺口,空 conflicts/unknowns 列表不是不存在风险的证明,公开/未归档/stars 不能推导安全或维护质量。段落仍只能引用经过结构化结论验证的证据,旧 DecisionResult 保持不可变。
所有正常完成或受控 BLOCKED 的调查回合都可进入既有独立 DecisionRole 收口;FAILED/CANCELLED 不被改成成功。即使 M5 曾认为 EvidenceNeed 已解决,M6 新发现缺口时也先通过 M4 ContinuationGate 保留 Need,再以新 revision 提交可读阶段报告,两个操作在同一事务内完成。本轮问答绑定该不可变 Decision,Case 保持 waiting。非法 continuation target 仍被拒绝,并进入安全边界报告回退;任务重投不重复创建 Need/Decision。新报告包含 unknowns 时也保持 waiting,不因模型给出 final 就误报调查完成。
同一调查继续暴露 SEARCH 回传正文却遗漏已有 EvidenceLink 的问题。现在由 M3 公开读取接口按 chunk、DocumentRevision、object 和该 revision 的 Observation 精确绑定已存在引用,M5 的 lexical/dense Percept 同时携带段落与证据;不存在匹配 link 时仍留空,不借用新版本。文献支撑的发现必须归因原文,并以文档对象为 StatePatch target,不把论文提到仓库视为已经独立验证仓库安全状态。该链路经过原有 M4 支撑对象校验;不修改来源或自动晋升 canonical Knowledge。
真实运行进一步发现 StatePatch 拒绝反馈被 recent_percepts 遮蔽,模型看不到 target_ref 校验失败并重复同一写入直至 no_progress。Planner 现在合并最近来源 Percepts 和未重复的 last_percept;拒绝原因与可引用材料共同进入下一次 PromptAssembly。仅从已展示对象补全稳定 object 引用,relation ID 不会被自动改绑;结构化 schema 明示 target_ref 的对象/事件命名空间。完整 Role-loop 回归覆盖先拒绝、再纠正、最终只接受一个事实,M4 gate 保持原有严格性。
报告质量复查又发现模型选择 continuation 后,旧回退仅取最近三条事实,丢失更早且更相关的安全发现。Product 的已结束调查回合现使用 final-only InvestigationReportResponse,由同一次 M6 调用从全量 confirmed state 选择相关结论并组织段落;未检查维度写入 Decision unknowns,Case 保持 waiting。“交付报告”不等于“证据充分”。普通 QA/M6 调用保留 continuation,旧 continuation → Need → report 分支保留为非标准 provider 的防御兼容。新增 schema 与生命周期回归覆盖 M5 已解决原 Need、M6 仍发现覆盖缺口的情形。
本地真实问题复核已输出关联 PR、研究论文中的安全线索和清晰的待核实边界,报告自然段、固定来源版本、原文入口与会话回填均已走通;Case 保持 waiting。该检查是产品功能联调,不作为正式 QA 准确率或安全覆盖率结论;CVE/NVD、官方通告和版本修复状态仍需进一步取证。实现分批推送于 8c45072、60354f5、9396e24;详情阅读组件迭代为 831b8cb。