{
  "canonical_name": "smaramwbc/statewave",
  "compilation_id": "pack_7016fe2fc437412ea1d84e474f0a35ac",
  "created_at": "2026-05-15T10:19:39.365621+00:00",
  "created_by": "project-pack-compiler",
  "feedback": {
    "carrier_selection_notes": [
      "viable_asset_types=skill, recipe, host_instruction, eval, preflight",
      "recommended_asset_types=skill, recipe, host_instruction, eval, preflight"
    ],
    "evidence_delta": {
      "confirmed_claims": [
        "identity_anchor_present",
        "capability_and_host_targets_present",
        "install_path_declared_or_better"
      ],
      "missing_required_fields": [],
      "must_verify_forwarded": [
        "Run or inspect `pip install statewave` in an isolated environment.",
        "Confirm the project exposes the claimed capability to at least one target host."
      ],
      "quickstart_execution_scope": "allowlisted_sandbox_smoke",
      "sandbox_command": "pip install statewave",
      "sandbox_container_image": "python:3.12-slim",
      "sandbox_execution_backend": "docker",
      "sandbox_planner_decision": "deterministic_isolated_install",
      "sandbox_validation_id": "sbx_968016cc8dbf497b9cb78643d09f8afa"
    },
    "feedback_event_type": "project_pack_compilation_feedback",
    "learning_candidate_reasons": [],
    "template_gaps": []
  },
  "identity": {
    "canonical_id": "project_b26a8931ff89435971f628384405e8e3",
    "canonical_name": "smaramwbc/statewave",
    "homepage_url": null,
    "license": "unknown",
    "repo_url": "https://github.com/smaramwbc/statewave",
    "slug": "statewave",
    "source_packet_id": "phit_c21c5975d6ff484fbc49d5edaf419483",
    "source_validation_id": "dval_710ffdadb42e4d4ca81c22901be11584"
  },
  "merchandising": {
    "best_for": "需要软件开发与交付能力，并使用 local_cli的用户",
    "github_forks": 1,
    "github_stars": 217,
    "one_liner_en": "Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres.",
    "one_liner_zh": "Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres.",
    "primary_category": {
      "category_id": "software-development",
      "confidence": "medium",
      "name_en": "Software Development",
      "name_zh": "软件开发与交付",
      "reason": "matched_keywords:git, cli"
    },
    "target_user": "使用 local_cli 等宿主 AI 的用户",
    "title_en": "statewave",
    "title_zh": "statewave 能力包",
    "visible_tags": [
      {
        "label_en": "MCP Tools",
        "label_zh": "MCP 工具",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "product_domain-mcp-tools",
        "type": "product_domain"
      },
      {
        "label_en": "Knowledge Base Q&A",
        "label_zh": "知识库问答",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "user_job-knowledge-base-q-a",
        "type": "user_job"
      },
      {
        "label_en": "Structured Data Extraction",
        "label_zh": "结构化数据提取",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "core_capability-structured-data-extraction",
        "type": "core_capability"
      },
      {
        "label_en": "Automated Workflow",
        "label_zh": "自动化工作流",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "workflow_pattern-automated-workflow",
        "type": "workflow_pattern"
      },
      {
        "label_en": "Open Source Tool",
        "label_zh": "开源工具",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "selection_signal-open-source-tool",
        "type": "selection_signal"
      }
    ]
  },
  "packet_id": "phit_c21c5975d6ff484fbc49d5edaf419483",
  "page_model": {
    "artifacts": {
      "artifact_slug": "statewave",
      "files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json",
        "REPO_INSPECTION.md",
        "CAPABILITY_CONTRACT.json",
        "EVIDENCE_INDEX.json",
        "CLAIM_GRAPH.json"
      ],
      "required_files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json"
      ]
    },
    "detail": {
      "capability_source": "Project Hit Packet + DownstreamValidationResult",
      "commands": [
        {
          "command": "pip install statewave",
          "label": "Python / pip · 官方安装入口",
          "source": "https://github.com/smaramwbc/statewave#readme",
          "verified": true
        }
      ],
      "display_tags": [
        "MCP 工具",
        "知识库问答",
        "结构化数据提取",
        "自动化工作流",
        "开源工具"
      ],
      "eyebrow": "软件开发与交付",
      "glance": [
        {
          "body": "判断自己是不是目标用户。",
          "label": "最适合谁",
          "value": "需要软件开发与交付能力，并使用 local_cli的用户"
        },
        {
          "body": "先理解能力边界，再决定是否继续。",
          "label": "核心价值",
          "value": "Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres."
        },
        {
          "body": "未完成验证前保持审慎。",
          "label": "继续前",
          "value": "publish to Doramagic.ai project surfaces"
        }
      ],
      "guardrail_source": "Boundary & Risk Card",
      "guardrails": [
        {
          "body": "Prompt Preview 只展示流程，不证明项目已安装或运行。",
          "label": "Check 1",
          "value": "不要把试用当真实运行"
        },
        {
          "body": "local_cli",
          "label": "Check 2",
          "value": "确认宿主兼容"
        },
        {
          "body": "publish to Doramagic.ai project surfaces",
          "label": "Check 3",
          "value": "先隔离验证"
        }
      ],
      "mode": "skill, recipe, host_instruction, eval, preflight",
      "pitfall_log": {
        "items": [
          {
            "body": "README/documentation is current enough for a first validation pass.",
            "category": "能力坑",
            "evidence": [
              "capability.assumptions | github_repo:1219923941 | https://github.com/smaramwbc/statewave | README/documentation is current enough for a first validation pass."
            ],
            "severity": "medium",
            "suggested_check": "将假设转成下游验证清单。",
            "title": "能力判断依赖假设",
            "user_impact": "假设不成立时，用户拿不到承诺的能力。"
          },
          {
            "body": "未记录 last_activity_observed。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | last_activity_observed missing"
            ],
            "severity": "medium",
            "suggested_check": "补 GitHub 最近 commit、release、issue/PR 响应信号。",
            "title": "维护活跃度未知",
            "user_impact": "新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "downstream_validation.risk_items | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "进入安全/权限治理复核队列。",
            "title": "下游验证发现风险项",
            "user_impact": "下游已经要求复核，不能在页面中弱化。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "risks.scoring_risks | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "把风险写入边界卡，并确认是否需要人工复核。",
            "title": "存在评分风险",
            "user_impact": "风险会影响是否适合普通用户安装。"
          },
          {
            "body": "issue_or_pr_quality=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | issue_or_pr_quality=unknown"
            ],
            "severity": "low",
            "suggested_check": "抽样最近 issue/PR，判断是否长期无人处理。",
            "title": "issue/PR 响应质量未知",
            "user_impact": "用户无法判断遇到问题后是否有人维护。"
          },
          {
            "body": "release_recency=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | release_recency=unknown"
            ],
            "severity": "low",
            "suggested_check": "确认最近 release/tag 和 README 安装命令是否一致。",
            "title": "发布节奏不明确",
            "user_impact": "安装命令和文档可能落后于代码，用户踩坑概率升高。"
          }
        ],
        "source": "ProjectPitfallLog + ProjectHitPacket + validation + community signals",
        "summary": "发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。",
        "title": "踩坑日志"
      },
      "snapshot": {
        "contributors": 2,
        "forks": 1,
        "license": "unknown",
        "note": "站点快照，非实时质量证明；用于开工前背景判断。",
        "stars": 217
      },
      "source_url": "https://github.com/smaramwbc/statewave",
      "steps": [
        {
          "body": "不安装项目，先体验能力节奏。",
          "code": "preview",
          "title": "先试 Prompt"
        },
        {
          "body": "理解输入、输出、失败模式和边界。",
          "code": "manual",
          "title": "读说明书"
        },
        {
          "body": "把上下文交给宿主 AI 继续工作。",
          "code": "context",
          "title": "带给 AI"
        },
        {
          "body": "进入主力环境前先完成安装入口与风险边界验证。",
          "code": "verify",
          "title": "沙箱验证"
        }
      ],
      "subtitle": "Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres.",
      "title": "statewave 能力包",
      "trial_prompt": "# statewave - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 statewave 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的软件开发与交付任务。\n我常用的宿主 AI：Local CLI\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres. 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. page-overview：Overview - What is Statewave?。围绕“Overview - What is Statewave?”模拟一次用户任务，不展示安装或运行结果。\n2. page-getting-started：Getting Started。围绕“Getting Started”模拟一次用户任务，不展示安装或运行结果。\n3. page-architecture：System Architecture。围绕“System Architecture”模拟一次用户任务，不展示安装或运行结果。\n4. page-database-schema：Database Schema & Migrations。围绕“Database Schema & Migrations”模拟一次用户任务，不展示安装或运行结果。\n5. page-api-endpoints：API Endpoints Reference。围绕“API Endpoints Reference”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. page-overview\n输入：用户提供的“Overview - What is Statewave?”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. page-getting-started\n输入：用户提供的“Getting Started”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. page-architecture\n输入：用户提供的“System Architecture”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. page-database-schema\n输入：用户提供的“Database Schema & Migrations”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. page-api-endpoints\n输入：用户提供的“API Endpoints Reference”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / page-overview：Step 1 必须围绕“Overview - What is Statewave?”形成一个小中间产物，并等待用户确认。\n- Step 2 / page-getting-started：Step 2 必须围绕“Getting Started”形成一个小中间产物，并等待用户确认。\n- Step 3 / page-architecture：Step 3 必须围绕“System Architecture”形成一个小中间产物，并等待用户确认。\n- Step 4 / page-database-schema：Step 4 必须围绕“Database Schema & Migrations”形成一个小中间产物，并等待用户确认。\n- Step 5 / page-api-endpoints：Step 5 必须围绕“API Endpoints Reference”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/smaramwbc/statewave\n- https://github.com/smaramwbc/statewave#readme\n- README.md\n- server/domain/models.py\n- docker-compose.yml\n- alembic/env.py\n- server/app.py\n- server/main.py\n- server/services/__init__.py\n- server/core/dependencies.py\n- server/db/tables.py\n- alembic/versions\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 statewave 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "voices": [
        {
          "body": "来源平台：github。github/github_issue: policy_bundles: support cross-tenant bundle reuse via composite (tenant_（https://github.com/smaramwbc/statewave/issues/79）；github/github_release: v0.8.0（https://github.com/smaramwbc/statewave/releases/tag/v0.8.0）；github/github_release: v0.7.2（https://github.com/smaramwbc/statewave/releases/tag/v0.7.2）；github/github_release: v0.7.0: Admin Dashboard API（https://github.com/smaramwbc/statewave/releases/tag/v0.7.0）。这些是项目级外部声音，不作为单独质量证明。",
          "items": [
            {
              "kind": "github_issue",
              "source": "github",
              "title": "policy_bundles: support cross-tenant bundle reuse via composite (tenant_",
              "url": "https://github.com/smaramwbc/statewave/issues/79"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.8.0",
              "url": "https://github.com/smaramwbc/statewave/releases/tag/v0.8.0"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.7.2",
              "url": "https://github.com/smaramwbc/statewave/releases/tag/v0.7.2"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.7.0: Admin Dashboard API",
              "url": "https://github.com/smaramwbc/statewave/releases/tag/v0.7.0"
            }
          ],
          "status": "已收录 4 条来源",
          "title": "社区讨论"
        }
      ]
    },
    "homepage_card": {
      "category": "软件开发与交付",
      "desc": "Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres.",
      "effort": "安装已验证",
      "forks": 1,
      "icon": "code",
      "name": "statewave 能力包",
      "risk": "可发布",
      "slug": "statewave",
      "stars": 217,
      "tags": [
        "MCP 工具",
        "知识库问答",
        "结构化数据提取",
        "自动化工作流",
        "开源工具"
      ],
      "thumb": "gray",
      "type": "Skill Pack"
    },
    "manual": {
      "markdown": "# https://github.com/smaramwbc/statewave 项目说明书\n\n生成时间：2026-05-15 10:02:16 UTC\n\n## 目录\n\n- [Overview - What is Statewave?](#page-overview)\n- [Getting Started](#page-getting-started)\n- [System Architecture](#page-architecture)\n- [Database Schema & Migrations](#page-database-schema)\n- [API Endpoints Reference](#page-api-endpoints)\n- [Context Assembly & Ranking](#page-context-assembly)\n- [Compilation Services](#page-compilation-services)\n- [Embedding Services](#page-embeddings)\n- [Governance - Receipts & Policy Engine](#page-receipts-policy)\n- [Multi-tenancy & Security](#page-multi-tenancy)\n\n<a id='page-overview'></a>\n\n## Overview - What is Statewave?\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Getting Started](#page-getting-started)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n- [SUPPORT.md](https://github.com/smaramwbc/statewave/blob/main/SUPPORT.md)\n- [DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n- [CONTRIBUTING.md](https://github.com/smaramwbc/statewave/blob/main/CONTRIBUTING.md)\n- [scripts/bootstrap_docs_pack.py](https://github.com/smaramwbc/statewave/blob/main/scripts/bootstrap_docs_pack.py)\n- [scripts/docs_loader.py](https://github.com/smaramwbc/statewave/blob/main/scripts/docs_loader.py)\n- [scripts/eval/eval_docs_support.py](https://github.com/smaramwbc/statewave/blob/main/scripts/eval/eval_docs_support.py)\n- [server/starter_packs/statewave-support-agent/manifest.json](https://github.com/smaramwbc/statewave/blob/main/server/starter_packs/statewave-support-agent/manifest.json)\n</details>\n\n# Overview - What is Statewave?\n\nStatewave is a self-hosted **memory infrastructure** for AI agents. It enables AI systems to store, retrieve, compile, and reason over long-term contextual information across conversations and sessions.\n\n## Core Concept\n\nStatewave solves the memory problem for AI agents by providing:\n\n- **Episode Ingestion** — Capture events, conversations, and real-world signals as structured memory units\n- **Memory Compilation** — Transform raw episodes into refined, actionable memories using LLM or heuristic approaches\n- **Context Assembly** — Retrieve and rank relevant memories within token budgets for inference\n- **Temporal Reasoning** — Track state changes and resolution status over time\n\nThe system operates as a REST API service that agents and applications query to build persistent, evolving memory without hand-writing custom storage and retrieval logic for each use case.\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"Sources\"\n        MCP[MCP Server]\n        GH[GitHub]\n        MD[Markdown Docs]\n        SL[Slack]\n        APP[Application]\n    end\n\n    subgraph \"Statewave Core\"\n        INGEST[Ingestion API]\n        COMPILE[Memory Compiler]\n        SEARCH[Search API]\n        CONTEXT[Context Assembly]\n    end\n\n    subgraph \"Storage\"\n        PG[(PostgreSQL<br/>+ pgvector)]\n    end\n\n    MCP --> INGEST\n    GH --> INGEST\n    MD --> INGEST\n    SL --> INGEST\n    APP --> INGEST\n\n    INGEST --> PG\n    COMPILE --> PG\n    SEARCH --> PG\n    CONTEXT --> PG\n\n    APP --> SEARCH\n    APP --> CONTEXT\n```\n\n## Key Components\n\n| Component | Description |\n|-----------|-------------|\n| **Episodes** | Raw, append-only event records captured from sources (conversations, issues, documents, etc.) |\n| **Memories** | Compiled, refined knowledge derived from episodes through LLM or heuristic processing |\n| **Subjects** | Logical namespaces grouping episodes and memories (typically one per user, customer, or agent persona) |\n| **Resolutions** | Tracking of issue/session completion state per subject |\n| **Context Bundle** | Ranked, token-bounded response assembled from relevant memories for inference |\n\n## Data Flow\n\n```mermaid\ngraph LR\n    A[Source Event] --> B[POST /v1/episodes]\n    B --> C[(Episode Store)]\n    C --> D[POST /v1/memories/compile]\n    D --> E[(Memory Store)]\n    E --> F[GET /v1/memories/search]\n    F --> G[POST /v1/context]\n    G --> H[Ranked Context Bundle]\n```\n\n## API Reference\n\n### Core Endpoints\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/episodes` | Ingest a single episode (append-only) |\n| `POST` | `/v1/episodes/batch` | Ingest up to 100 episodes at once |\n| `POST` | `/v1/memories/compile` | Compile memories from episodes (idempotent) |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n\n### Subject Management\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n| `DELETE` | `/v1/subjects/{id}` | Permanently delete all data for a subject |\n| `GET` | `/v1/subjects/{id}/health` | Customer health score with explainable factors |\n| `GET` | `/v1/subjects/{id}/sla` | SLA metrics — response time, resolution time, breaches |\n\n### Resolution Tracking\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/resolutions` | Track issue resolution state per session |\n| `GET` | `/v1/resolutions` | List resolutions for a subject |\n\n### Additional Endpoints\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/handoff` | Generate compact handoff context pack |\n| `GET` | `/healthz` or `/health` | Liveness check |\n| `GET` | `/readyz` or `/ready` | Readiness check |\n\n资料来源：[README.md:26-49](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Connectors\n\nStatewave is not limited to live chat transcripts. **Connectors** feed real-world events into Statewave as episodes, enabling agents to build memory from diverse sources.\n\n| Source | Memory Shape | Status |\n|--------|--------------|--------|\n| MCP server | Copilot / Claude / Cursor / agent memory | ✅ Shipped |\n| GitHub | Issues, PRs, reviews, releases → repo memory | ✅ Shipped |\n| Markdown | Local docs, ADRs, RFCs → decision memory | ✅ Shipped |\n| Slack | Channel messages → conversation memory | ✅ Shipped |\n\n资料来源：[README.md:53-60](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Deployment\n\n### Docker Deployment\n\nStatewave is deployed as a containerized service using Docker Compose:\n\n```yaml\nservices:\n  app:\n    image: statewavedev/statewave:latest\n    ports: [\"8100:8100\"]\n    environment:\n      STATEWAVE_DATABASE_URL: postgresql+asyncpg://statewave:statewave@db:5432/statewave\n      STATEWAVE_LITELLM_API_KEY: sk-...\n    depends_on:\n      db:\n        condition: service_healthy\n```\n\n```bash\ndocker compose up -d\ncurl http://localhost:8100/healthz\n```\n\n资料来源：[DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n\n### Environment Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | — | PostgreSQL connection string (required) |\n| `STATEWAVE_LITELLM_API_KEY` | — | LiteLLM API key for LLM compilation |\n| `STATEWAVE_LOG_LEVEL` | `INFO` | Logging verbosity |\n| `STATEWAVE_MAX_CONTEXT_TOKENS` | `4000` | Default token budget for context assembly |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests/min/IP (0 = disabled) |\n| `STATEWAVE_WEBHOOK_URL` | — | Webhook callback URL |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Header for multi-tenant isolation |\n\n资料来源：[README.md:93-107](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Multi-Tenant Support\n\nStatewave supports multi-tenant deployments through application-layer isolation:\n\n- **Tenant Header**: `X-Tenant-ID` header identifies the tenant (configurable via `STATEWAVE_TENANT_HEADER`)\n- **Query-Scoped Isolation**: Data isolation is enforced at the query layer\n- **Per-Tenant Configuration**: Policy bundles and receipts support tenant-specific settings\n\n资料来源：[README.md:100-107](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Documentation System\n\nStatewave includes a documentation-grounded memory system:\n\n- Curated documentation sections are chunked at heading boundaries\n- Each section becomes an episode with `source=\"statewave-docs\"`, `type=\"doc_section\"`\n- Episodes carry a deterministic content hash for change detection\n- A bundled starter pack provides 276 episodes and 364 compiled memories out of the box\n\n资料来源：[scripts/docs_loader.py](https://github.com/smaramwbc/statewave/blob/main/scripts/docs_loader.py)\n资料来源：[server/starter_packs/statewave-support-agent/manifest.json](https://github.com/smaramwbc/statewave/blob/main/server/starter_packs/statewave-support-agent/manifest.json)\n\n## Evaluation Framework\n\nThe repository includes an evaluation framework for testing docs-grounded retrieval:\n\n```python\n@dataclass\nclass Question:\n    task: str\n    expected_doc_paths: list[str]\n    expected_terms: list[str]\n```\n\nSample evaluation questions verify that the system correctly surfaces documentation for queries about deployment, compilation modes, hardware requirements, and API contracts.\n\n资料来源：[scripts/eval/eval_docs_support.py](https://github.com/smaramwbc/statewave/blob/main/scripts/eval/eval_docs_support.py)\n\n## Starter Packs\n\nStatewave ships with pre-built starter packs:\n\n| Pack | Description |\n|------|-------------|\n| `statewave-support-agent` | Full Statewave Support docs pack with 276 episodes and 364 memories |\n| `demo-support-agent` | Support agent persona |\n| `demo-coding-assistant` | Coding assistant persona |\n| `demo-sales-copilot` | Sales copilot persona |\n| `demo-devops-agent` | DevOps agent persona |\n| `demo-research-assistant` | Research assistant persona |\n\n资料来源：[server/starter_packs/statewave-support-agent/manifest.json](https://github.com/smaramwbc/statewave/blob/main/server/starter_packs/statewave-support-agent/manifest.json)\n资料来源：[scripts/build_demo_packs.py](https://github.com/smaramwbc/statewave/blob/main/scripts/build_demo_packs.py)\n\n## Health Monitoring\n\nStatewave provides subject-level health monitoring:\n\n- **Health Score**: Aggregated customer health with explainable factors\n- **SLA Metrics**: Response time, resolution time, and breach tracking\n- **Snapshot Restore**: Restore subject state from snapshots with timestamp shifting\n\n资料来源：[README.md:46-47](https://github.com/smaramwbc/statewave/blob/main/README.md)\n资料来源：[server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n\n## Getting Started\n\n1. **Quick Start**:\n   ```bash\n   docker compose up db -d\n   python -m venv .venv && source .venv/bin/activate\n   pip install -e \".[dev,llm]\"\n   alembic upgrade head\n   uvicorn server.main:app --host 0.0.0.0 --port 8100\n   ```\n\n2. **Run Tests**:\n   ```bash\n   # Unit tests (no DB required)\n   pytest tests/test_*.py -v\n\n   # Integration tests (requires Postgres)\n   PGPASSWORD=statewave createdb -h localhost -U statewave statewave_test\n   pytest tests/integration/ -v\n   ```\n\n资料来源：[CONTRIBUTING.md](https://github.com/smaramwbc/statewave/blob/main/CONTRIBUTING.md)\n资料来源：[README.md:11-19](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Current Limitations\n\n| Limitation | Description |\n|------------|-------------|\n| Rate limiting per-IP | Distributed (Postgres-backed), but keyed by IP only, not per-tenant or per-API-key |\n| Multi-tenant app-layer | Query-scoped data isolation + per-tenant config, but no Postgres RLS |\n\n资料来源：[README.md:117-122](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Repository Structure\n\n| Repository | Purpose |\n|------------|---------|\n| [statewave](https://github.com/smaramwbc/statewave) | Backend API, server, core |\n| [statewave-py](https://github.com/smaramwbc/statewave-py) | Python SDK (`pip install statewave`) |\n| [statewave-ts](https://github.com/smaramwbc/statewave-ts) | TypeScript SDK (`npm install @statewavedev/sdk`) |\n| [statewave-connectors](https://github.com/smaramwbc/statewave-connectors) | Connectors (GitHub, Markdown, MCP, etc.) |\n| [statewave-docs](https://github.com/smaramwbc/statewave-docs) | Documentation |\n| [statewave-examples](https://github.com/smaramwbc/statewave-examples) | Working code examples |\n| [statewave-web](https://github.com/smaramwbc/statewave-web) | Marketing site + embedded demo |\n| [statewave-admin](https://github.com/smaramwbc/statewave-admin) | Admin dashboard |\n\n资料来源：[SUPPORT.md:73-83](https://github.com/smaramwbc/statewave/blob/main/SUPPORT.md)\n\n---\n\n<a id='page-getting-started'></a>\n\n## Getting Started\n\n### 相关页面\n\n相关主题：[Overview - What is Statewave?](#page-overview), [API Endpoints Reference](#page-api-endpoints)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n- [DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n- [helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n- [scripts/bootstrap_docs_pack.py](https://github.com/smaramwbc/statewave/blob/main/scripts/bootstrap_docs_pack.py)\n- [scripts/seed_demo_subjects.py](https://github.com/smaramwbc/statewave/blob/main/scripts/seed_demo_subjects.py)\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n</details>\n\n# Getting Started\n\n## Overview\n\nThe Getting Started guide provides developers and operators with the essential knowledge to install, configure, and run Statewave — an agent memory system that captures, compiles, and retrieves episodic and semantic memory for AI agents. The guide covers three primary deployment paths: Docker Compose for local development, Helm charts for Kubernetes production environments, and Python packages for programmatic integration.\n\nStatewave operates as an append-only memory store where **episodes** represent raw events (chat messages, commits, support tickets) and **memories** are compiled, high-confidence knowledge units derived from episodes through LLM or heuristic processing. The system enables agents to assemble token-bounded context bundles for RAG (Retrieval-Augmented Generation) workflows.\n\n资料来源：[README.md:1-50]()\n\n## System Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Ingestion Layer\"\n        E[Episodes] --> B[Batch Ingest]\n        E --> S[Single Ingest]\n    end\n    \n    subgraph \"Compilation Layer\"\n        S --> COMP[Memory Compiler]\n        B --> COMP\n        COMP -->|LLM or Heuristic| M[Memories]\n    end\n    \n    subgraph \"Retrieval Layer\"\n        M --> CX[Context Assembler]\n        Q[Query] --> CX\n        CX --> CB[Token-Bounded Context]\n    end\n    \n    subgraph \"Storage Layer\"\n        M --> PG[(PostgreSQL)]\n        E --> PG\n    end\n    \n    subgraph \"Connectors\"\n        MCP[MCP Server]\n        GH[GitHub]\n        MD[Markdown]\n        SL[Slack]\n        MCP --> E\n        GH --> E\n        MD --> E\n        SL --> E\n    end\n```\n\n## Prerequisites\n\nBefore beginning the installation, ensure the following requirements are met:\n\n| Requirement | Minimum Version | Purpose |\n|-------------|-----------------|---------|\n| Python | 3.11+ | SDK and CLI usage |\n| Docker | 24.0+ | Container runtime |\n| Docker Compose | 2.20+ | Multi-container orchestration |\n| PostgreSQL | 15+ | Primary data store |\n| Kubernetes | 1.28+ | Production deployment |\n| Helm | 3.14+ | Chart package manager |\n\n资料来源：[DOCKER.md:1-30]()\n\n## Installation Methods\n\n### Quick Start with Docker Compose\n\nThe fastest path to a running Statewave instance uses Docker Compose:\n\n```yaml\n# docker-compose.yml\nservices:\n  api:\n    image: statewavedev/statewave:latest\n    ports: [\"8100:8100\"]\n    environment:\n      STATEWAVE_DATABASE_URL: postgresql+asyncpg://statewave:statewave@db:5432/statewave\n      STATEWAVE_LITELLM_API_KEY: sk-...\n    depends_on:\n      db:\n        condition: service_healthy\n\nvolumes:\n  pgdata:\n```\n\n资料来源：[DOCKER.md:40-55]()\n\nExecute the following commands to start Statewave:\n\n```bash\n# Start the stack\ndocker compose up -d\n\n# Verify health\ncurl http://localhost:8100/healthz\n```\n\n### Pinning a Specific Version\n\nProduction deployments should pin to a specific version:\n\n```bash\nSTATEWAVE_VERSION=0.7.0 docker compose up -d\n```\n\nAvailable tagging conventions:\n\n| Tag Pattern | Meaning |\n|-------------|---------|\n| `latest` | Tip of `main` branch |\n| `X.Y.Z` | Specific semver release |\n| `X.Y` | Latest in the minor line |\n| `X` | Latest in the major line |\n| `sha-<7>` | Specific git commit |\n\n资料来源：[DOCKER.md:70-85]()\n\n### Verify Build Attestation\n\nFor supply chain security, verify the container image:\n\n```bash\ngh attestation verify \\\n  oci://docker.io/statewavedev/statewave:latest \\\n  --owner smaramwbc\n```\n\n资料来源：[DOCKER.md:90-95]()\n\n## Environment Configuration\n\nStatewave uses environment variables for all configuration. The following table documents the complete set:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | — | PostgreSQL connection string (required) |\n| `STATEWAVE_LITELLM_API_KEY` | — | LLM provider API key |\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Embedding backend (`litellm`, `openai`, `stub`) |\n| `STATEWAVE_COMPILER_TYPE` | `llm` | Compilation method (`llm` or `heuristic`) |\n| `STATEWAVE_AUTH_API_KEY` | — | Static API key for authentication |\n| `STATEWAVE_PORT` | `8100` | HTTP server port |\n| `STATEWAVE_LOG_LEVEL` | `INFO` | Logging verbosity |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests per minute per IP |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | `distributed` (Postgres) or `memory` |\n| `STATEWAVE_WEBHOOK_URL` | — | Callback URL for async events |\n| `STATEWAVE_WEBHOOK_TIMEOUT` | `5.0` | Webhook HTTP timeout (seconds) |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Multi-tenant isolation header |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Enforce tenant header presence |\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Token budget for context assembly |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n\n资料来源：[README.md:180-200]()\n\n## API Endpoints\n\n### Health and Readiness\n\n| Endpoint | Method | Purpose |\n|----------|--------|---------|\n| `/healthz` | GET | Liveness check |\n| `/health` | GET | Liveness check (alias) |\n| `/readyz` | GET | Readiness check |\n| `/ready` | GET | Readiness check (alias) |\n\n### Core Memory Operations\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/v1/episodes` | Ingest a single episode (append-only) |\n| `POST` | `/v1/episodes/batch` | Ingest up to 100 episodes at once |\n| `POST` | `/v1/memories/compile` | Compile memories from episodes (idempotent) |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n| `DELETE` | `/v1/subjects/{id}` | Permanently delete all data for a subject |\n\n### Advanced Operations\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/v1/resolutions` | Track issue resolution state per session |\n| `GET` | `/v1/resolutions` | List resolutions for a subject |\n| `POST` | `/v1/handoff` | Generate compact handoff context pack |\n| `GET` | `/v1/subjects/{id}/health` | Customer health score with explainable factors |\n| `GET` | `/v1/subjects/{id}/sla` | SLA metrics — response time, resolution time, breaches |\n\n资料来源：[README.md:30-60]()\n\n## Connectors Ecosystem\n\nStatewave supports external data sources through modular connectors:\n\n```bash\n# Install connectors individually\nnpm install @statewavedev/connectors-github\nnpm install @statewavedev/connectors-markdown\nnpm install @statewavedev/connectors-slack\nnpm install @statewavedev/connectors-n8n\nnpm install @statewavedev/connectors-zapier\nnpm install @statewavedev/mcp-server\n\n# Meta-package for all connectors\nnpm install @statewavedev/connectors\n```\n\nAvailable connectors and their status:\n\n| Source | Memory Shape | Status |\n|--------|--------------|--------|\n| MCP Server | Copilot/Claude/Cursor/agent memory | ✅ Shipped |\n| GitHub | Issues, PRs, reviews, releases → repo memory | ✅ Shipped |\n| Markdown | Local docs, ADRs, RFCs → decision memory | ✅ Shipped |\n| Slack | Channel conversations | ✅ Shipped |\n\n资料来源：[README.md:250-280]()\n\n### Connector Usage Examples\n\n```bash\n# Sync GitHub data (dry-run first)\nstatewave-connectors sync github \\\n  --repo smaramwbc/statewave \\\n  --subject repo:smaramwbc/statewave \\\n  --dry-run\n\n# Sync Markdown documentation\nstatewave-connectors sync markdown \\\n  --path ./docs \\\n  --subject repo:smaramwbc/statewave \\\n  --dry-run\n\n# Start MCP server\nstatewave-connectors mcp start\n```\n\n## Kubernetes Deployment\n\nFor production environments, use the Helm chart:\n\n```bash\nhelm install statewave ./helm/statewave \\\n  --set database.url='postgresql+asyncpg://...' \\\n  --set llm.apiKey='sk-...' \\\n  --set auth.apiKey='replace-me'\n```\n\nThe Helm chart runs a pre-install Job (`alembic upgrade head`) before any API pod admits traffic. Upgrades repeat migration as a pre-upgrade Job.\n\n资料来源：[helm/statewave/README.md:1-40]()\n\n### Helm Configuration Reference\n\n| Value | Default | Notes |\n|-------|---------|-------|\n| `image.tag` | `\"\"` | Falls back to `Chart.AppVersion` |\n| `replicaCount` | `1` | Check connection-budget math before raising |\n| `database.url` / `database.existingSecret` | — | One is **required** |\n| `compiler.type` | `llm` | `heuristic` for demo/no-LLM mode |\n| `embedding.provider` | `litellm` | `stub` for demo/no-embedding mode |\n| `llm.apiKey` / `llm.existingSecret` | — | Required when `compiler.type=llm` |\n| `auth.apiKey` / `auth.existingSecret` | — | Strongly recommended in production |\n\n资料来源：[helm/statewave/README.md:50-70]()\n\n## Running Tests\n\nStatewave includes unit tests (no database required) and integration tests (requires PostgreSQL):\n\n```bash\n# Unit tests\npytest tests/test_*.py -v\n\n# Integration tests\nPGPASSWORD=statewave createdb -h localhost -U statewave statewave_test\npytest tests/integration/ -v\n\n# All tests\npytest tests/ -v\n```\n\n资料来源：[README.md:210-220]()\n\n## Bootstrap Documentation Pack\n\nAfter initial deployment, bootstrap the documentation memory pack for a self-hosted support agent:\n\n```bash\npython -m scripts.bootstrap_docs_pack [--docs-path PATH] [--purge] [--dry-run]\n```\n\n### Environment Variables for Bootstrap\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `STATEWAVE_URL` | `http://localhost:8100` | API base URL |\n| `STATEWAVE_API_KEY` | — | Authentication key |\n| `STATEWAVE_DOCS_PATH` | — | Override documentation path |\n\n### Bootstrap Behavior\n\n```mermaid\ngraph LR\n    A[Read statewave-docs corpus] --> B[Ingest each section as Episode]\n    B --> C[Compile Episodes to Memories]\n    C --> D[Assemble docs-grounded Knowledge Base]\n    D --> E[Support Agent queries via POST /v1/context]\n    \n    F[--purge] -.->|Wipe and rebuild| A\n    G[--dry-run] -.->|No ingestion| A\n```\n\nThe bootstrap process is idempotent. By default, it fails if the subject already has episodes. Re-run with `--purge` to wipe and rebuild from scratch.\n\n资料来源：[scripts/bootstrap_docs_pack.py:1-50]()\n\n## Seed Demo Subjects\n\nFor development and testing, seed demo subjects with sample data:\n\n```bash\npython -m scripts.seed_demo_subjects [--dry-run]\n```\n\nThis creates sample episodes and memories that reference each other, enabling verification of the compilation and retrieval pipeline.\n\n资料来源：[scripts/seed_demo_subjects.py:1-60]()\n\n## Current Limitations\n\nStatewave v0.8.0 has known limitations:\n\n| Limitation | Description |\n|------------|-------------|\n| Rate limiting | Per-IP only — not yet per-tenant or per-API-key |\n| Multi-tenant isolation | App-layer query-scoped isolation — no Postgres RLS yet |\n\n资料来源：[README.md:225-235]()\n\n## Next Steps\n\n| Resource | Purpose |\n|----------|---------|\n| [API v1 contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md) | Complete API reference |\n| [Connector docs](https://github.com/smaramwbc/statewave-docs/blob/main/connectors/index.md) | Connector configuration |\n| [Horizontal Scaling Guide](https://github.com/smaramwbc/statewave-docs/blob/main/deployment/horizontal-scaling.md) | Production scaling guidance |\n| [Architecture documentation](https://github.com/smaramwbc/statewave-docs/blob/main/architecture/ranking.md) | Context ranking internals |\n\n---\n\n<a id='page-architecture'></a>\n\n## System Architecture\n\n### 相关页面\n\n相关主题：[Overview - What is Statewave?](#page-overview), [Database Schema & Migrations](#page-database-schema), [Compilation Services](#page-compilation-services)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n- [server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/api/timeline.py](https://github.com/smaramwbc/statewave/blob/main/server/api/timeline.py)\n- [server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n- [server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n- [server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n- [DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n</details>\n\n# System Architecture\n\nStatewave is an AI agent memory system designed to ingest real-world events as episodes, compile them into structured memories, and retrieve ranked, token-bounded context for agentic workflows. The system follows a layered architecture with clear separation between API handling, business logic services, data persistence, and external connectors.\n\n## High-Level Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"External Clients\"\n        A[Agents / Applications]\n        B[Connectors: GitHub, Slack, MCP]\n        C[SDK Clients]\n    end\n\n    subgraph \"API Layer\"\n        D[FastAPI Application]\n        E[Endpoint Routes]\n        F[Middleware / Auth]\n    end\n\n    subgraph \"Service Layer\"\n        G[Episode Service]\n        H[Memory Service]\n        I[Compiler Service]\n        J[Search Service]\n        K[Snapshot Service]\n    end\n\n    subgraph \"Data Layer\"\n        L[(PostgreSQL)]\n        M[(Vector Embeddings)]\n        N[Starter Packs]\n    end\n\n    A --> D\n    B --> D\n    C --> D\n    D --> F\n    F --> E\n    E --> G\n    E --> H\n    E --> I\n    E --> J\n    E --> K\n    G --> L\n    H --> L\n    H --> M\n    I --> L\n    J --> M\n    K --> L\n    K --> N\n```\n\n## Core Data Models\n\n### Episode\n\nAn **Episode** represents a discrete unit of experience — a chat message, a support ticket update, a GitHub issue event, or a documentation section. Episodes are the atomic ingestion unit in Statewave.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique identifier |\n| `subject_id` | UUID | Parent subject this episode belongs to |\n| `session_id` | str | Session context identifier |\n| `type` | str | Kind of episode (e.g., `doc_section`, `chat`, `ticket`) |\n| `source` | str | Origin system (e.g., `github`, `slack`, `statewave-docs`) |\n| `content` | str | Raw content body |\n| `metadata_` | dict | Arbitrary key-value metadata |\n| `provenance` | dict | Source-specific tracking (e.g., `content_hash` for docs) |\n| `created_at` | datetime | Ingestion timestamp |\n| `valid_from` | datetime | Temporal anchor for memory derivation |\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n### Memory\n\nA **Memory** is a compiled, structured artifact extracted from one or more episodes. Memories have temporal validity windows, confidence scores, and lineage tracking.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique identifier |\n| `subject_id` | UUID | Parent subject |\n| `kind` | str | Memory category (e.g., `episode_summary`, `profile_fact`, `decision`) |\n| `content` | str | Compiled memory content |\n| `summary` | str | Short summary (max 200 chars) |\n| `confidence` | float | Confidence score (0.0-1.0) |\n| `valid_from` | datetime | Start of validity window |\n| `valid_to` | datetime | End of validity window (nullable) |\n| `source_episode_ids` | list[UUID] | Episodes this memory was derived from |\n| `status` | str | Memory lifecycle state |\n| `sensitivity_labels` | list[str] | Optional sensitivity classification |\n\n资料来源：[server/api/timeline.py](https://github.com/smaramwbc/statewave/blob/main/server/api/timeline.py)\n\n### Subject\n\nA **Subject** is the central entity in Statewave — a persona, entity, or concept that accumulates memory over time.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique identifier |\n| `tenant_id` | str | Multi-tenant isolation key |\n| `name` | str | Human-readable name |\n| `type_` | str | Subject type classification |\n| `metadata_` | dict | Arbitrary metadata |\n| `embedding` | vector | Semantic embedding for similarity search |\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n## API Layer\n\n### REST API v1\n\nThe API is served by FastAPI on port 8100 by default and exposes OpenAPI documentation at `/docs` and ReDoc at `/redoc`.\n\n```mermaid\ngraph LR\n    A[Client] --> B[\"POST /v1/episodes\"]\n    A --> C[\"POST /v1/episodes/batch\"]\n    A --> D[\"POST /v1/memories/compile\"]\n    A --> E[\"GET /v1/memories/search\"]\n    A --> F[\"POST /v1/context\"]\n    A --> G[\"GET /v1/timeline\"]\n    A --> H[\"GET /v1/subjects\"]\n    A --> I[\"DELETE /v1/subjects/{id}\"]\n    A --> J[\"POST /v1/resolutions\"]\n    A --> K[\"POST /v1/handoff\"]\n    A --> L[\"GET /v1/subjects/{id}/health\"]\n    A --> M[\"GET /v1/subjects/{id}/sla\"]\n```\n\n### Core Endpoints\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/episodes` | Ingest a single episode (append-only) |\n| `POST` | `/v1/episodes/batch` | Ingest up to 100 episodes at once |\n| `POST` | `/v1/memories/compile` | Compile memories from episodes (idempotent) |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n| `DELETE` | `/v1/subjects/{id}` | Permanently delete all data for a subject |\n| `POST` | `/v1/resolutions` | Track issue resolution state per session |\n| `GET` | `/v1/resolutions` | List resolutions for a subject |\n| `POST` | `/v1/handoff` | Generate compact handoff context pack |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n### Health Endpoints\n\n| Endpoint | Purpose |\n|----------|---------|\n| `GET /healthz` or `GET /health` | Liveness check |\n| `GET /readyz` or `GET /ready` | Readiness check |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Service Layer\n\n### Compiler Service\n\nThe compiler extracts memories from episodes. Statewave supports two compilation modes:\n\n| Mode | Description | Use Case |\n|------|-------------|----------|\n| `llm` | Uses an LLM provider (via LiteLLM) to extract structured memories | Production with semantic understanding |\n| `heuristic` | Rule-based extraction for basic facts and summaries | Demo mode, no API key required |\n\n#### Heuristic Compiler\n\nThe heuristic compiler extracts two memory kinds from episodes:\n\n1. **episode_summary**: A 500-character truncation of the episode text with 0.8 confidence\n2. **profile_fact**: Extracted profile facts with 0.6 confidence\n\n```python\nMemoryRow(\n    kind=\"episode_summary\",\n    content=text[:500],\n    summary=text[:200],\n    confidence=0.8,\n    valid_from=ep_valid_from,\n    valid_to=compute_valid_to(\"episode_summary\", ep_valid_from, ttl),\n    source_episode_ids=[ep.id],\n    status=\"active\",\n)\n```\n\n资料来源：[server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n\n#### Temporal Anchoring\n\nThe compiler determines episode temporal anchors with the following priority:\n\n1. `payload.event_time` — Explicit client override for historical data replay\n2. `payload.messages[0].timestamp` — First message timestamp in chat-shaped payloads (used by LoCoMo, Slack, Zendesk connectors)\n3. `created_at` — Fallback to ingestion timestamp\n\n```mermaid\ngraph TD\n    A[Episode Ingestion] --> B{event_time present?}\n    B -->|Yes| C[Use event_time]\n    B -->|No| D{messages timestamp present?}\n    D -->|Yes| E[Use messages[0].timestamp]\n    D -->|No| F[Use created_at]\n```\n\n资料来源：[server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n\n### Snapshot Service\n\nSnapshots enable point-in-time restoration of subject data, including episodes, memories, and resolutions.\n\n| Feature | Description |\n|---------|-------------|\n| Create Snapshot | Captures all subject data with version metadata |\n| Restore Snapshot | Clones data with optional time-shifting for temporal consistency |\n| Metadata Tracking | Records `restored_from_snapshot` in restored records |\n\n```python\nsnapshot = SubjectSnapshotRow(\n    name=name,\n    version=version,\n    source_subject_id=snapshot_subject,\n    episode_count=len(eps),\n    memory_count=len(mems),\n    metadata_=metadata or {},\n)\n```\n\n资料来源：[server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n\n### Timeline Service\n\nThe timeline service provides chronological event merging across episodes and resolutions within a session.\n\n```mermaid\ngraph TD\n    A[Session Request] --> B[Fetch Episodes]\n    A --> C[Fetch Resolutions]\n    B --> D[Merge Events Chronologically]\n    C --> D\n    D --> E[TimelineResponse]\n    \n    E --> F[TimelineEpisodeEvent]\n    E --> G[TimelineResolutionEvent]\n    \n    F --> H[id]\n    F --> I[source]\n    F --> J[type]\n    F --> K[payload]\n    F --> L[created_at]\n    F --> M[citing_memory_count]\n    \n    G --> N[resolved_at]\n    G --> O[status]\n```\n\n#### Timeline Response Model\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `session_id` | str | Session identifier |\n| `status` | str | Overall session status |\n| `first_message_at` | str | Timestamp of first user message |\n| `first_response_at` | str | Timestamp of first agent response |\n| `resolved_at` | str | Resolution timestamp |\n| `first_response_seconds` | float | Time to first response |\n| `resolution_seconds` | float | Total resolution time |\n| `first_response_breached` | bool | SLA breach indicator |\n| `resolution_breached` | bool | Resolution SLA breach indicator |\n| `episode_count` | int | Total episodes in session |\n| `events` | list | Chronologically merged events |\n\n资料来源：[server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n\n### Handoff Service\n\nThe handoff endpoint generates compact context packs for transferring conversation context between agents or sessions.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `subject_id` | UUID | Yes | Target subject |\n| `session_id` | str | No | Optional session context |\n| `reason` | str | No | Handoff reason |\n| `max_tokens` | int | No | Token budget for context |\n| `caller_id` | str | Conditional | Required when tenant config mandates it |\n| `caller_type` | str | Conditional | Required when tenant config mandates it |\n\n资料来源：[server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n\n## Data Layer\n\n### Database Schema\n\nStatewave uses PostgreSQL with SQLAlchemy async for data persistence. Key tables:\n\n| Table | Purpose |\n|-------|---------|\n| `subjects` | Central entity registry with embeddings |\n| `episodes` | Raw experience ingestion records |\n| `memories` | Compiled memory artifacts with validity windows |\n| `resolutions` | Issue resolution tracking per session |\n| `policy_bundles` | Immutable policy YAML bundles |\n| `policy_receipts` | Compliance receipts for policy enforcement |\n| `subject_snapshots` | Point-in-time backup metadata |\n\n### Multi-Tenancy\n\nMulti-tenant isolation is implemented at the application layer:\n\n| Configuration | Default | Description |\n|---------------|--------|-------------|\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Header for multi-tenant isolation |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant header |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n> **Current Limitation**: Multi-tenant isolation is query-scoped (application-layer) with no PostgreSQL Row-Level Security (RLS) enforcement.\n\n## Connectors\n\nConnectors feed external data sources into Statewave as episodes without requiring custom ingestion code.\n\n```mermaid\ngraph LR\n    A[GitHub] -->|Issues, PRs, Reviews| B[Connector]\n    C[Slack] -->|Messages, Threads| B\n    D[MCP Server] -->|Agent Memory| B\n    E[Markdown] -->|Docs, RFCs| B\n    F[n8n] -->|Workflow Events| B\n    G[Zapier] -->|Automation Triggers| B\n    \n    B --> H[Episodes]\n    H --> I[Statewave API]\n```\n\n### Available Connectors\n\n| Source | Memory Shape | Status |\n|--------|--------------|--------|\n| MCP Server | Copilot / Claude / Cursor / agent memory | ✅ Shipped |\n| GitHub | Issues, PRs, reviews, releases → repo memory | ✅ Shipped |\n| Markdown | Local docs, ADRs, RFCs → decision memory | ✅ Shipped |\n| Slack | Channel messages → conversation memory | ✅ Shipped |\n| n8n | Workflow events → process memory | ✅ Shipped |\n| Zapier | Automation triggers → event memory | ✅ Shipped |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | — | PostgreSQL connection string (required) |\n| `STATEWAVE_LITELLM_API_KEY` | — | LiteLLM API key for LLM compilation |\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Embedding provider |\n| `STATEWAVE_COMPILER_TYPE` | `llm` | Compiler mode: `llm` or `heuristic` |\n| `STATEWAVE_API_KEY` | — | API authentication key |\n| `STATEWAVE_PORT` | `8100` | HTTP server port |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests/min/IP (0 = disabled) |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | `distributed` (Postgres) or `memory` |\n| `STATEWAVE_WEBHOOK_URL` | — | Webhook callback URL |\n| `STATEWAVE_WEBHOOK_TIMEOUT` | `5.0` | Webhook HTTP timeout (seconds) |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Tenant isolation header |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant |\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Default token budget for context |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Deployment\n\n### Docker Deployment\n\nStatewave is distributed as a Docker image and can be deployed using Docker Compose.\n\n```yaml\nservices:\n  statewave:\n    image: statewavedev/statewave:latest\n    ports: [\"8100:8100\"]\n    environment:\n      STATEWAVE_DATABASE_URL: postgresql+asyncpg://statewave:statewave@db:5432/statewave\n      STATEWAVE_LITELLM_API_KEY: sk-...\n    depends_on:\n      db:\n        condition: service_healthy\n```\n\n#### Image Tags\n\n| Tag | Meaning |\n|-----|---------|\n| `latest` | Tip of `main` |\n| `X.Y.Z` | Semver release |\n| `X.Y` | Latest in the minor line |\n| `X` | Latest in the major line |\n| `sha-<7>` | Specific commit |\n\n资料来源：[DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n\n### Helm Chart\n\nKubernetes deployment is supported via Helm:\n\n| Value | Default | Notes |\n|-------|---------|-------|\n| `image.tag` | `\"\"` | Falls back to Chart.AppVersion |\n| `replicaCount` | `1` | See horizontal scaling guide |\n| `database.url` | — | Required |\n| `database.existingSecret` | — | Alternative to url |\n| `compiler.type` | `llm` | `heuristic` for demo mode |\n| `embedding.provider` | `litellm` | `stub` for no-embedding mode |\n| `llm.apiKey` | — | Required for LLM mode |\n| `auth.apiKey` | — | Recommended for production |\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n## Testing\n\n### Test Execution\n\n```bash\n# Unit tests (no DB required)\npytest tests/test_*.py -v\n\n# Integration tests (requires Postgres)\nPGPASSWORD=statewave createdb -h localhost -U statewave statewave_test\npytest tests/integration/ -v\n\n# All tests\npytest tests/ -v\n```\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n<a id='page-database-schema'></a>\n\n## Database Schema & Migrations\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Governance - Receipts & Policy Engine](#page-receipts-policy)\n\n<details>\n<summary>Relevant Source Files</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n- [alembic/env.py](https://github.com/smaramwbc/statewave/blob/main/alembic/env.py)\n- [alembic/versions](https://github.com/smaramwbc/statewave/blob/main/alembic/versions)\n- [server/db/engine.py](https://github.com/smaramwbc/statewave/blob/main/server/db/engine.py)\n- [server/services/backup.py](https://github.com/smaramwbc/statewave/blob/main/server/services/backup.py)\n- [alembic/versions/0016_memory_status_tombstoned.py](https://github.com/smaramwbc/statewave/blob/main/alembic/versions/0016_memory_status_tombstoned.py)\n</details>\n\n# Database Schema & Migrations\n\n## Overview\n\nThe Statewave application uses PostgreSQL as its primary data store, managed through SQLAlchemy ORM with Alembic for schema migrations. The database layer provides persistent storage for the core domain entities: **Subjects**, **Episodes**, **Memories**, **Resolutions**, and **Snapshots**.\n\nAll tables use UUID v4 as primary keys and include automatic timestamp tracking (`created_at`, `updated_at`) with timezone-aware `DateTime(timezone=True)` columns. The schema is designed to support multi-tenant isolation through a `tenant_id` column on relevant entities.\n\n资料来源：[server/db/tables.py]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Database Layer\"\n        T[PostgreSQL]\n        ORM[SQLAlchemy ORM]\n        MIG[Alembic Migrations]\n    end\n    \n    subgraph \"Core Tables\"\n        SUBJ[subjects]\n        EP[episodes]\n        MEM[memories]\n        RES[resolutions]\n        SNAP[snapshots]\n        POL[policy_bundles]\n        SES[sessions]\n    end\n    \n    T --> ORM\n    ORM --> SUBJ\n    ORM --> EP\n    ORM --> MEM\n    ORM --> RES\n    ORM --> SNAP\n    ORM --> POL\n    ORM --> SES\n    \n    MIG -.->|manage schema| T\n```\n\n## Core Table Definitions\n\n### subjects\n\nThe central entity representing a user, entity, or concept that episodes and memories are associated with.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | `uuid.uuid4()` | Primary key |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `name` | String(512) | Yes | — | Display name |\n| `metadata_` | JSONB | No | `{}` | Flexible metadata |\n| `version` | Integer | No | `1` | Optimistic locking |\n| `created_at` | DateTime | No | `server_default=func.now()` | Creation timestamp |\n| `updated_at` | DateTime | No | `server_default + onupdate` | Last modification |\n\n资料来源：[server/db/tables.py]()\n\n### episodes\n\nImmutable event records representing interactions, activities, or data points fed into the system via connectors.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `subject_id` | UUID | No | — | FK → subjects |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `source` | String(64) | No | — | Origin (e.g., `slack`, `github`, `mcp`) |\n| `type` | String(64) | No | — | Event type (e.g., `doc_section`, `chat_message`) |\n| `payload` | JSONB | No | — | Raw event data |\n| `metadata_` | JSONB | No | `{}` | Extracted metadata |\n| `provenance` | JSONB | No | `{}` | Source attribution (hashes, URLs) |\n| `occurred_at` | DateTime | Yes | — | When the event actually occurred |\n| `created_at` | DateTime | No | Auto | Ingestion timestamp |\n| `session_id` | UUID | Yes | — | Optional session grouping |\n\n资料来源：[server/db/tables.py]()\n资料来源：[server/services/context.py]()\n\n### memories\n\nCompiled, semantically indexed summaries derived from episodes. Memories have temporal validity windows and confidence scores.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `subject_id` | UUID | No | — | FK → subjects |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `kind` | String(32) | No | — | Memory category (e.g., `episode_summary`, `profile_fact`) |\n| `content` | Text | No | — | Full memory content |\n| `summary` | String(512) | Yes | — | Abbreviated summary |\n| `confidence` | Float | No | — | LLM-assigned confidence (0.0-1.0) |\n| `valid_from` | DateTime | No | — | When the memory becomes relevant |\n| `valid_to` | DateTime | Yes | — | When the memory expires (TTL) |\n| `source_episode_ids` | Array[UUID] | Yes | — | Episodes this memory was compiled from |\n| `embedding` | Array[Float] | Yes | — | Vector embedding for semantic search |\n| `metadata_` | JSONB | No | `{}` | Additional metadata |\n| `status` | String(32) | No | — | `active`, `superseded`, or `tombstoned` |\n| `sensitivity_labels` | Array[String] | Yes | — | Privacy/classification labels |\n| `created_at` | DateTime | No | Auto | Creation timestamp |\n| `updated_at` | DateTime | No | Auto | Last modification |\n\n资料来源：[server/db/tables.py]()\n\n**Status Values:**\n\n| Status | Description |\n|--------|-------------|\n| `active` | Currently valid and usable |\n| `superseded` | Replaced by a newer memory covering the same scope |\n| `tombstoned` | Soft-deleted, retained for audit trail |\n\n资料来源：[alembic/versions/0016_memory_status_tombstoned.py]()\n\n### resolutions\n\nTracks issue or conversation resolution state per session.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `subject_id` | UUID | No | — | FK → subjects |\n| `session_id` | UUID | No | — | Session identifier |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `status` | String(32) | No | — | Resolution status |\n| `resolution_summary` | Text | Yes | — | Summary of resolution |\n| `resolved_at` | DateTime | Yes | — | When resolution occurred |\n| `metadata_` | JSONB | No | `{}` | Additional metadata |\n| `created_at` | DateTime | No | Auto | Creation timestamp |\n| `updated_at` | DateTime | No | Auto | Last modification |\n\n资料来源：[server/db/tables.py]()\n资料来源：[server/services/snapshots.py]()\n\n### subject_snapshots\n\nImmutable snapshots capturing a point-in-time state of a subject for backup/restore purposes.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `name` | String(512) | No | — | Snapshot name |\n| `version` | Integer | No | — | Snapshot version |\n| `source_subject_id` | UUID | No | — | Original subject being snapshotted |\n| `episode_count` | Integer | No | — | Number of episodes captured |\n| `memory_count` | Integer | No | — | Number of memories captured |\n| `metadata_` | JSONB | No | `{}` | Snapshot metadata |\n| `created_at` | DateTime | No | Auto | Creation timestamp |\n\n资料来源：[server/db/tables.py]()\n\n### policy_bundles\n\nImmutable policy YAML bundles content-addressed by `bundle_hash`.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `bundle_hash` | String(64) | No | — | SHA-256 content hash (indexed) |\n| `yaml_content` | Text | No | — | Full YAML policy content |\n| `active` | Boolean | No | `False` | Whether this bundle is active |\n| `tenant_id` | String(256) | Yes | — | Tenant isolation |\n\n资料来源：[server/db/tables.py]()\n\n**Design Note:** Composite unique index on `(tenant_id, bundle_hash) NULLS NOT DISTINCT` ensures one bundle per (scope, content) combination while allowing multiple tenants to install the same policy independently.\n\n## Migration System\n\nStatewave uses **Alembic** for database schema versioning. Migrations are located in the `alembic/versions/` directory and follow a sequential naming convention (e.g., `0016_memory_status_tombstoned.py`).\n\n### Migration Workflow\n\n```mermaid\ngraph LR\n    A[Development] --> B[Create Migration]\n    B --> C[Review SQL]\n    C --> D[Apply: alembic upgrade head]\n    D --> E[Production Deploy]\n    E --> F[Rollback if needed: alembic downgrade]\n```\n\n### Migration Naming Convention\n\nMigrations use the format `XXXX_<short_description>.py` where `XXXX` is a zero-padded sequence number. This ensures deterministic ordering across distributed development.\n\n### Migration Example: Status Rename\n\nThe migration `0016_memory_status_tombstoned.py` demonstrates the migration pattern:\n\n```python\n\"\"\"memories.status — rename `deleted` to `tombstoned` (defensive)\n\nRevision ID: 0016_memory_status_tombstoned\nRevises: 0015_episode_occurred_at\nCreate Date: 2026-05-10\n```\n\n**Purpose:**\n1. Normalize any existing `deleted` values to `tombstoned`\n2. Align vocabulary with issue #49 (State-assembly receipts specify `supersession_status: active | superseded | tombstoned`)\n3. Provide a visible breadcrumb for future developers tracing the change\n\n资料来源：[alembic/versions/0016_memory_status_tombstoned.py]()\n\n### Key Migration Characteristics\n\n| Characteristic | Description |\n|----------------|-------------|\n| **Reversible** | All migrations include `downgrade` paths |\n| **Idempotent checks** | Migrations verify existing state before modifying |\n| **Server defaults** | Timestamps use `server_default=func.now()` for consistency |\n| **Zero-downtime aware** | Helm chart runs pre-upgrade Jobs for migrations |\n\n## Data Import/Export\n\nThe backup service (`server/services/backup.py`) provides import/export functionality that serializes and deserializes subjects, episodes, and memories.\n\n### Import Process\n\n```mermaid\ngraph TD\n    A[JSON Archive] --> B[Parse episodes_data]\n    B --> C[Parse memories_data]\n    C --> D[Resolve subject_id]\n    D --> E[Insert Episodes]\n    E --> F[Insert Memories]\n    F --> G[Return Import Result]\n    \n    E -->|preserve_ids| E1[Use original UUIDs]\n    E -->|new_ids| E2[Generate new UUIDs]\n```\n\n**Import Flow:**\n1. Validate archive structure\n2. Resolve target `subject_id` based on `conflict_strategy`\n3. Insert episodes with optional ID preservation\n4. Insert memories with source episode ID remapping\n5. Commit transaction\n\n资料来源：[server/services/backup.py]()\n\n### Snapshot Restore Process\n\nSnapshots preserve the complete state of a subject including temporal offsets:\n\n```python\n# Timestamp shifting during restore\ntime_shift = restore_time - snapshot.created_at\nvalid_from = mem_valid_from + time_shift\nvalid_to = (mem_valid_to + time_shift) if mem_valid_to else None\n```\n\nThe `metadata_` field receives `\"restored_from_snapshot\": str(snapshot_id)` for audit tracking.\n\n资料来源：[server/services/snapshots.py]()\n\n## Schema Design Patterns\n\n### Temporal Modeling\n\nMemories use `valid_from` and `valid_to` columns for temporal validity:\n\n```python\ndef compute_valid_to(kind: str, valid_from: datetime, ttl: dict) -> datetime | None:\n    \"\"\"Compute expiration based on memory kind TTL.\"\"\"\n    ttl_hours = ttl.get(kind, DEFAULT_TTL_HOURS)\n    return valid_from + timedelta(hours=ttl_hours)\n```\n\n资料来源：[server/services/compilers/heuristic.py]()\n\n### Temporal Anchoring\n\nThe system extracts temporal anchors from episodes with priority:\n\n1. `payload.event_time` — explicit client override\n2. `payload.messages[0].timestamp` — first message timestamp in chat payloads\n3. `created_at` — fallback to ingestion time\n\n资料来源：[server/services/compilers/heuristic.py]()\n\n### JSONB Flexibility\n\nColumns like `payload`, `metadata_`, and `provenance` use PostgreSQL's `JSONB` type for schema flexibility:\n\n- **payload**: Raw event data varying by source connector\n- **metadata_**: Extracted structured data\n- **provenance**: Source attribution with content hashes\n\nThis allows the system to evolve connectors without schema migrations.\n\n### Composite Indexes\n\nKey indexes for query performance:\n\n| Index | Columns | Purpose |\n|-------|---------|---------|\n| `policy_bundles.bundle_hash` | `bundle_hash` | Content-addressed lookups |\n| `memories.subject_id + kind` | (implied) | Subject memory filtering |\n| `episodes.subject_id + occurred_at` | (implied) | Timeline queries |\n\n## See Also\n\n- [API v1 Contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md) — Database operations via REST API\n- [Deployment Guide](https://github.com/smaramwbc/statewave-docs/blob/main/deployment/guide.md) — Database configuration\n- [Helm Chart Configuration](../helm/statewave/README.md) — Migration job settings\n\n---\n\n<a id='page-api-endpoints'></a>\n\n## API Endpoints Reference\n\n### 相关页面\n\n相关主题：[Context Assembly & Ranking](#page-context-assembly)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/api/episodes.py](https://github.com/smaramwbc/statewave/blob/main/server/api/episodes.py)\n- [server/api/memories.py](https://github.com/smaramwbc/statewave/blob/main/server/api/memories.py)\n- [server/api/context.py](https://github.com/smaramwbc/statewave/blob/main/server/api/context.py)\n- [server/api/subjects.py](https://github.com/smaramwbc/statewave/blob/main/server/api/subjects.py)\n- [server/api/resolutions.py](https://github.com/smaramwbc/statewave/blob/main/server/api/resolutions.py)\n- [server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n- [server/api/sla.py](https://github.com/smaramwbc/statewave/blob/main/server/api/sla.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n- [server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n</details>\n\n# API Endpoints Reference\n\n## Overview\n\nThe Statewave API provides a comprehensive set of RESTful endpoints for managing agent memory, tracking session context, and enabling multi-tenant workspace isolation. The API is built on FastAPI and follows OpenAPI standards with automatic documentation at `/docs` (Swagger UI) and `/redoc` (ReDoc).\n\n**Base URL:** `http://localhost:8100`\n\n**API Version:** v1\n\nAll endpoints support multi-tenant isolation through the `X-Tenant-ID` header, configurable via the `STATEWAVE_TENANT_HEADER` environment variable. The API enforces query-scoped data isolation for multi-tenant deployments. 资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n## Health & Readiness\n\n### Liveness Check\n\n```\nGET /healthz\nGET /health\n```\n\nReturns `200 OK` when the service is running. Use this for basic liveness probes in container orchestration.\n\n### Readiness Check\n\n```\nGET /readyz\nGET /ready\n```\n\nReturns `200 OK` when the service is ready to accept traffic, including database connectivity validation.\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n## Episodes API\n\nEpisodes are the atomic, append-only units of memory ingestion. Each episode represents a discrete event, message, or interaction associated with a subject.\n\n### Ingest Single Episode\n\n```\nPOST /v1/episodes\n```\n\nIngests a single episode under a subject. The episode is stored with provenance metadata and becomes available for memory compilation.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"session_id\": \"string (optional)\",\n  \"source\": \"string (e.g., 'live-chat', 'mcp-server', 'github')\",\n  \"type\": \"string (e.g., 'message', 'doc_section', 'issue')\",\n  \"payload\": {\n    \"messages\": [...],\n    \"event_time\": \"ISO8601 datetime (optional)\"\n  },\n  \"metadata\": {},\n  \"provenance\": {\n    \"content_hash\": \"string (optional)\"\n  }\n}\n```\n\n### Batch Ingest Episodes\n\n```\nPOST /v1/episodes/batch\n```\n\nIngests up to 100 episodes in a single request. This is the recommended endpoint for bulk data loading or connector imports.\n\n**Request Body:**\n```json\n{\n  \"episodes\": [\n    { /* Episode object */ }\n  ]\n}\n```\n\n**Constraints:**\n- Maximum 100 episodes per batch\n- Each episode requires a valid `subject_id`\n- All episodes are processed atomically\n\n资料来源：[server/api/episodes.py](https://github.com/smaramwbc/statewave/blob/main/server/api/episodes.py)\n\n---\n\n## Memories API\n\nMemories are compiled, queryable representations derived from episodes through the heuristic or LLM compiler.\n\n### Compile Memories\n\n```\nPOST /v1/memories/compile\n```\n\nTriggers memory compilation from episodes. This operation is idempotent—re-running compiles only processes new episodes.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"force\": false\n}\n```\n\n### Search Memories\n\n```\nGET /v1/memories/search\n```\n\nSearches memories by kind, text content, or semantic similarity.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `subject_id` | string | required | Target subject UUID |\n| `kind` | string | - | Filter by memory kind (e.g., `episode_summary`, `profile_fact`) |\n| `q` | string | - | Full-text search query |\n| `limit` | int | 50 | Maximum results (1-200) |\n| `offset` | int | 0 | Pagination offset |\n\n### Memory Evolution Tracking\n\nThe system maintains memory lineage through `source_episode_ids` relationships, enabling:\n- **Supersession**: When new memories deprecate older ones\n- **Sibling relationships**: Memories derived from the same source episodes\n- **Provenance tracing**: Track which episodes contributed to each memory\n\n资料来源：[server/api/memories.py](https://github.com/smaramwbc/statewave/blob/main/server/api/memories.py)\n\n---\n\n## Context API\n\nThe context API assembles ranked, token-bounded context bundles optimized for LLM consumption.\n\n### Assemble Context\n\n```\nPOST /v1/context\n```\n\nGenerates a ranked context bundle suitable for passing to an LLM. The system considers:\n- Memory relevance and confidence scores\n- Token budget constraints (configurable via `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS`)\n- Temporal validity of memories\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"query\": \"string (optional)\",\n  \"max_tokens\": 4000,\n  \"include_episodes\": false,\n  \"kinds\": [\"episode_summary\", \"profile_fact\"]\n}\n```\n\n**Response:**\n```json\n{\n  \"subject_id\": \"string\",\n  \"query\": \"string\",\n  \"context\": \"string (assembled text)\",\n  \"token_count\": 1234,\n  \"memories_included\": [\n    {\n      \"id\": \"string\",\n      \"kind\": \"string\",\n      \"content\": \"string\",\n      \"summary\": \"string\",\n      \"confidence\": 0.8\n    }\n  ]\n}\n```\n\nThe context assembly uses a scoring algorithm that weighs relevance, recency, and confidence to produce optimal results within the token budget. 资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n---\n\n## Subjects API\n\nSubjects are the primary entity representing a user, session, or workspace that maintains memory.\n\n### List Subjects\n\n```\nGET /v1/subjects\n```\n\nReturns all subjects with episode and memory counts.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `tenant_id` | string | - | Filter by tenant (for multi-tenant deployments) |\n| `limit` | int | 50 | Results per page (1-200) |\n| `offset` | int | 0 | Pagination offset |\n\n### Delete Subject\n\n```\nDELETE /v1/subjects/{id}\n```\n\nPermanently deletes all episodes, memories, and resolutions for a subject. This operation is irreversible.\n\n**Path Parameters:**\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `id` | UUID | Subject identifier |\n\n### Get Subject Health\n\n```\nGET /v1/subjects/{id}/health\n```\n\nReturns a customer health score with explainable factors based on recent activity, resolution rates, and memory density.\n\n### Get Subject SLA\n\n```\nGET /v1/subjects/{id}/sla\n```\n\nReturns SLA metrics including:\n- Response time\n- Resolution time\n- SLA breaches\n\n资料来源：[server/api/subjects.py](https://github.com/smaramwbc/statewave/blob/main/server/api/subjects.py)\n\n---\n\n## Timeline API\n\n### Get Subject Timeline\n\n```\nGET /v1/timeline\n```\n\nReturns a chronological timeline of events for a subject.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `subject_id` | UUID | required | Target subject |\n| `session_id` | string | - | Filter by session |\n| `limit` | int | 50 | Maximum events |\n| `offset` | int | 0 | Pagination offset |\n\n**Response includes:**\n- Episode events with full payload and metadata\n- Resolution events with status transitions\n- Temporal metadata (first/last message timestamps)\n- SLA breach indicators\n\n资料来源：[server/api/timeline.py](https://github.com/smaramwbc/statewave/blob/main/server/api/timeline.py)\n\n---\n\n## Resolutions API\n\nResolutions track issue resolution state per session, enabling workflow tracking and SLA measurement.\n\n### Create Resolution\n\n```\nPOST /v1/resolutions\n```\n\nRecords a resolution event for a session.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"session_id\": \"string\",\n  \"status\": \"resolved | escalated | pending\",\n  \"resolution_summary\": \"string (optional)\",\n  \"metadata\": {}\n}\n```\n\n### List Resolutions\n\n```\nGET /v1/resolutions\n```\n\nLists resolutions for a subject.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `subject_id` | UUID | required | Target subject |\n| `session_id` | string | - | Filter by session |\n| `status` | string | - | Filter by status |\n\n资料来源：[server/api/resolutions.py](https://github.com/smaramwbc/statewave/blob/main/server/api/resolutions.py)\n\n---\n\n## Handoff API\n\n### Generate Handoff Context\n\n```\nPOST /v1/handoff\n```\n\nGenerates a compact, self-contained context pack for transferring conversation context between agents or sessions.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"session_id\": \"string (optional)\",\n  \"include_full_history\": false,\n  \"max_tokens\": 2000\n}\n```\n\nThis endpoint produces a lightweight JSON payload containing:\n- Recent memory summaries\n- Pending context items\n- Session state indicators\n- Structured for immediate agent consumption\n\n资料来源：[server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n\n---\n\n## SLA API\n\n### Get SLA Metrics\n\n```\nGET /v1/subjects/{id}/sla\n```\n\nReturns structured SLA metrics for monitoring and reporting.\n\n**Response:**\n```json\n{\n  \"subject_id\": \"string\",\n  \"period\": \"string (e.g., '30d')\",\n  \"response_time_p50\": 120.5,\n  \"response_time_p95\": 450.0,\n  \"resolution_time_avg\": 1800.0,\n  \"total_sessions\": 150,\n  \"resolved_sessions\": 142,\n  \"breach_count\": 8,\n  \"breach_rate\": 0.053\n}\n```\n\n资料来源：[server/api/sla.py](https://github.com/smaramwbc/statewave/blob/main/server/api/sla.py)\n\n---\n\n## Admin API\n\nThe admin endpoints provide extended visibility and management capabilities for system operators.\n\n### List Episodes (Admin)\n\n```\nGET /admin/subjects/{subject_id}/episodes\n```\n\nAdministrative endpoint for listing episodes with pagination.\n\n### List Citing Memories\n\n```\nGET /admin/subjects/{subject_id}/episodes/{episode_id}/citing-memories\n```\n\nReturns all memories that cite a specific episode as a source. This enables reverse provenance lookup.\n\n### List All Subjects (Admin)\n\n```\nGET /admin/subjects\n```\n\nAdministrative listing of all subjects with optional pagination.\n\n### Import Subject Data\n\n```\nPOST /admin/import\n```\n\nImports episodes and memories for a subject from JSONL format.\n\n### Export Subject Data\n\n```\nGET /admin/subjects/{id}/export\n```\n\nExports all subject data (episodes, memories, resolutions) to JSONL format.\n\n### Create Snapshot\n\n```\nPOST /admin/snapshots\n```\n\nCreates a point-in-time snapshot of a subject's state.\n\n### Restore Snapshot\n\n```\nPOST /admin/snapshots/{id}/restore\n```\n\nRestores a subject from a previously created snapshot.\n\n### List Snapshots\n\n```\nGET /admin/snapshots\n```\n\nLists available snapshots with metadata.\n\n资料来源：[server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n\n---\n\n## Request/Response Schemas\n\n### Core Request Schema Fields\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `subject_id` | UUID | Yes | Target subject identifier |\n| `session_id` | string | No | Associated session |\n| `source` | string | No | Origin of data (e.g., 'mcp-server', 'github') |\n| `type` | string | No | Data type discriminator |\n| `payload` | object | Yes | Type-specific payload data |\n| `metadata` | object | No | Arbitrary metadata |\n| `provenance` | object | No | Source tracking information |\n\n### Core Response Schema Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique resource identifier |\n| `created_at` | ISO8601 | Creation timestamp |\n| `updated_at` | ISO8601 | Last modification timestamp |\n| `status` | string | Resource status (active, archived, etc.) |\n\n资料来源：[server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n\n---\n\n## API Flow Diagram\n\n```mermaid\ngraph TD\n    A[Client] -->|POST /v1/episodes| B[Episodes API]\n    A -->|POST /v1/memories/compile| C[Memory Compiler]\n    A -->|GET /v1/memories/search| D[Memory Search]\n    A -->|POST /v1/context| E[Context Assembler]\n    \n    B --> F[(PostgreSQL<br/>episodes table)]\n    C --> G[Heuristic or LLM Compiler]\n    G --> H[(PostgreSQL<br/>memories table)]\n    D --> H\n    E --> H\n    E --> I[Ranked Context Bundle]\n    \n    A -->|GET /v1/timeline| J[Timeline Service]\n    J --> F\n    J --> H\n    \n    A -->|POST /v1/resolutions| K[(PostgreSQL<br/>resolutions table)]\n    \n    A -->|POST /v1/handoff| L[Handoff Generator]\n    L --> H\n    L --> M[Compact Handoff Pack]\n```\n\n---\n\n## Environment Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | required | PostgreSQL connection string |\n| `STATEWAVE_API_KEY` | - | API authentication key |\n| `STATEWAVE_LITELLM_API_KEY` | - | LLM provider API key |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Multi-tenant isolation header |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant header |\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Token budget for context assembly |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests per minute per IP |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | Rate limiting strategy |\n| `STATEWAVE_WEBHOOK_URL` | - | Webhook callback URL |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n## OpenAPI Documentation\n\nInteractive API documentation is available at:\n\n| URL | Format |\n|-----|--------|\n| `http://localhost:8100/docs` | Swagger UI |\n| `http://localhost:8100/redoc` | ReDoc |\n\nFull API contract documentation: [API v1 contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md)\n\n---\n\n<a id='page-context-assembly'></a>\n\n## Context Assembly & Ranking\n\n### 相关页面\n\n相关主题：[API Endpoints Reference](#page-api-endpoints), [Embedding Services](#page-embeddings), [Governance - Receipts & Policy Engine](#page-receipts-policy)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n- [server/api/context.py](https://github.com/smaramwbc/statewave/blob/main/server/api/context.py)\n- [server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n</details>\n\n# Context Assembly & Ranking\n\nContext Assembly & Ranking is the core mechanism that transforms raw episodic memory into a curated, token-bounded context bundle for LLM consumption. When an agent queries Statewave for context, the system retrieves relevant memories and episodes, scores them by relevance, and assembles them within a configurable token budget.\n\n## Architecture Overview\n\nThe context assembly system operates as a multi-stage pipeline:\n\n1. **Retrieval** — Query memories and episodes by subject, kind, text, or semantic similarity\n2. **Scoring** — Assign relevance scores to each item using configurable strategies\n3. **Ranking** — Sort items by score and enforce token budget constraints\n4. **Assembly** — Build the final context bundle with proper formatting and ordering\n\n```mermaid\ngraph TD\n    A[Client Request: POST /v1/context] --> B[ContextService.assemble]\n    B --> C[Retrieve Memories by Query]\n    B --> D[Retrieve Episodes by Query]\n    C --> E[_ScoredItem Scoring Loop]\n    D --> E\n    E --> F[Apply Ranking Strategy]\n    F --> G[Token Budget Enforcement]\n    G --> H[Context Bundle Response]\n    \n    E -->|score, kind, text, section| E\n```\n\n## Core Data Model\n\n### `_ScoredItem` Class\n\nThe fundamental unit used throughout the ranking pipeline is the `_ScoredItem` class, defined in `server/services/context.py`:\n\n```python\nclass _ScoredItem:\n    \"\"\"An item (memory or episode) with its computed relevance score.\"\"\"\n\n    __slots__ = (\"score\", \"kind\", \"memory_row\", \"episode_row\", \"text\", \"section\")\n\n    def __init__(\n        self,\n        score: float,\n        kind: str,\n        text: str,\n        section: str,\n        memory_row: Any = None,\n        episode_row: Any = None,\n    ) -> None:\n        self.score = score\n        self.kind = kind\n        self.memory_row = memory_row\n        self.episode_row = episode_row\n        self.text = text\n        self.section = section\n```\n\n| Attribute | Type | Description |\n|-----------|------|-------------|\n| `score` | `float` | Computed relevance score (higher = more relevant) |\n| `kind` | `str` | Item type: `\"memory\"` or `\"episode\"` |\n| `memory_row` | `Any` | `MemoryRow` instance when `kind == \"memory\"` |\n| `episode_row` | `Any` | `EpisodeRow` instance when `kind == \"episode\"` |\n| `text` | `str` | Extracted text content for scoring |\n| `section` | `str` | Section identifier for display/breadcrumb |\n\n资料来源：[server/services/context.py:49-67]()\n\n### Memory Response Model\n\nWhen context is assembled, memories are returned with full provenance:\n\n```python\nMemoryResponse(\n    id=m.id,\n    subject_id=m.subject_id,\n    kind=m.kind,\n    content=m.content,\n    summary=m.summary,\n    confidence=m.confidence,\n    valid_from=m.valid_from,\n    valid_to=m.valid_to,\n    source_episode_ids=m.source_episode_ids or [],\n    metadata=m.metadata_,\n    status=m.status,\n    sensitivity_labels=list(m.sensitivity_labels or []),\n    created_at=m.created_at,\n    updated_at=m.updated_at,\n)\n```\n\n资料来源：[server/api/timeline.py:1-20]()\n\n## Context Assembly Flow\n\n### Endpoint: `POST /v1/context`\n\nAssembles a ranked, token-bounded context bundle from a subject's episodic memory.\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant API as /v1/context\n    participant ContextService\n    participant MemoryStore\n    participant EpisodeStore\n\n    Client->>API: POST /v1/context {subject_id, query, max_tokens}\n    API->>ContextService: assemble(request)\n    ContextService->>MemoryStore: search_memories(query)\n    MemoryStore-->>ContextService: [MemoryRow...]\n    ContextService->>EpisodeStore: search_episodes(query)\n    EpisodeStore-->>ContextService: [EpisodeRow...]\n    ContextService->>ContextService: score_and_rank(items)\n    ContextService->>ContextService: enforce_token_budget(items, max_tokens)\n    ContextService-->>API: ContextResponse\n    API-->>Client: 200 OK\n```\n\n### Token Budget Enforcement\n\nThe system enforces a configurable token budget via the `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` environment variable (default: 4000 tokens). This ensures that:\n\n- Large subjects don't overwhelm LLM context windows\n- The most relevant items are prioritized\n- Lower-scored items are truncated when budget is exhausted\n\n| Parameter | Default | Description |\n|-----------|---------|-------------|\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Default token budget for context assembly |\n\n资料来源：[README.md:1-100]()\n\n## Ranking Strategies\n\nThe ranking system supports multiple strategies that can be applied in combination:\n\n### 1. Semantic Similarity Ranking\n\nFor queries with semantic intent, memories are ranked by vector similarity against the query embedding. This is the default strategy when using `kind=\"semantic\"` in search requests.\n\n### 2. Confidence-Based Ranking\n\nMemories include a `confidence` field (0.0–1.0) that reflects the compiler's certainty. Higher-confidence memories are ranked higher by default.\n\n| Memory Kind | Typical Confidence Range |\n|-------------|-------------------------|\n| `episode_summary` | 0.8 |\n| `profile_fact` | 0.6 |\n| `key_event` | 0.7–0.9 |\n| Custom | Variable |\n\n资料来源：[server/services/compilers/heuristic.py:1-100]()\n\n### 3. Temporal Recency Ranking\n\nFor timeline-sensitive queries, items can be weighted by recency (`valid_from`, `created_at`). Recent memories receive higher ranking weights.\n\n### 4. Composite Scoring\n\nThe `_ScoredItem` system enables composite scoring:\n\n```python\nfinal_score = (\n    semantic_weight * semantic_score +\n    confidence_weight * confidence +\n    recency_weight * recency_score\n)\n```\n\n## Memory Kinds and Their Role in Context\n\nStatewave supports structured memory kinds that inform ranking behavior:\n\n| Kind | Description | Ranking Priority |\n|------|-------------|-------------------|\n| `episode_summary` | Auto-generated summary of an episode | High |\n| `profile_fact` | Extracted subject facts | Medium-High |\n| `key_event` | Significant events in subject history | High |\n| `resolution` | Issue resolution tracking | Context-dependent |\n| Custom kinds | User-defined memory types | User-defined |\n\n资料来源：[server/services/compilers/heuristic.py:50-100]()\n\n## Configuration Options\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Token budget for context assembly |\n| `STATEWAVE_LITELLM_API_KEY` | — | LLM API key for embedding-based ranking |\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Provider for semantic embeddings |\n\n资料来源：[README.md:100-150]()\n\n### Helm Chart Configuration\n\nFor Kubernetes deployments:\n\n```yaml\ncompiler:\n  type: llm  # or 'heuristic' for no-LLM mode\nembedding:\n  provider: litellm  # or 'stub' for demo mode\n```\n\n资料来源：[helm/statewave/README.md:1-50]()\n\n## API Response Structure\n\n### Success Response: `200 OK`\n\n```json\n{\n  \"subject_id\": \"uuid\",\n  \"query\": \"user query string\",\n  \"memories\": [\n    {\n      \"id\": \"uuid\",\n      \"subject_id\": \"uuid\",\n      \"kind\": \"episode_summary\",\n      \"content\": \"...\",\n      \"summary\": \"...\",\n      \"confidence\": 0.8,\n      \"valid_from\": \"2024-01-15T10:00:00Z\",\n      \"valid_to\": \"2024-01-20T10:00:00Z\",\n      \"source_episode_ids\": [\"uuid1\", \"uuid2\"],\n      \"metadata\": {},\n      \"status\": \"active\",\n      \"sensitivity_labels\": [],\n      \"created_at\": \"2024-01-15T10:30:00Z\",\n      \"updated_at\": \"2024-01-15T10:30:00Z\"\n    }\n  ],\n  \"episodes\": [],\n  \"total_tokens\": 3500,\n  \"truncated\": false\n}\n```\n\n## Snapshot Integration\n\nContext assembly respects snapshot-restored memories. When memories are restored from snapshots, they carry provenance:\n\n```python\nmetadata_={\n    **mem.metadata_,\n    \"restored_from_snapshot\": str(snapshot_id),\n}\n```\n\n资料来源：[server/services/snapshots.py:1-50]()\n\n## Memory Evolution and Context\n\nThe memory evolution system tracks superseding relationships:\n\n```python\nclass MemoryEvolutionResponse(BaseModel):\n    memory_id: str\n    status: str\n    created_at: str\n    superseding_memory: Optional[MemoryRelation]\n    superseded_memories: list[MemoryRelation]\n    sibling_memories: list[MemoryRelation]\n    source_episode_count: int\n```\n\nWhen assembling context, superseded memories may be excluded or marked, ensuring agents see the most current information.\n\n资料来源：[server/api/admin.py:1-100]()\n\n## Evaluation and Testing\n\nThe `scripts/eval/eval_docs_support.py` module provides evaluation patterns for context quality:\n\n```python\nQuestion(\n    task=\"How does context ranking work?\",\n    expected_doc_paths=[\"architecture/ranking.md\"],\n    expected_terms=[\"ranking\", \"score\"],\n)\n```\n\nThis validates that the ranking system correctly surfaces relevant memories for queries.\n\n资料来源：[scripts/eval/eval_docs_support.py:1-50]()\n\n## Best Practices\n\n1. **Set Appropriate Token Budgets**: Balance context richness against LLM limits. Start with 4000 and adjust based on model context window.\n\n2. **Use Semantic Search for Complex Queries**: When users ask complex questions, semantic similarity ranking outperforms keyword matching.\n\n3. **Leverage Memory Kinds**: Structure memories with appropriate kinds to enable kind-filtered context retrieval.\n\n4. **Monitor Confidence Scores**: Low-confidence memories may indicate compilation issues or ambiguous data.\n\n5. **Snapshot Before Major Changes**: Use snapshots to preserve context state before bulk operations.\n\n## Related Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n\n资料来源：[README.md:50-80]()\n\n---\n\n<a id='page-compilation-services'></a>\n\n## Compilation Services\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/compiler.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compiler.py)\n- [server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n- [server/services/compilers/llm.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/llm.py)\n- [server/services/conflicts.py](https://github.com/smaramwbc/statewave/blob/main/server/services/conflicts.py)\n- [server/services/compile_jobs.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compile_jobs.py)\n</details>\n\n# Compilation Services\n\nCompilation Services transform raw episodes into structured memories within Statewave. This process extracts meaningful information from conversation events, resolves conflicts between overlapping facts, and produces durable knowledge representations that agents can retrieve during context assembly.\n\n## Overview\n\nStatewave's compilation pipeline operates as a multi-stage process that converts incoming episode data into memory entities. The system supports two distinct compilation modes — heuristic and LLM — allowing deployments to choose between performance and intelligence based on infrastructure constraints.\n\n```mermaid\ngraph TD\n    A[Episode Ingest] --> B{Compilation Mode}\n    B -->|Heuristic| C[Heuristic Compiler]\n    B -->|LLM| D[LLM Compiler]\n    C --> E[Memory Rows]\n    D --> E\n    E --> F[Conflict Resolution]\n    F --> G[Finalized Memories]\n    \n    H[Context Assembly] --> I[Memory Retrieval]\n    G --> I\n```\n\n## Compilation Modes\n\nStatewave ships with two compiler implementations, each suited to different operational contexts.\n\n### Heuristic Compiler\n\nThe heuristic compiler performs rule-based extraction without external AI dependencies. It analyzes episode text using pattern matching and natural language heuristics to identify structured facts.\n\n**Supported Memory Kinds:**\n\n| Kind | Description | Confidence | TTL |\n|------|-------------|------------|-----|\n| `episode_summary` | Concise summary of episode content | 0.8 | 30 days |\n| `profile_fact` | Extracted user profile attributes | 0.6 | 90 days |\n| `preference` | User-stated preferences | 0.7 | 60 days |\n| `fact` | General factual statements | 0.65 | 60 days |\n\nThe heuristic compiler processes each episode independently, extracting profile facts through pattern recognition and generating episode summaries through text truncation and normalization.\n\n### LLM Compiler\n\nThe LLM compiler leverages large language models to perform semantic understanding of episodes. This mode produces higher-quality memories with better contextual awareness but requires external LLM infrastructure.\n\n**Key Capabilities:**\n- Multi-episode summarization across conversation turns\n- Inference of implicit facts not explicitly stated\n- Better handling of ambiguous or complex dialogue\n- Cross-episode fact consolidation\n\n## Temporal Anchoring\n\nEvery memory requires a temporal anchor to support time-bounded queries and historical reasoning. The compilation system determines validity windows using a priority cascade.\n\n```mermaid\ngraph LR\n    A[Temporal Anchor Priority] --> B[payload.event_time]\n    B --> C[payload.messages[0].timestamp]\n    C --> D[Episode created_at]\n    \n    E[compute_valid_to] --> F[Memory.valid_from]\n    F --> G[Memory.valid_to]\n```\n\n**Anchor Resolution Order:**\n1. Explicit `event_time` in episode payload (connector replay scenarios)\n2. First message timestamp in chat-shaped payloads\n3. Episode creation timestamp (fallback)\n\nThe `valid_to` date derives from the memory kind's configured TTL (time-to-live), ensuring automatic expiration of transient information.\n\n## Conflict Resolution\n\nWhen multiple episodes produce overlapping memories, the conflict resolution service determines which information takes precedence.\n\n```mermaid\ngraph TD\n    A[New Memory] --> B{Same Subject?}\n    B -->|No| C[Insert Directly]\n    B -->|Yes| D{Overlapping Time Range?}\n    D -->|No| E[Insert Directly]\n    D -->|Yes| F{Conflicting Content?}\n    F -->|No| G[Insert as Sibling]\n    F -->|Yes| H[Apply Resolution Strategy]\n    \n    H --> I{Strategy: Supersede}\n    H --> J{Strategy: Merge}\n    H --> K{Strategy: Retain Both}\n    \n    I --> L[Mark Older as Superseded]\n    J --> M[Combine Content]\n    K --> N[Link as Alternatives]\n```\n\n**Resolution Strategies:**\n\n| Strategy | Behavior | Use Case |\n|----------|----------|----------|\n| `supersede` | Replace older conflicting memory | Corrected information |\n| `merge` | Combine facts from both memories | Complementary details |\n| `retain_both` | Keep both as alternatives | Ambiguous or opinion-based |\n\n## Compilation Job Management\n\nLong-running compilation tasks are managed through an asynchronous job system that prevents API timeouts and supports retry logic.\n\n```mermaid\ngraph TD\n    A[POST /v1/memories/compile] --> B{Currently Compiling?}\n    B -->|Yes| C[Return 409 Conflict]\n    B -->|No| D[Queue Job]\n    D --> E[Job Created]\n    E --> F[Background Processing]\n    F --> G{Success?}\n    G -->|Yes| H[Memories Created]\n    G -->|No| I{Retryable?}\n    I -->|Yes| J[Retry with Backoff]\n    I -->|No| K[Mark Failed]\n    J --> F\n```\n\n**Job States:**\n- `pending` — Queued for processing\n- `running` — Actively compiling\n- `completed` — Successfully finished\n- `failed` — Unrecoverable error\n- `cancelled` — Manually aborted\n\n## Data Models\n\n### Episode to Memory Flow\n\n```\nEpisodeRow\n├── id: UUID\n├── subject_id: UUID\n├── source: str (e.g., \"mcp-server\", \"github\", \"statewave-docs\")\n├── type: str (e.g., \"conversation\", \"doc_section\", \"issue\")\n├── payload: dict\n│   ├── title: str\n│   ├── text: str\n│   ├── messages: list[dict]\n│   └── ...\n├── metadata_: dict\n├── provenance: dict\n│   └── content_hash: str\n└── created_at: datetime\n\n         ↓ Compilation\n\nMemoryRow\n├── id: UUID\n├── subject_id: UUID\n├── kind: str (e.g., \"episode_summary\", \"profile_fact\")\n├── content: str\n├── summary: str\n├── confidence: float (0.0 - 1.0)\n├── valid_from: datetime\n├── valid_to: datetime\n├── source_episode_ids: list[UUID]\n├── metadata_: dict\n├── status: str (\"active\", \"superseded\", \"redacted\")\n├── sensitivity_labels: list[str]\n├── embedding: vector (optional)\n└── created_at, updated_at: datetime\n```\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_COMPILER_TYPE` | `llm` | Compiler mode: `llm` or `heuristic` |\n| `STATEWAVE_LLM_API_KEY` | — | API key for LLM provider |\n| `STATEWAVE_LLM_MODEL` | `gpt-4o` | Model identifier for LLM compiler |\n| `STATEWAVE_COMPILE_TIMEOUT` | `300` | Compilation timeout in seconds |\n\n### Helm Chart Configuration\n\n| Value | Default | Notes |\n|-------|---------|-------|\n| `compiler.type` | `llm` | `heuristic` for no-LLM mode |\n| `llm.apiKey` | — | Required when `compiler.type=llm` |\n| `llm.model` | `gpt-4o` | Override default model |\n\n## Idempotency\n\nCompilation is designed to be idempotent. Re-running compilation on episodes that have already been compiled will not create duplicate memories. The system tracks `source_episode_ids` to prevent reprocessing and uses content hashing in provenance metadata to detect unchanged source material.\n\nThis design supports:\n- Safe re-compilation after configuration changes\n- Incremental updates from connector replay\n- Bootstrap and refresh workflows\n\n## API Integration\n\nCompilation is triggered through the REST API:\n\n```bash\nPOST /v1/memories/compile\n```\n\nThe endpoint accepts a `subject_id` and initiates asynchronous processing. Polling the job status or receiving webhooks (if configured) provides completion feedback.\n\n**Request Example:**\n```json\n{\n  \"subject_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"force\": false\n}\n```\n\n**Response:**\n```json\n{\n  \"status\": \"queued\",\n  \"job_id\": \"660e8400-e29b-41d4-a716-446655440001\"\n}\n\n---\n\n<a id='page-embeddings'></a>\n\n## Embedding Services\n\n### 相关页面\n\n相关主题：[Context Assembly & Ranking](#page-context-assembly)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/embeddings/litellm.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/litellm.py)\n- [server/services/embeddings/stub.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/stub.py)\n- [server/services/embeddings/query_cache.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/query_cache.py)\n- [server/services/embeddings/backfill.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/backfill.py)\n</details>\n\n# Embedding Services\n\nEmbedding Services provide semantic vector representations for memories and episodes in Statewave, enabling similarity-based search, context ranking, and retrieval-augmented generation workflows.\n\n## Overview\n\nThe embedding layer is a pluggable component that converts textual content into high-dimensional vector embeddings. These vectors power the semantic search capabilities of the `/v1/memories/search` endpoint and the relevance scoring in context assembly (`POST /v1/context`).\n\nStatewave supports two embedding providers:\n\n| Provider | Purpose | Use Case |\n|----------|---------|----------|\n| `litellm` | Real embeddings via LiteLLM proxy | Production deployments with LLM API access |\n| `stub` | Zero vectors (all dimensions = 0) | Development, demos, or when embeddings are disabled |\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Embedding Services Layer\"\n        LLM[LiteLLM Embeddings<br/>litellm.py]\n        STUB[Stub Embeddings<br/>stub.py]\n        CACHE[Query Cache<br/>query_cache.py]\n    end\n    \n    subgraph \"Backfill Operations\"\n        BF[Backfill Service<br/>backfill.py]\n    end\n    \n    subgraph \"Consumers\"\n        SEARCH[Memory Search<br/>/v1/memories/search]\n        CONTEXT[Context Assembly<br/>/v1/context]\n        COMPILER[Memory Compiler]\n    end\n    \n    LLM --> CACHE\n    STUB --> CACHE\n    CACHE --> SEARCH\n    CACHE --> CONTEXT\n    CACHE --> COMPILER\n    BF --> LLM\n    BF --> STUB\n```\n\n## Configuration\n\nEmbedding behavior is controlled via environment variables:\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Embedding provider: `litellm` or `stub` |\n| `STATEWAVE_LITELLM_API_KEY` | — | API key for LiteLLM |\n| `STATEWAVE_LITELLM_BASE_URL` | — | Custom LiteLLM base URL (for proxy deployments) |\n| `STATEWAVE_EMBEDDING_MODEL` | provider default | Specific embedding model to use |\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n## Providers\n\n### LiteLLM Provider\n\nThe LiteLLM provider (`server/services/embeddings/litellm.py`) routes embedding requests through the LiteLLM proxy library, which standardizes access to multiple LLM backends including OpenAI, Azure, Cohere, and custom providers.\n\n**Key responsibilities:**\n\n- Accept text input and return normalized embedding vectors\n- Handle API authentication via `STATEWAVE_LITELLM_API_KEY`\n- Support custom base URLs via `STATEWAVE_LITELLM_BASE_URL`\n- Model selection via `STATEWAVE_EMBEDDING_MODEL`\n- Normalize embedding dimensions across providers\n\n### Stub Provider\n\nThe stub provider (`server/services/embeddings/stub.py`) returns zero vectors for all inputs. This is useful for:\n\n- Development environments without API access\n- Demo deployments where semantic search is not required\n- Testing the rest of the system without embedding dependencies\n\n资料来源：[server/services/embeddings/stub.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/stub.py)\n\n## Query Cache\n\nThe query cache (`server/services/embeddings/query_cache.py`) reduces redundant embedding computations by caching the results of previously generated embeddings.\n\n### Cache Strategy\n\n```mermaid\ngraph LR\n    A[Embedding Request] --> B{Hit in Cache?}\n    B -->|Yes| C[Return Cached Vector]\n    B -->|No| D[Compute Embedding]\n    D --> E[Store in Cache]\n    E --> F[Return Vector]\n    C --> F\n```\n\n### Cache Behavior\n\n- Cache key is derived from the text content being embedded\n- Cached vectors are returned directly on cache hit\n- Reduces API calls and latency for repeated queries\n- Particularly effective for search queries that repeat across requests\n\n资料来源：[server/services/embeddings/query_cache.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/query_cache.py)\n\n## Backfill Operations\n\nThe backfill service (`server/services/embeddings/backfill.py`) handles bulk embedding regeneration for existing data.\n\n### Use Cases\n\n- **Model migration**: When switching embedding models, regenerate all existing embeddings\n- **Corruption recovery**: Rebuild embeddings for data with missing or corrupted vectors\n- **Schema changes**: When embedding schema or normalization changes\n\n### Backfill Process\n\n```mermaid\ngraph TD\n    A[Start Backfill] --> B[Query Rows Missing Embeddings]\n    B --> C{Process Batch}\n    C -->|Has More| D[Fetch Batch]\n    D --> E[Generate Embeddings]\n    E --> F[Update Database]\n    F --> C\n    C -->|Complete| G[Backfill Complete]\n```\n\n资料来源：[server/services/embeddings/backfill.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/backfill.py)\n\n## Integration with Memory System\n\nEmbeddings are stored alongside memory records and used for relevance scoring:\n\n```mermaid\ngraph LR\n    subgraph \"Memory Row Schema\"\n        M1[id]\n        M2[content]\n        M3[embedding]\n        M4[source_episode_ids]\n    end\n    \n    subgraph \"Usage Flow\"\n        S[Search Query] --> E[Generate Query Embedding]\n        E --> SC[Compute Similarity Scores]\n        M3 --> SC\n        SC --> R[Ranked Results]\n    end\n```\n\nThe `embedding` field in `MemoryRow` stores the vector representation of memory content, enabling:\n\n1. **Semantic similarity search** via cosine similarity\n2. **Context relevance scoring** during context assembly\n3. **Deduplication** by detecting high-similarity memory candidates\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n## API Endpoints Using Embeddings\n\n| Endpoint | Embedding Usage |\n|----------|-----------------|\n| `GET /v1/memories/search` | Query embedding vs stored memory embeddings |\n| `POST /v1/context` | Rank episode and memory candidates by relevance |\n| `POST /v1/memories/compile` | Generate embeddings for new memories |\n\n## Deployment Considerations\n\n### Production Deployment\n\nFor production with semantic search enabled:\n\n1. Set `STATEWAVE_EMBEDDING_PROVIDER=litellm`\n2. Configure `STATEWAVE_LITELLM_API_KEY` with appropriate permissions\n3. Optionally specify `STATEWAVE_EMBEDDING_MODEL` for a specific model\n4. For proxy deployments, set `STATEWAVE_LITELLM_BASE_URL`\n\n### Demo Mode\n\nFor demos or development without API costs:\n\n1. Set `STATEWAVE_EMBEDDING_PROVIDER=stub`\n2. Full functionality except semantic search (returns zero similarity)\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n### Helm Configuration\n\n```yaml\nembedding:\n  provider: litellm  # or \"stub\" for demo mode\n  model: \"\"          # optional: specify model\n```\n\n## Related Services\n\n- **Compiler Services**: Use embeddings during memory compilation\n- **Context Assembly**: Uses embeddings for relevance scoring\n- **Memory Search**: Primary consumer of embedding similarity\n- **Snapshots**: Preserves embeddings when snapshotting subject state\n\n资料来源：[server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n\n---\n\n<a id='page-receipts-policy'></a>\n\n## Governance - Receipts & Policy Engine\n\n### 相关页面\n\n相关主题：[Multi-tenancy & Security](#page-multi-tenancy), [Context Assembly & Ranking](#page-context-assembly)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py) - Context assembly with receipt emission\n- [server/services/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/services/handoff.py) - Handoff service with receipt support\n- [server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py) - Response schemas including receipt fields\n- [server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py) - Request schemas with receipt and policy parameters\n- [server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py) - Database schema including PolicyBundleRow\n</details>\n\n# Governance - Receipts & Policy Engine\n\n## Overview\n\nThe Governance layer in Statewave provides two interrelated mechanisms for operational accountability and data access control:\n\n1. **State Assembly Receipts** — Immutable audit records that capture exactly which memories and episodes were included in a `/v1/context` or `/v1/handoff` response, enabling full traceability of AI-generated context.\n2. **Policy Engine** — A content-addressed bundle system that enforces sensitivity-label-based filtering on memories before they appear in responses, with configurable enforcement modes.\n\nThese systems work together to ensure that when a context bundle is assembled for downstream AI consumption, there is a verifiable record of what was included, why it was included, and what policy rules were applied.\n\n资料来源：[server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n\n---\n\n## State Assembly Receipts\n\n### Purpose\n\nReceipts address the \"black box\" problem in RAG-based AI systems. When an agent receives a context bundle, receipts provide cryptographic proof of:\n\n- Which specific memories and episodes were selected\n- The ranking scores used for selection\n- What policy filters were applied\n- The token budget consumed\n- Which policy bundle version governed the decision\n\nThis enables auditing, debugging, compliance reporting, and reproducibility of AI decisions that depend on Statewave's memory layer.\n\n### Receipt Data Model\n\nReceipts are persisted to the database and linked to the request via a unique `receipt_id`. The core receipt structure captures the complete assembly decision:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `receipt_id` | `uuid.UUID` | Unique identifier for this receipt |\n| `subject_id` | `str` | The subject whose context was assembled |\n| `task` | `str` | The task/retrieval purpose |\n| `tenant_id` | `str \\| None` | Tenant context for multi-tenant deployments |\n| `as_of` | `datetime` | Timestamp of the assembly request |\n| `context_hash` | `str` | Hash of the assembled context for integrity verification |\n| `context_size_bytes` | `int` | Size of the assembled context in bytes |\n| `token_estimate` | `int` | Estimated token count consumed |\n| `selected_memories` | `list` | Memory IDs with scores that were included |\n| `selected_episodes` | `list` | Episode IDs with scores that were included |\n| `policy_bundle_hash` | `str \\| None` | Hash of the policy bundle applied |\n| `policy_mode` | `str` | Mode used (`log_only` or `enforce`) |\n| `filters_applied` | `list` | Policy rules that resulted in exclusions |\n| `filters_skipped` | `list` | Policy rules not triggered |\n| `query_id` | `str \\| None` | External correlation ID |\n| `task_id` | `str \\| None` | Task correlation ID |\n| `parent_receipt_id` | `str \\| None` | For nested/derived requests |\n| `caller_id` | `str \\| None` | Identity of the calling service |\n| `caller_type` | `str \\| None` | Type of caller (service, user, etc.) |\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n### Receipt Emission Modes\n\nReceipts support three emission policies configurable at the tenant level:\n\n| Mode | Behavior |\n|------|----------|\n| `on_request` (default) | Callers opt in per-request via `emit_receipt: true` |\n| `always` | Every context/handoff request generates a receipt, overriding `emit_receipt: false` |\n| `never` | No receipts are generated, regardless of request flags |\n\n配置来源：[server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py)\n\n### Receipt Response Fields\n\nWhen a receipt is successfully written, the response includes:\n\n```python\nreceipt_id: str | None  # UUID of the written receipt, None if emission failed\nreceipt_emitted: bool   # True iff receipt was successfully persisted\n```\n\nThe `receipt_emitted` field distinguishes between three states:\n\n1. **True** — Receipt was successfully written\n2. **False with `receipt_id = None`** — Receipt emission was not requested\n3. **False with `receipt_id = ...`** — Emission was attempted but failed; the response is still authoritative\n\n资料来源：[server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n\n### Receipt Emission Workflow\n\n```mermaid\nsequenceDiagram\n    participant Caller\n    participant ContextService\n    participant PolicyEngine\n    participant ReceiptsService\n    participant Database\n\n    Caller->>ContextService: POST /v1/context (emit_receipt=true)\n    ContextService->>PolicyEngine: Filter memories by sensitivity labels\n    PolicyEngine-->>ContextService: Filtered memories + applied/skipped rules\n    \n    ContextService->>ContextService: Assemble context bundle\n    ContextService->>ReceiptsService: Build receipt body\n    ReceiptsService->>Database: Write receipt record\n    Database-->>ReceiptsService: receipt_id\n    \n    ContextService-->>Caller: ContextBundleResponse + receipt_id, receipt_emitted=true\n```\n\nThe `_maybe_emit_receipt` helper in the context service implements this flow, accepting parameters for memory rows, episode rows, policy decisions, and caller identity.\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n---\n\n## Policy Engine\n\n### Architecture Overview\n\nThe Policy Engine operates on an immutable, content-addressed bundle model. Each policy bundle is:\n\n1. **Content-addressed** — Identified by `bundle_hash` (SHA-256 of YAML content)\n2. **Tenant-scoped** — Same YAML can be installed by different tenants as independent rows\n3. **Activatable** — Only one bundle per tenant can be active at a time\n\n```mermaid\ngraph TD\n    A[YAML Policy File] --> B[Compute bundle_hash]\n    B --> C[PolicyBundleRow]\n    C --> D{Tenant A}\n    C --> E{Tenant B}\n    D --> F[Active Bundle]\n    E --> G[Active Bundle]\n    \n    H[Context Request] --> I[Lookup active bundle]\n    I --> F\n    F --> J[Apply filters to memories]\n    J --> K[Filtered response]\n```\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n### PolicyBundleRow Schema\n\n| Column | Type | Description |\n|--------|------|-------------|\n| `id` | `UUID` | Synthetic primary key (allows multiple tenants to install same bundle) |\n| `bundle_hash` | `String(64)` | SHA-256 of YAML content, indexed |\n| `yaml_content` | `Text` | Full YAML policy definition |\n| `active` | `Boolean` | Whether this is the tenant's active policy |\n| `tenant_id` | `String(256)` | Tenant scope (NULL for system-wide) |\n| `config` | `JSONB` | Additional configuration |\n| `version` | `Integer` | Row version for optimistic locking |\n| `created_at` | `DateTime` | Creation timestamp |\n| `updated_at` | `DateTime` | Last modification timestamp |\n\nThe composite unique index on `(tenant_id, bundle_hash) NULLS NOT DISTINCT` enforces \"one bundle per (scope, content)\" — two tenants can independently install identical policy YAML.\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n### Policy Modes\n\nThe policy engine operates in two modes:\n\n| Mode | Behavior | Use Case |\n|------|----------|----------|\n| `log_only` (default) | Records what *would* be filtered into receipts without removing memories | Initial deployment, auditing, compliance review |\n| `enforce` | Drops denied memories and redacts marked ones from the response | Production enforcement after validating log_only behavior |\n\n```python\npolicy_mode: Literal[\"log_only\", \"enforce\"] | None = Field(\n    None,\n    description=(\n        \"Sensitivity-label policy enforcement mode (#50). `log_only` \"\n        \"(the default) records what *would* be filtered into receipts \"\n        \"without removing memories from the response. `enforce` drops \"\n        \"denied memories and redacts marked ones. Flip to enforce only \"\n        \"after auditing the log_only receipts for a few days.\"\n    ),\n)\n```\n\n配置来源：[server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py)\n\n### Policy Filter Tracking\n\nWhen a context bundle is assembled, the policy engine records:\n\n- **`filters_applied`** — List of policy rules that resulted in memory exclusions or modifications\n- **`filters_skipped`** — List of policy rules that were evaluated but not triggered\n\nThis data is written to receipts, enabling operators to:\n\n1. Verify that policies are being evaluated correctly\n2. Identify false positives in `enforce` mode before full deployment\n3. Generate compliance reports on data access patterns\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n---\n\n## Integration Points\n\n### Context Assembly (`/v1/context`)\n\nThe primary integration point where receipts are emitted and policy is enforced:\n\n```\nPOST /v1/context\n{\n  \"subject_id\": \"customer-123\",\n  \"task\": \"support_response\",\n  \"emit_receipt\": true,\n  \"policy_mode\": \"enforce\",\n  ...\n}\n```\n\nResponse includes `receipt_id` and `receipt_emitted` fields.\n\n### Handoff Service (`/v1/handoff`)\n\nThe handoff service also supports receipt emission for agent-to-agent transitions:\n\n```python\nhandoff_notes=handoff_notes,\ntoken_estimate=token_estimate,\nactive_fact_rows=[row for row in fact_rows if row.status == \"active\"],\nsession_episode_rows=current_session_eps[:10],\nemit_receipt=emit_receipt,\npolicy_bundle=active_bundle,\npolicy_mode=policy_mode,\n```\n\n资料来源：[server/services/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/services/handoff.py)\n\n### Tenant Configuration\n\nReceipts and policy settings can be configured at the tenant level:\n\n| Configuration | Type | Default | Description |\n|--------------|------|---------|-------------|\n| `receipts` | `Literal[\"always\", \"on_request\", \"never\"]` | `on_request` | Global receipt emission policy |\n| `receipt_retention_days` | `int` | `0` (forever) | Days to retain receipts before purge (0 = never purge) |\n| `policy_mode` | `Literal[\"log_only\", \"enforce\"]` | `log_only` | Default policy enforcement mode |\n| `require_caller_identity` | `bool` | `false` | Require `caller_id`/`caller_type` for context/handoff |\n\n配置来源：[server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py)\n\n---\n\n## Security Considerations\n\n### Caller Identity\n\nWhen `require_caller_identity` is enabled, the `/v1/context` and `/v1/handoff` endpoints will:\n\n- Reject anonymous callers (missing both `caller_id` and `caller_type`)\n- Record caller identity in receipts for audit purposes\n\nThis ensures that every context assembly can be traced to a specific service or user.\n\n### Immutable Receipts\n\nReceipts are append-only by design. Once written, they cannot be modified. This provides:\n\n- Non-repudiation for compliance audits\n- Reproducibility of AI decisions\n- Historical tracking of policy changes\n\n### Policy Bundle Integrity\n\nThe content-addressed nature of policy bundles means:\n\n- Any modification to the YAML content produces a different `bundle_hash`\n- The old bundle remains accessible by its hash\n- The `bundle_hash` recorded in receipts provides proof of which policy version was applied\n\n---\n\n## Related Documentation\n\n- [API v1 Contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md)\n- [Getting Started Guide](https://github.com/smaramwbc/statewave-docs/blob/main/getting-started.md)\n- [Architecture Overview](https://github.com/smaramwbc/statewave-docs/blob/main/architecture/overview.md)\n\n---\n\n<a id='page-multi-tenancy'></a>\n\n## Multi-tenancy & Security\n\n### 相关页面\n\n相关主题：[Governance - Receipts & Policy Engine](#page-receipts-policy)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/core/tenant.py](https://github.com/smaramwbc/statewave/blob/main/server/core/tenant.py)\n- [server/core/auth.py](https://github.com/smaramwbc/statewave/blob/main/server/core/auth.py)\n- [server/core/ratelimit.py](https://github.com/smaramwbc/statewave/blob/main/server/core/ratelimit.py)\n- [server/services/webhooks.py](https://github.com/smaramwbc/statewave/blob/main/server/services/webhooks.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/services/ratelimit.py](https://github.com/smaramwbc/statewave/blob/main/server/services/ratelimit.py)\n</details>\n\n# Multi-tenancy & Security\n\n## Overview\n\nStatewave implements a multi-tenant architecture with comprehensive security controls for enterprise deployments. The system provides query-scoped data isolation, per-tenant policy enforcement, caller identity validation, and distributed rate limiting—all coordinated through a Postgres-backed shared infrastructure.\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"API Layer\"\n        A[Incoming Request] --> B[Tenant Resolution]\n        B --> C[Auth Middleware]\n        C --> D[Rate Limiter]\n        D --> E[Policy Engine]\n        E --> F[Business Logic]\n    end\n    \n    subgraph \"Security Components\"\n        C -->|API Key| Auth[Auth Service]\n        D -->|Distributed| RL[Rate Limit Store]\n        E -->|Bundle Hash| PB[Policy Bundles]\n        E -->|caller_id/caller_type| CI[Caller Identity]\n    end\n    \n    subgraph \"Tenant Isolation\"\n        B -->|tenant_id| TI[Tenant Isolation Layer]\n        TI -->|query scoping| DB[(Postgres)]\n        PB -->|per-tenant| TI\n    end\n```\n\n## Tenant Resolution\n\n### Tenant Header Configuration\n\nStatewave uses a configurable HTTP header for tenant identification. The header name defaults to `X-Tenant-ID` but can be customized via environment variables.\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Header for multi-tenant isolation |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant header |\n\nWhen `STATEWAVE_REQUIRE_TENANT` is set to `true`, any request missing the tenant header receives a `400 Bad Request` response. When `false`, requests without a tenant header are processed with an anonymous tenant context.\n\n资料来源：[README.md:env-vars]() (configuration documentation)\n\n### Tenant Resolution Flow\n\n```mermaid\nsequenceDiagram\n    participant C as Client\n    participant A as API Server\n    participant T as Tenant Resolver\n    participant DB as Postgres\n    \n    C->>A: Request + X-Tenant-ID header\n    A->>T: Extract tenant_id\n    T->>DB: Lookup tenant config\n    DB-->>T: TenantConfigResponse\n    T-->>A: Tenant context\n    A->>A: Apply tenant-scoped logic\n```\n\n## Tenant Configuration API\n\n### Configuration Schema\n\nThe `TenantConfigResponse` schema defines the tenant configuration structure:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `tenant_id` | `str` | Unique tenant identifier |\n| `config` | `dict[str, Any]` | Full configuration document |\n| `version` | `int` | Optimistic-concurrency counter |\n| `created_at` | `datetime \\| None` | First configuration timestamp |\n| `updated_at` | `datetime \\| None` | Last modification timestamp |\n\n### Configuration Keys\n\n| Key | Type | Description |\n|-----|------|-------------|\n| `receipts` | `string` | Emission mode: `\"always\"`, `\"never\"`, `\"on_request\"` |\n| `receipt_retention_days` | `int` | Days to retain receipts before cleanup |\n| `policy_mode` | `string` | `\"log_only\"` or `\"enforce\"` |\n| `require_caller_identity` | `bool` | Enforce caller_id/caller_type presence |\n\n资料来源：[server/schemas/responses.py:tenant-config-schema]() (response schema definition)\n\n### Admin Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `GET` | `/admin/tenants/{id}/config` | Retrieve tenant configuration |\n| `PATCH` | `/admin/tenants/{id}/config` | Update tenant configuration |\n\n#### PATCH Request Shape\n\nThe PATCH operation performs a merge update with optimistic concurrency control:\n\n```python\n# Expected version must match current state\n{\n    \"expected_version\": 5,\n    \"config\": {\n        \"policy_mode\": \"enforce\",\n        \"receipt_retention_days\": 90\n    }\n}\n```\n\nIf `expected_version` does not match the current database version, the update fails with a `409 Conflict` response.\n\n资料来源：[server/api/admin.py:config-endpoints]() (admin API implementation)\n\n## Authentication & Authorization\n\n### API Key Authentication\n\nStatewave supports API key authentication via the `Authorization` header:\n\n```http\nAuthorization: Bearer <api_key>\n```\n\nOr via query parameter for specific integration scenarios:\n\n```http\nGET /v1/context?api_key=<api_key>\n```\n\n### Caller Identity Validation\n\nWhen `require_caller_identity` is enabled in tenant config, every context and handoff request must include:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `caller_id` | `str` | Unique identifier of the calling agent/user |\n| `caller_type` | `str` | Type classification (e.g., `\"agent\"`, `\"user\"`, `\"system\"`) |\n\nRequests missing these fields receive a `401 Unauthorized` response:\n\n```json\n{\n    \"detail\": \"tenant config requires caller_id and caller_type on every context call\"\n}\n```\n\n资料来源：[server/api/handoff.py:identity-validation]() (identity enforcement)\n\n## Rate Limiting\n\n### Rate Limit Strategy\n\nStatewave supports two rate limiting backends:\n\n| Strategy | Backend | Use Case |\n|----------|---------|----------|\n| `distributed` | Postgres | Multi-instance deployments |\n| `memory` | In-process | Single instance / development |\n\n### Configuration\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `STATEWAVE_RATE_LIMIT` | `1000` | Requests per window |\n| `STATEWAVE_RATE_WINDOW` | `60` | Window duration in seconds |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | Backend strategy selection |\n\n### Current Limitations\n\n> **Note**: Rate limiting is currently keyed by IP address only, not per-tenant or per-API-key. This is a known limitation in v0.8.0.\n\n资料来源：[README.md:rate-limiting-limits]() (documentation of limitations)\n\n## Policy Engine\n\n### Policy Bundle Structure\n\nPolicy bundles are declarative YAML/JSON documents that define filtering rules. Each bundle is:\n\n- **Immutable**: Once created, content cannot be modified\n- **Content-addressed**: Identified by `bundle_hash` (SHA-256)\n- **Per-tenant**: Same bundle content can exist independently per tenant\n\n```yaml\n# Example policy bundle\nversion: 1\nrules:\n  - id: redact_sensitive\n    predicates:\n      - kind: label_match\n        args:\n          label: PII\n      - kind: caller_type\n        args:\n          type: external_agent\n    action: redact\n```\n\n### Predicate Types\n\n| Predicate | Description |\n|-----------|-------------|\n| `label_match` | Match memory by sensitivity label |\n| `caller_type` | Match by calling agent type |\n| `caller_id` | Match by specific caller identifier |\n\n### Actions\n\n| Action | Behavior |\n|--------|----------|\n| `deny` | Reject the memory from context |\n| `redact` | Remove sensitive content, keep metadata |\n\n### Policy Modes\n\n| Mode | Behavior |\n|------|----------|\n| `log_only` | Record decisions to receipts, no filtering applied |\n| `enforce` | Drop denied memories before ranking |\n\n资料来源：[server/db/tables.py:policy-bundle-row]() (database schema)\n\n## Receipts System\n\n### Receipt Emission Logic\n\nReceipts record policy decisions for audit and compliance. The emission decision follows a priority cascade:\n\n```mermaid\nflowchart TD\n    A[Receipt Request] --> B{Global Kill Switch?}\n    B -->|Enabled| E[Emit = False]\n    B -->|Disabled| C{Bundle Force Off?}\n    C -->|Yes| E\n    C -->|No| D{Tenant Mode?}\n    D -->|always| F[Emit = True]\n    D -->|never| E\n    D -->|on_request| G{Request Flag?}\n    G -->|True| F\n    G -->|False| E\n```\n\n### Kill Switch\n\nGlobal environment variable disables all receipt emission:\n\n```bash\nSTATEWAVE_RECEIPTS_DISABLED=true  # or \"1\", \"yes\"\n```\n\n### Receipt Data Model\n\n| Field | Description |\n|-------|-------------|\n| `id` | ULID identifier |\n| `tenant_id` | Associated tenant |\n| `policy_bundle_hash` | Hash of applied policy bundle |\n| `policy_mode` | Mode at time of decision |\n| `filters_applied` | List of applied filter rules |\n| `filters_skipped` | List of bypassed filter rules |\n| `caller_id` | Identity of requesting agent |\n| `caller_type` | Type of requesting agent |\n\n资料来源：[server/services/receipts.py:emission-decision]() (emission logic)\n\n## Multi-Tenant Data Isolation\n\n### Query-Scoped Isolation\n\nAll database queries include tenant_id in their WHERE clauses. This is enforced at the service layer:\n\n```python\n# Example isolation pattern\nquery = select(MemoryRow).where(\n    MemoryRow.tenant_id == tenant_id,\n    MemoryRow.subject_id == subject_id\n)\n```\n\n### Composite Unique Index\n\nPolicy bundles use a composite unique index to enforce:\n\n```sql\nUNIQUE (tenant_id, bundle_hash) NULLS NOT DISTINCT\n```\n\nThis allows multiple tenants to install identical policy content while maintaining row-level separation.\n\n资料来源：[server/db/tables.py:composite-index]() (index definition)\n\n## Security Best Practices\n\n### Recommended Configuration\n\nFor production deployments:\n\n```yaml\n# Kubernetes/Helm values\nauth:\n  apiKey: <use-external-secret>\n  \ndatabase:\n  url: <use-external-secret>\n  existingSecret: statewave-db\n  existingSecretKey: STATEWAVE_DATABASE_URL\n\n# Tenant configuration\npolicy_mode: enforce\nrequire_caller_identity: true\nreceipts: always\nreceipt_retention_days: 90\n```\n\n### Secret Management\n\nThe Helm chart supports two patterns:\n\n1. **Inline secrets**: Set via `--set` for development\n2. **External secrets**: Reference existing secrets (recommended for production)\n\n| Secret | Purpose |\n|--------|---------|\n| `statewave-db` | Database connection URL |\n| `statewave-llm` | LLM provider API key |\n| `statewave-auth` | API authentication key |\n\n资料来源：[helm/statewave/README.md:secret-management]() (Helm documentation)\n\n## Current Limitations\n\n| Feature | Status | Notes |\n|---------|--------|-------|\n| Rate limiting per-IP | ✅ Shipped | Distributed but IP-only |\n| Rate limiting per-tenant | 🔜 Planned | Not yet implemented |\n| Rate limiting per-API-key | 🔜 Planned | Not yet implemented |\n| Postgres RLS | 🔜 Planned | App-layer isolation only |\n| Multi-tenant policy bundles | ✅ v0.8 | Content-hashed, per-tenant |\n| Caller identity validation | ✅ v0.8 | Configurable per tenant |\n\n资料来源：[README.md:current-limitations]() (version 0.8.0 status)\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：smaramwbc/statewave\n\n摘要：发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1219923941 | https://github.com/smaramwbc/statewave | README/documentation is current enough for a first validation pass.\n\n## 2. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | last_activity_observed missing\n\n## 3. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n\n## 4. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n\n## 5. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | issue_or_pr_quality=unknown\n\n## 6. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | release_recency=unknown\n\n<!-- canonical_name: smaramwbc/statewave; human_manual_source: deepwiki_human_wiki -->\n",
      "markdown_key": "statewave",
      "pages": "draft",
      "source_refs": [
        {
          "evidence_id": "github_repo:1219923941",
          "kind": "repo",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/smaramwbc/statewave"
        },
        {
          "evidence_id": "art_4784ca0874154258a85b1099b900cdf5",
          "kind": "docs",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/smaramwbc/statewave#readme"
        }
      ],
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "statewave 说明书",
      "toc": [
        "https://github.com/smaramwbc/statewave 项目说明书",
        "目录",
        "Overview - What is Statewave?",
        "Core Concept",
        "Architecture Overview",
        "Key Components",
        "Data Flow",
        "API Reference",
        "Doramagic 踩坑日志"
      ]
    }
  },
  "quality_gate": {
    "blocking_gaps": [],
    "category_confidence": "medium",
    "compile_status": "ready_for_review",
    "five_assets_present": true,
    "install_sandbox_verified": true,
    "missing_evidence": [],
    "next_action": "publish to Doramagic.ai project surfaces",
    "prompt_preview_boundary_ok": true,
    "publish_status": "publishable",
    "quick_start_verified": true,
    "repo_clone_verified": true,
    "repo_commit": "28ff5ad08131d9e387478d6f9d5a53c279680435",
    "repo_inspection_error": null,
    "repo_inspection_files": [
      "pyproject.toml",
      "Dockerfile",
      "README.md",
      "docker-compose.yml",
      "uv.lock",
      "docs/state-assembly-receipts.md",
      "docs/memory-portability.md"
    ],
    "repo_inspection_verified": true,
    "review_reasons": [],
    "tag_count_ok": true,
    "unsupported_claims": []
  },
  "schema_version": "0.1",
  "user_assets": {
    "ai_context_pack": {
      "asset_id": "ai_context_pack",
      "filename": "AI_CONTEXT_PACK.md",
      "markdown": "# statewave - Doramagic AI Context Pack\n\n> 定位：安装前体验与判断资产。它帮助宿主 AI 有一个好的开始，但不代表已经安装、执行或验证目标项目。\n\n## 充分原则\n\n- **充分原则，不是压缩原则**：AI Context Pack 应该充分到让宿主 AI 在开工前理解项目价值、能力边界、使用入口、风险和证据来源；它可以分层组织，但不以最短摘要为目标。\n- **压缩策略**：只压缩噪声和重复内容，不压缩会影响判断和开工质量的上下文。\n\n## 给宿主 AI 的使用方式\n\n你正在读取 Doramagic 为 statewave 编译的 AI Context Pack。请把它当作开工前上下文：帮助用户理解适合谁、能做什么、如何开始、哪些必须安装后验证、风险在哪里。不要声称你已经安装、运行或执行了目标项目。\n\n## Claim 消费规则\n\n- **事实来源**：Repo Evidence + Claim/Evidence Graph；Human Wiki 只提供显著性、术语和叙事结构。\n- **事实最低状态**：`supported`\n- `supported`：可以作为项目事实使用，但回答中必须引用 claim_id 和证据路径。\n- `weak`：只能作为低置信度线索，必须要求用户继续核实。\n- `inferred`：只能用于风险提示或待确认问题，不能包装成项目事实。\n- `unverified`：不得作为事实使用，应明确说证据不足。\n- `contradicted`：必须展示冲突来源，不得替用户强行选择一个版本。\n\n## 它最适合谁\n\n- **正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**：README 或插件配置提到多个宿主 AI。 证据：`README.md` Claim：`clm_0002` supported 0.86\n\n## 它能做什么\n\n- **命令行启动或安装流程**（需要安装后验证）：项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 证据：`README.md` Claim：`clm_0001` supported 0.86\n\n## 怎么开始\n\n- `pip install -e \".[dev,llm]\"` 证据：`README.md` Claim：`clm_0003` supported 0.86\n- `npm install @statewavedev/connectors-github` 证据：`README.md` Claim：`clm_0004` supported 0.86\n- `npm install @statewavedev/connectors-markdown` 证据：`README.md` Claim：`clm_0005` supported 0.86\n- `npm install @statewavedev/connectors-slack` 证据：`README.md` Claim：`clm_0006` supported 0.86\n- `npm install @statewavedev/connectors-n8n` 证据：`README.md` Claim：`clm_0007` supported 0.86\n- `npm install @statewavedev/connectors-zapier` 证据：`README.md` Claim：`clm_0008` supported 0.86\n- `npm install @statewavedev/mcp-server` 证据：`README.md` Claim：`clm_0009` supported 0.86\n\n## 继续前判断卡\n\n- **当前建议**：需要管理员/安全审批\n- **为什么**：继续前可能涉及密钥、账号、外部服务或敏感上下文，建议先经过管理员或安全审批。\n\n### 30 秒判断\n\n- **现在怎么做**：需要管理员/安全审批\n- **最小安全下一步**：先跑 Prompt Preview；若涉及凭证或企业环境，先审批再试装\n- **先别相信**：工具权限边界不能在安装前相信。\n- **继续会触碰**：命令执行、本地环境或项目文件、环境变量 / API Key\n\n### 现在可以相信\n\n- **适合人群线索：正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**（supported）：有 supported claim 或项目证据支撑，但仍不等于真实安装效果。 证据：`README.md` Claim：`clm_0002` supported 0.86\n- **能力存在：命令行启动或安装流程**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`README.md` Claim：`clm_0001` supported 0.86\n- **存在 Quick Start / 安装命令线索**（supported）：可以相信项目文档出现过启动或安装入口；不要因此直接在主力环境运行。 证据：`README.md` Claim：`clm_0003` supported 0.86\n\n### 现在还不能相信\n\n- **工具权限边界不能在安装前相信。**（unverified）：MCP/tool 类项目通常会触碰文件、网络、浏览器或外部 API，必须真实检查权限和日志。\n- **真实输出质量不能在安装前相信。**（unverified）：Prompt Preview 只能展示引导方式，不能证明真实项目中的结果质量。\n- **宿主 AI 版本兼容性不能在安装前相信。**（unverified）：Claude、Cursor、Codex、Gemini 等宿主加载规则和版本差异必须在真实环境验证。\n- **不会污染现有宿主 AI 行为，不能直接相信。**（inferred）：Skill、plugin、AGENTS/CLAUDE/GEMINI 指令可能改变宿主 AI 的默认行为。\n- **可安全回滚不能默认相信。**（unverified）：除非项目明确提供卸载和恢复说明，否则必须先在隔离环境验证。\n- **真实安装后是否与用户当前宿主 AI 版本兼容？**（unverified）：兼容性只能通过实际宿主环境验证。\n- **项目输出质量是否满足用户具体任务？**（unverified）：安装前预览只能展示流程和边界，不能替代真实评测。\n- **安装命令是否需要网络、权限或全局写入？**（unverified）：这影响企业环境和个人环境的安装风险。 证据：`README.md`\n\n### 继续会触碰什么\n\n- **命令执行**：包管理器、网络下载、本地插件目录、项目配置或用户主目录。 原因：运行第一条命令就可能产生环境改动；必须先判断是否值得跑。 证据：`README.md`\n- **本地环境或项目文件**：安装结果、插件缓存、项目配置或本地依赖目录。 原因：安装前无法证明写入范围和回滚方式，需要隔离验证。 证据：`README.md`\n- **环境变量 / API Key**：项目入口文档明确出现 API key、token、secret 或账号凭证配置。 原因：如果真实安装需要凭证，应先使用测试凭证并经过权限/合规判断。 证据：`DOCKER.md`, `README.md`, `helm/statewave/README.md`, `infra/postgres-pgvector/README.md` 等\n- **宿主 AI 上下文**：AI Context Pack、Prompt Preview、Skill 路由、风险规则和项目事实。 原因：导入上下文会影响宿主 AI 后续判断，必须避免把未验证项包装成事实。\n\n### 最小安全下一步\n\n- **先跑 Prompt Preview**：用安装前交互式试用判断工作方式是否匹配，不需要授权或改环境。（适用：任何项目都适用，尤其是输出质量未知时。）\n- **只在隔离目录或测试账号试装**：避免安装命令污染主力宿主 AI、真实项目或用户主目录。（适用：存在命令执行、插件配置或本地写入线索时。）\n- **不要使用真实生产凭证**：环境变量/API key 一旦进入宿主或工具链，可能产生账号和合规风险。（适用：出现 API、TOKEN、KEY、SECRET 等环境线索时。）\n- **安装后只验证一个最小任务**：先验证加载、兼容、输出质量和回滚，再决定是否深用。（适用：准备从试用进入真实工作流时。）\n\n### 退出方式\n\n- **保留安装前状态**：记录原始宿主配置和项目状态，后续才能判断是否可恢复。\n- **记录安装命令和写入路径**：没有明确卸载说明时，至少要知道哪些目录或配置需要手动清理。\n- **准备撤销测试 API key 或 token**：测试凭证泄露或误用时，可以快速止损。\n- **如果没有回滚路径，不进入主力环境**：不可回滚是继续前阻断项，不应靠信任或运气继续。\n\n## 哪些只能预览\n\n- 解释项目适合谁和能做什么\n- 基于项目文档演示典型对话流程\n- 帮助用户判断是否值得安装或继续研究\n\n## 哪些必须安装后验证\n\n- 真实安装 Skill、插件或 CLI\n- 执行脚本、修改本地文件或访问外部服务\n- 验证真实输出质量、性能和兼容性\n\n## 边界与风险判断卡\n\n- **把安装前预览误认为真实运行**：用户可能高估项目已经完成的配置、权限和兼容性验证。 处理方式：明确区分 prompt_preview_can_do 与 runtime_required。 Claim：`clm_0010` inferred 0.45\n- **命令执行会修改本地环境**：安装命令可能写入用户主目录、宿主插件目录或项目配置。 处理方式：先在隔离环境或测试账号中运行。 证据：`README.md` Claim：`clm_0011` supported 0.86\n- **待确认**：真实安装后是否与用户当前宿主 AI 版本兼容？。原因：兼容性只能通过实际宿主环境验证。\n- **待确认**：项目输出质量是否满足用户具体任务？。原因：安装前预览只能展示流程和边界，不能替代真实评测。\n- **待确认**：安装命令是否需要网络、权限或全局写入？。原因：这影响企业环境和个人环境的安装风险。\n\n## 开工前工作上下文\n\n### 加载顺序\n\n- 先读取 how_to_use.host_ai_instruction，建立安装前判断资产的边界。\n- 读取 claim_graph_summary，确认事实来自 Claim/Evidence Graph，而不是 Human Wiki 叙事。\n- 再读取 intended_users、capabilities 和 quick_start_candidates，判断用户是否匹配。\n- 需要执行具体任务时，优先查 role_skill_index，再查 evidence_index。\n- 遇到真实安装、文件修改、网络访问、性能或兼容性问题时，转入 risk_card 和 boundaries.runtime_required。\n\n### 任务路由\n\n- **命令行启动或安装流程**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`README.md` Claim：`clm_0001` supported 0.86\n\n### 上下文规模\n\n- 文件总数：230\n- 重要文件覆盖：40/230\n- 证据索引条目：50\n- 角色 / Skill 条目：17\n\n### 证据不足时的处理\n\n- **missing_evidence**：说明证据不足，要求用户提供目标文件、README 段落或安装后验证记录；不要补全事实。\n- **out_of_scope_request**：说明该任务超出当前 AI Context Pack 证据范围，并建议用户先查看 Human Manual 或真实安装后验证。\n- **runtime_request**：给出安装前检查清单和命令来源，但不要替用户执行命令或声称已执行。\n- **source_conflict**：同时展示冲突来源，标记为待核实，不要强行选择一个版本。\n\n## Prompt Recipes\n\n### 适配判断\n\n- 目标：判断这个项目是否适合用户当前任务。\n- 预期输出：适配结论、关键理由、证据引用、安装前可预览内容、必须安装后验证内容、下一步建议。\n\n```text\n请基于 statewave 的 AI Context Pack，先问我 3 个必要问题，然后判断它是否适合我的任务。回答必须包含：适合谁、能做什么、不能做什么、是否值得安装、证据来自哪里。所有项目事实必须引用 evidence_refs、source_paths 或 claim_id。\n```\n\n### 安装前体验\n\n- 目标：让用户在安装前感受核心工作流，同时避免把预览包装成真实能力或营销承诺。\n- 预期输出：一段带边界标签的体验剧本、安装后验证清单和谨慎建议；不含真实运行承诺或强营销表述。\n\n```text\n请把 statewave 当作安装前体验资产，而不是已安装工具或真实运行环境。\n\n请严格输出四段：\n1. 先问我 3 个必要问题。\n2. 给出一段“体验剧本”：用 [安装前可预览]、[必须安装后验证]、[证据不足] 三种标签展示它可能如何引导工作流。\n3. 给出安装后验证清单：列出哪些能力只有真实安装、真实宿主加载、真实项目运行后才能确认。\n4. 给出谨慎建议：只能说“值得继续研究/试装”“先补充信息后再判断”或“不建议继续”，不得替项目背书。\n\n硬性边界：\n- 不要声称已经安装、运行、执行测试、修改文件或产生真实结果。\n- 不要写“自动适配”“确保通过”“完美适配”“强烈建议安装”等承诺性表达。\n- 如果描述安装后的工作方式，必须使用“如果安装成功且宿主正确加载 Skill，它可能会……”这种条件句。\n- 体验剧本只能写成“示例台词/假设流程”：使用“可能会询问/可能会建议/可能会展示”，不要写“已写入、已生成、已通过、正在运行、正在生成”。\n- Prompt Preview 不负责给安装命令；如用户准备试装，只能提示先阅读 Quick Start 和 Risk Card，并在隔离环境验证。\n- 所有项目事实必须来自 supported claim、evidence_refs 或 source_paths；inferred/unverified 只能作风险或待确认项。\n\n```\n\n### 角色 / Skill 选择\n\n- 目标：从项目里的角色或 Skill 中挑选最匹配的资产。\n- 预期输出：候选角色或 Skill 列表，每项包含适用场景、证据路径、风险边界和是否需要安装后验证。\n\n```text\n请读取 role_skill_index，根据我的目标任务推荐 3-5 个最相关的角色或 Skill。每个推荐都要说明适用场景、可能输出、风险边界和 evidence_refs。\n```\n\n### 风险预检\n\n- 目标：安装或引入前识别环境、权限、规则冲突和质量风险。\n- 预期输出：环境、权限、依赖、许可、宿主冲突、质量风险和未知项的检查清单。\n\n```text\n请基于 risk_card、boundaries 和 quick_start_candidates，给我一份安装前风险预检清单。不要替我执行命令，只说明我应该检查什么、为什么检查、失败会有什么影响。\n```\n\n### 宿主 AI 开工指令\n\n- 目标：把项目上下文转成一次对话开始前的宿主 AI 指令。\n- 预期输出：一段边界明确、证据引用明确、适合复制给宿主 AI 的开工前指令。\n\n```text\n请基于 statewave 的 AI Context Pack，生成一段我可以粘贴给宿主 AI 的开工前指令。这段指令必须遵守 not_runtime=true，不能声称项目已经安装、运行或产生真实结果。\n```\n\n\n## 角色 / Skill 索引\n\n- 共索引 17 个角色 / Skill / 项目文档条目。\n\n- **Statewave**（project_doc）：! CI https://github.com/smaramwbc/statewave/workflows/CI/badge.svg https://github.com/smaramwbc/statewave/actions/workflows/ci.yml ! License: AGPL-3.0 + Commercial https://img.shields.io/badge/license-AGPL--3.0%20%2B%20Commercial-blue.svg LICENSING.md ! Python 3.11+ https://img.shields.io/badge/python-3.11%2B-blue.svg https://www.python.org/ 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.md`\n- **Statewave Helm chart**（project_doc）：Deploys the Statewave API on Kubernetes. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`helm/statewave/README.md`\n- **Fly Postgres + pgvector — deployment runbook**（project_doc）：Fly Postgres + pgvector — deployment runbook 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`infra/postgres-pgvector/README.md`\n- **Server-side evals**（project_doc）：Internal regression tools for measuring server behaviour. These hit a live Statewave deployment admin endpoints included and are intended for the maintainers of this repo, not for external developers — see statewave-examples https://github.com/smaramwbc/statewave-examples for developer-facing demos. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`scripts/eval/README.md`\n- **Contributing to Statewave**（project_doc）：Thanks for your interest in contributing — Statewave is built in the open and external contributions are very welcome. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CONTRIBUTING.md`\n- **Statewave Commercial Licensing — Tiers**（project_doc）：Statewave Commercial Licensing — Tiers 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/licensing.md`\n- **Memory portability — admin API reference**（project_doc）：Memory portability — admin API reference 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/memory-portability.md`\n- **State-assembly receipts — design & reference**（project_doc）：State-assembly receipts — design & reference 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/state-assembly-receipts.md`\n- **Description**（project_doc）：- 🐛 Bug fix non-breaking change that fixes an issue - ✨ New feature non-breaking change that adds functionality - 💥 Breaking change fix or feature that would cause existing functionality to change - 📚 Documentation update - 🔧 Maintenance refactoring, dependencies, CI, etc. - 🧪 Test improvement 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`.github/PULL_REQUEST_TEMPLATE.md`\n- **Code of Conduct**（project_doc）：Statewave adopts the Contributor Covenant, version 2.1 as its Code of Conduct. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CODE_OF_CONDUCT.md`\n- **Statewave Commercial License**（project_doc）：Statewave is dual-licensed. You may use it under the terms of the GNU Affero General Public License v3.0 LICENSE , or under a separate commercial license agreement with Statewave. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`COMMERCIAL-LICENSE.md`\n- **Statewave server**（project_doc）：Open-source memory runtime for AI agents — episodes in, distilled memories out. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`DOCKER.md`\n- **Licensing**（project_doc）：1. Open source — GNU Affero General Public License v3.0 LICENSE AGPLv3 2. Commercial — a separate Statewave Commercial License COMMERCIAL-LICENSE.md for proprietary, SaaS, embedded, hosted, or enterprise use. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`LICENSING.md`\n- **NOTICE**（project_doc）：Statewave Copyright c Statewave contributors. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`NOTICE.md`\n- **Security Policy**（project_doc）：Version Supported ------- ------------------ latest ✅ < latest ❌ upgrade recommended 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`SECURITY.md`\n- **Support**（project_doc）：Welcome to Statewave! Here's how to get help. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`SUPPORT.md`\n- **Statewave Trademark Policy**（project_doc）：The name \"Statewave\" , the Statewave logo, and related branding the \"Statewave Marks\" are project and company marks. The open-source license that covers the source code of Statewave AGPLv3 does not grant any rights to use the Statewave Marks. This policy describes the limited use we permit without a separate written agreement. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`TRADEMARKS.md`\n\n## 证据索引\n\n- 共索引 50 条证据。\n\n- **Statewave**（documentation）：! CI https://github.com/smaramwbc/statewave/workflows/CI/badge.svg https://github.com/smaramwbc/statewave/actions/workflows/ci.yml ! License: AGPL-3.0 + Commercial https://img.shields.io/badge/license-AGPL--3.0%20%2B%20Commercial-blue.svg LICENSING.md ! Python 3.11+ https://img.shields.io/badge/python-3.11%2B-blue.svg https://www.python.org/ 证据：`README.md`\n- **Statewave Helm chart**（documentation）：Deploys the Statewave API on Kubernetes. 证据：`helm/statewave/README.md`\n- **Fly Postgres + pgvector — deployment runbook**（documentation）：Fly Postgres + pgvector — deployment runbook 证据：`infra/postgres-pgvector/README.md`\n- **Server-side evals**（documentation）：Internal regression tools for measuring server behaviour. These hit a live Statewave deployment admin endpoints included and are intended for the maintainers of this repo, not for external developers — see statewave-examples https://github.com/smaramwbc/statewave-examples for developer-facing demos. 证据：`scripts/eval/README.md`\n- **Contributing to Statewave**（documentation）：Thanks for your interest in contributing — Statewave is built in the open and external contributions are very welcome. 证据：`CONTRIBUTING.md`\n- **License**（source_file）：GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 证据：`LICENSE`\n- **Statewave Commercial Licensing — Tiers**（documentation）：Statewave Commercial Licensing — Tiers 证据：`docs/licensing.md`\n- **Memory portability — admin API reference**（documentation）：Memory portability — admin API reference 证据：`docs/memory-portability.md`\n- **State-assembly receipts — design & reference**（documentation）：State-assembly receipts — design & reference 证据：`docs/state-assembly-receipts.md`\n- **Description**（documentation）：- 🐛 Bug fix non-breaking change that fixes an issue - ✨ New feature non-breaking change that adds functionality - 💥 Breaking change fix or feature that would cause existing functionality to change - 📚 Documentation update - 🔧 Maintenance refactoring, dependencies, CI, etc. - 🧪 Test improvement 证据：`.github/PULL_REQUEST_TEMPLATE.md`\n- **Code of Conduct**（documentation）：Statewave adopts the Contributor Covenant, version 2.1 as its Code of Conduct. 证据：`CODE_OF_CONDUCT.md`\n- **Statewave Commercial License**（documentation）：Statewave is dual-licensed. You may use it under the terms of the GNU Affero General Public License v3.0 LICENSE , or under a separate commercial license agreement with Statewave. 证据：`COMMERCIAL-LICENSE.md`\n- **Statewave server**（documentation）：Open-source memory runtime for AI agents — episodes in, distilled memories out. 证据：`DOCKER.md`\n- **Licensing**（documentation）：1. Open source — GNU Affero General Public License v3.0 LICENSE AGPLv3 2. Commercial — a separate Statewave Commercial License COMMERCIAL-LICENSE.md for proprietary, SaaS, embedded, hosted, or enterprise use. 证据：`LICENSING.md`\n- **NOTICE**（documentation）：Statewave Copyright c Statewave contributors. 证据：`NOTICE.md`\n- **Security Policy**（documentation）：Version Supported ------- ------------------ latest ✅ < latest ❌ upgrade recommended 证据：`SECURITY.md`\n- **Support**（documentation）：Welcome to Statewave! Here's how to get help. 证据：`SUPPORT.md`\n- **Statewave Trademark Policy**（documentation）：The name \"Statewave\" , the Statewave logo, and related branding the \"Statewave Marks\" are project and company marks. The open-source license that covers the source code of Statewave AGPLv3 does not grant any rights to use the Statewave Marks. This policy describes the limited use we permit without a separate written agreement. 证据：`TRADEMARKS.md`\n- **Manifest**（structured_config）：{ \"format\": \"statewave-starter-pack\", \"format version\": 1, \"pack id\": \"demo-coding-assistant\", \"display name\": \"Coding Assistant\", \"description\": \"Coding-assistant showcase pack: a developer Priya working on the Stratus codebase across roughly two months. Captures stack choices TS strict + Tailwind frontend, FastAPI + SQLModel + Pydantic v2 backend , style preferences composition over inheritance, top-level async, conventional-commits , an architecture decision log, an in-flight auth-middleware refactor with a documented blocker, a session-pool race fix that becomes a reusable diagnostic, and a no-mocks test policy traced to a real incident. Demonstrates preference layering, decision proven… 证据：`server/starter_packs/demo-coding-assistant/manifest.json`\n- **Manifest**（structured_config）：{ \"format\": \"statewave-starter-pack\", \"format version\": 1, \"pack id\": \"demo-devops-agent\", \"display name\": \"DevOps Agent\", \"description\": \"DevOps showcase pack: an SRE running the nimbus-api service across three months \\u2014 March pool-exhaustion outage with PgBouncer mitigation, secrets/backup/DB-failover runbooks, observability stack decision Datadog over Grafana Cloud , a noisy-alerts post-mortem that rewrote alert thresholds, a TLS rotation incident that split staging/prod issuers, deploy-window and phased-migration policies, and a canary deploy framework that cut rollback time from 6m to 30s. Demonstrates runbook recall, decision provenance, recurring-incident detection, and operation… 证据：`server/starter_packs/demo-devops-agent/manifest.json`\n- **Manifest**（structured_config）：{ \"format\": \"statewave-starter-pack\", \"format version\": 1, \"pack id\": \"demo-research-assistant\", \"display name\": \"Research Assistant\", \"description\": \"Research-assistant showcase pack: a researcher Arushi writing a NeurIPS 2026 submission on agent memory across four months \\u2014 citation conventions, an active draft with section-level progress and a settled architectural decision hard temporal-validity cutoffs over sigmoid decay , a co-author dynamic with Dr. Mei Wu at Berkeley, two empirical experiments compiler-density and multi-session-recall that supply paper results, an ICLR 2026 poster acceptance, a tooling stack with explicit anti-preferences, and personal work habits. Demonstrates… 证据：`server/starter_packs/demo-research-assistant/manifest.json`\n- **Manifest**（structured_config）：{ \"format\": \"statewave-starter-pack\", \"format version\": 1, \"pack id\": \"demo-sales-copilot\", \"display name\": \"Sales Copilot\", \"description\": \"Sales-copilot showcase pack: a rep Tom running a four-account pipeline across three months \\u2014 Acme Corp closed expansion + Q3 renewal vector , BetaTech SOC 2 cleared, in pricing negotiation , Cirrus Robotics churned then re-engaged with a new VP , and Delta Health HIPAA / BAA prospect . Captures decision-makers, contact preferences, AE routing, competitive positioning vs Mem0, HIPAA procurement order, and a closing-quarter pipeline summary. Demonstrates multi-subject identity, cross-account procedures, deal-stage history, win-back signals, and comp… 证据：`server/starter_packs/demo-sales-copilot/manifest.json`\n- **Manifest**（structured_config）：{ \"format\": \"statewave-starter-pack\", \"format version\": 1, \"pack id\": \"demo-support-agent\", \"display name\": \"Default Support Agent\", \"description\": \"Customer-support showcase pack: a multi-session story arc for one representative customer Northwind Logistics, Team plan, EU region covering onboarding, integration preferences, an SSO incident, repeat-issue detection, billing, an SLA-breached ticket with service credit, and a renewal signal. Demonstrates identity persistence, preference layering, procedure recall, prior-issue surfacing, and SLA awareness.\", \"version\": \"2.2026.05.06-focused\", \"created at\": \"2026-05-06T15:25:56.070391+00:00\", \"subject id suggestion\": \"demo-support-agent\", \"episo… 证据：`server/starter_packs/demo-support-agent/manifest.json`\n- **Index**（structured_config）：{ \"format\": \"statewave-starter-pack-index\", \"format version\": 1, \"packs\": { \"pack id\": \"statewave-support-agent\", \"kind\": \"support docs\", \"directory\": \"statewave-support-agent\" }, { \"pack id\": \"demo-support-agent\", \"kind\": \"demo agent\", \"directory\": \"demo-support-agent\" }, { \"pack id\": \"demo-coding-assistant\", \"kind\": \"demo agent\", \"directory\": \"demo-coding-assistant\" }, { \"pack id\": \"demo-sales-copilot\", \"kind\": \"demo agent\", \"directory\": \"demo-sales-copilot\" }, { \"pack id\": \"demo-devops-agent\", \"kind\": \"demo agent\", \"directory\": \"demo-devops-agent\" }, { \"pack id\": \"demo-research-assistant\", \"kind\": \"demo agent\", \"directory\": \"demo-research-assistant\" } } 证据：`server/starter_packs/index.json`\n- **Manifest**（structured_config）：{ \"format\": \"statewave-starter-pack\", \"format version\": 1, \"pack id\": \"statewave-support-agent\", \"display name\": \"Statewave Support\", \"description\": \"Full Statewave Support docs pack \\u2014 every curated section in statewave-docs chunked at heading boundaries, ingested as episodes, and compiled to memories. Importing this pack into the statewave-support-docs subject powers the docs-grounded support agent on day one with no extra bootstrap step.\", \"version\": \"1.2026.05.08\", \"created at\": \"2026-05-08T13:35:42.704407+00:00\", \"subject id suggestion\": \"statewave-support-docs\", \"episode count\": 276, \"memory count\": 364, \"source count\": 0, \"tags\": \"starter-pack\", \"platform-bundled\", \"docs-grounded… 证据：`server/starter_packs/statewave-support-agent/manifest.json`\n- **Build context exclusions for docker build / docker compose build .**（source_file）：Build context exclusions for docker build / docker compose build . Keeps developer-local config and dev artifacts OUT of the image, so the environment: block in docker-compose.yml is the single source of truth for runtime config — no surprise overrides from a baked-in .env . 证据：`.dockerignore`\n- **──────────────────────────────────────────────────**（source_file）：────────────────────────────────────────────────── Statewave — Environment Configuration Quickstart: 1. cp .env.example .env 2. Set STATEWAVE LITELLM API KEY below recommended . 3. docker compose up -d All variables are prefixed STATEWAVE . Values left commented use the defaults baked into server/core/config.py. ────────────────────────────────────────────────── 证据：`.env.example`\n- **Funding**（source_file）：github: smaramwbc 证据：`.github/FUNDING.yml`\n- **Dependabot**（source_file）：version: 2 updates: - package-ecosystem: \"pip\" directory: \"/\" schedule: interval: \"weekly\" open-pull-requests-limit: 10 labels: - \"dependencies\" commit-message: prefix: \"chore deps :\" 证据：`.github/dependabot.yml`\n- **.gitignore**（source_file）：pycache / .pyc .env .egg-info/ dist/ .venv/ .pytest cache/ 证据：`.gitignore`\n- **Dockerfile**（source_file）：COPY pyproject.toml README.md ./ RUN pip install --no-cache-dir \". llm \" 证据：`Dockerfile`\n- **Alembic**（source_file）：alembic script location = alembic sqlalchemy.url = postgresql+asyncpg://statewave:statewave@localhost:5432/statewave 证据：`alembic.ini`\n- **Override sqlalchemy.url from env. STATEWAVE DATABASE URL is the first-class**（source_file）：\"\"\"Alembic env — async Postgres migrations.\"\"\" 证据：`alembic/env.py`\n- **revision identifiers, used by Alembic.**（source_file）：Revision ID: ${up revision} Revises: ${down revision comma,n} Create Date: ${create date} \"\"\" from typing import Sequence, Union 证据：`alembic/script.py.mako`\n- **Default to the published multi-arch image — docker compose up -d works**（source_file）：services: db: image: pgvector/pgvector:pg16 environment: POSTGRES USER: statewave POSTGRES PASSWORD: statewave POSTGRES DB: statewave ports: - \"5432:5432\" volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: \"CMD-SHELL\", \"pg isready -U statewave\" interval: 2s timeout: 5s retries: 10 证据：`docker-compose.yml`\n- **Production seeds the docs pack via the dedicated GitHub Actions**（source_file）：app = 'statewave-api' primary region = 'ord' 证据：`fly.toml`\n- **Pyproject**（source_file）：project name = \"statewave\" version = \"0.8.0\" description = \"Open-source memory runtime for AI agents — durable, structured context with provenance.\" readme = \"README.md\" license = {text = \"AGPL-3.0-only OR LicenseRef-Statewave-Commercial\"} requires-python = \" =3.11\" dependencies = \"fastapi =0.136.1, =0.29, =2.7, =2.14.1, =2.0, =0.31.0, =1.13, =0.4.2, =0.12.0, =24.1, =6,<7\", 证据：`pyproject.toml`\n- **Allow running as python scripts/bootstrap docs pack.py from repo root**（source_file）：\"\"\"Bootstrap the default Statewave support docs memory pack. 证据：`scripts/bootstrap_docs_pack.py`\n- **Each persona has:**（source_file）：\"\"\"Bootstrap subject snapshots for demo instant seeding. 证据：`scripts/bootstrap_snapshots.py`\n- **─── Per-persona expansion content ──────────────────────────────────────────**（source_file）：\"\"\"Rebuild the 5 bundled demo starter packs with denser, narrative-consistent content that can sustain 8–10 visitor turns of recallable context. 证据：`scripts/build_demo_packs.py`\n- **Allow running as python scripts/build support pack.py from repo root**（source_file）：\"\"\"Build the bundled Statewave Support starter pack from the live docs corpus. 证据：`scripts/build_support_pack.py`\n- **!/usr/bin/env python**（source_file）：!/usr/bin/env python \"\"\"Bump or verify the project version across all user-facing surfaces. 证据：`scripts/bump_version.py`\n- **Triple shape: source, type, payload-dict . The payload's content field is**（source_file）：\"\"\"New-episode content for the 5 demo persona packs. 证据：`scripts/demo_pack_expansions.py`\n- **Curated allowlist — see statewave-docs/default-support-docs-pack.md**（source_file）：\"\"\"Statewave docs → episodes loader. 证据：`scripts/docs_loader.py`\n- **!/usr/bin/env python**（source_file）：!/usr/bin/env python \"\"\"Migration preflight check. 证据：`scripts/preflight.py`\n- **─── Narrative seed data ─────────────────────────────────────────────────────**（source_file）：\"\"\"Re-seed the website demo subjects with rich many-to-one provenance. 证据：`scripts/seed_demo_subjects.py`\n- **Compile job retention**（source_file）：import asyncio from contextlib import asynccontextmanager from importlib.metadata import PackageNotFoundError, version 证据：`server/app.py`\n- **Main**（source_file）：\"\"\"Entrypoint for running the server directly.\"\"\" 证据：`server/main.py`\n- **!/bin/sh**（source_file）：!/bin/sh Boot script for the Fly.io machine. We wait for Postgres to be reachable before running migrations. On Fly especially with auto stop machines=suspend the database can briefly refuse connections during a wake-up, which previously crashed alembic and put the machine in a restart loop. The retry loop turns that into a soft delay instead of a fatal boot. 证据：`start.sh`\n- **Dispose engine after test to ensure clean state for next test**（source_file）：import pytest from httpx import ASGITransport, AsyncClient 证据：`tests/conftest.py`\n\n## 宿主 AI 必须遵守的规则\n\n- **把本资产当作开工前上下文，而不是运行环境。**：AI Context Pack 只包含证据化项目理解，不包含目标项目的可执行状态。 证据：`README.md`, `helm/statewave/README.md`, `infra/postgres-pgvector/README.md`\n- **回答用户时区分可预览内容与必须安装后才能验证的内容。**：安装前体验的消费者价值来自降低误装和误判，而不是伪装成真实运行。 证据：`README.md`, `helm/statewave/README.md`, `infra/postgres-pgvector/README.md`\n\n## 用户开工前应该回答的问题\n\n- 你准备在哪个宿主 AI 或本地环境中使用它？\n- 你只是想先体验工作流，还是准备真实安装？\n- 你最在意的是安装成本、输出质量、还是和现有规则的冲突？\n\n## 验收标准\n\n- 所有能力声明都能回指到 evidence_refs 中的文件路径。\n- AI_CONTEXT_PACK.md 没有把预览包装成真实运行。\n- 用户能在 3 分钟内看懂适合谁、能做什么、如何开始和风险边界。\n\n---\n\n## Doramagic Context Augmentation\n\n下面内容用于强化 Repomix/AI Context Pack 主体。Human Manual 只提供阅读骨架；踩坑日志会被转成宿主 AI 必须遵守的工作约束。\n\n## Human Manual 骨架\n\n使用规则：这里只是项目阅读路线和显著性信号，不是事实权威。具体事实仍必须回到 repo evidence / Claim Graph。\n\n宿主 AI 硬性规则：\n- 不得把页标题、章节顺序、摘要或 importance 当作项目事实证据。\n- 解释 Human Manual 骨架时，必须明确说它只是阅读路线/显著性信号。\n- 能力、安装、兼容性、运行状态和风险判断必须引用 repo evidence、source path 或 Claim Graph。\n\n- **Overview - What is Statewave?**：importance `high`\n  - source_paths: README.md, server/domain/models.py\n- **Getting Started**：importance `high`\n  - source_paths: README.md, docker-compose.yml, alembic/env.py\n- **System Architecture**：importance `high`\n  - source_paths: server/app.py, server/main.py, server/services/__init__.py, server/core/dependencies.py\n- **Database Schema & Migrations**：importance `high`\n  - source_paths: server/db/tables.py, alembic/env.py, alembic/versions, server/db/engine.py\n- **API Endpoints Reference**：importance `high`\n  - source_paths: server/api/episodes.py, server/api/memories.py, server/api/context.py, server/api/subjects.py, server/api/resolutions.py\n- **Context Assembly & Ranking**：importance `high`\n  - source_paths: server/services/context.py, server/api/context.py\n- **Compilation Services**：importance `high`\n  - source_paths: server/services/compiler.py, server/services/compilers/heuristic.py, server/services/compilers/llm.py, server/services/conflicts.py, server/services/compile_jobs.py\n- **Embedding Services**：importance `medium`\n  - source_paths: server/services/embeddings/litellm.py, server/services/embeddings/stub.py, server/services/embeddings/query_cache.py, server/services/embeddings/backfill.py\n\n## Repo Inspection Evidence / 源码检查证据\n\n- repo_clone_verified: true\n- repo_inspection_verified: true\n- repo_commit: `28ff5ad08131d9e387478d6f9d5a53c279680435`\n- inspected_files: `pyproject.toml`, `Dockerfile`, `README.md`, `docker-compose.yml`, `uv.lock`, `docs/state-assembly-receipts.md`, `docs/memory-portability.md`\n\n宿主 AI 硬性规则：\n- 没有 repo_clone_verified=true 时，不得声称已经读过源码。\n- 没有 repo_inspection_verified=true 时，不得把 README/docs/package 文件判断写成事实。\n- 没有 quick_start_verified=true 时，不得声称 Quick Start 已跑通。\n\n## Doramagic Pitfall Constraints / 踩坑约束\n\n这些规则来自 Doramagic 发现、验证或编译过程中的项目专属坑点。宿主 AI 必须把它们当作工作约束，而不是普通说明文字。\n\n### Constraint 1: 能力判断依赖假设\n\n- Trigger: README/documentation is current enough for a first validation pass.\n- Host AI rule: 将假设转成下游验证清单。\n- Why it matters: 假设不成立时，用户拿不到承诺的能力。\n- Evidence: capability.assumptions | github_repo:1219923941 | https://github.com/smaramwbc/statewave | README/documentation is current enough for a first validation pass.\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 2: 维护活跃度未知\n\n- Trigger: 未记录 last_activity_observed。\n- Host AI rule: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Why it matters: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Evidence: evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | last_activity_observed missing\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 3: 下游验证发现风险项\n\n- Trigger: no_demo\n- Host AI rule: 进入安全/权限治理复核队列。\n- Why it matters: 下游已经要求复核，不能在页面中弱化。\n- Evidence: downstream_validation.risk_items | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 4: 存在评分风险\n\n- Trigger: no_demo\n- Host AI rule: 把风险写入边界卡，并确认是否需要人工复核。\n- Why it matters: 风险会影响是否适合普通用户安装。\n- Evidence: risks.scoring_risks | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 5: issue/PR 响应质量未知\n\n- Trigger: issue_or_pr_quality=unknown。\n- Host AI rule: 抽样最近 issue/PR，判断是否长期无人处理。\n- Why it matters: 用户无法判断遇到问题后是否有人维护。\n- Evidence: evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | issue_or_pr_quality=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 6: 发布节奏不明确\n\n- Trigger: release_recency=unknown。\n- Host AI rule: 确认最近 release/tag 和 README 安装命令是否一致。\n- Why it matters: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Evidence: evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | release_recency=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n",
      "summary": "给宿主 AI 的上下文和工作边界。",
      "title": "AI Context Pack / 带给我的 AI"
    },
    "boundary_risk_card": {
      "asset_id": "boundary_risk_card",
      "filename": "BOUNDARY_RISK_CARD.md",
      "markdown": "# Boundary & Risk Card / 安装前决策卡\n\n项目：smaramwbc/statewave\n\n## Doramagic 试用结论\n\n当前结论：可以进入发布前推荐检查；首次使用仍应从最小权限、临时目录和可回滚配置开始。\n\n## 用户现在可以做\n\n- 可以先阅读 Human Manual，理解项目目的和主要工作流。\n- 可以复制 Prompt Preview 做安装前体验；这只验证交互感，不代表真实运行。\n- 可以把官方 Quick Start 命令放到隔离环境中验证，不要直接进主力环境。\n\n## 现在不要做\n\n- 不要把 Prompt Preview 当成项目实际运行结果。\n- 不要把 metadata-only validation 当成沙箱安装验证。\n- 不要把未验证能力写成“已支持、已跑通、可放心安装”。\n- 不要在首次试用时交出生产数据、私人文件、真实密钥或主力配置目录。\n\n## 安装前检查\n\n- 宿主 AI 是否匹配：local_cli\n- 官方安装入口状态：已发现官方入口\n- 是否在临时目录、临时宿主或容器中验证：必须是\n- 是否能回滚配置改动：必须能\n- 是否需要 API Key、网络访问、读写文件或修改宿主配置：未确认前按高风险处理\n- 是否记录了安装命令、实际输出和失败日志：必须记录\n\n## 当前阻塞项\n\n- 无阻塞项。\n\n## 项目专属踩坑\n\n- 能力判断依赖假设（medium）：假设不成立时，用户拿不到承诺的能力。 建议检查：将假设转成下游验证清单。\n- 维护活跃度未知（medium）：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 下游验证发现风险项（medium）：下游已经要求复核，不能在页面中弱化。 建议检查：进入安全/权限治理复核队列。\n- 存在评分风险（medium）：风险会影响是否适合普通用户安装。 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- issue/PR 响应质量未知（low）：用户无法判断遇到问题后是否有人维护。 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n\n## 风险与权限提示\n\n- no_demo: medium\n\n## 证据缺口\n\n- 暂未发现结构化证据缺口。\n",
      "summary": "安装、权限、验证和推荐前风险。",
      "title": "Boundary & Risk Card / 边界与风险卡"
    },
    "human_manual": {
      "asset_id": "human_manual",
      "filename": "HUMAN_MANUAL.md",
      "markdown": "# https://github.com/smaramwbc/statewave 项目说明书\n\n生成时间：2026-05-15 10:02:16 UTC\n\n## 目录\n\n- [Overview - What is Statewave?](#page-overview)\n- [Getting Started](#page-getting-started)\n- [System Architecture](#page-architecture)\n- [Database Schema & Migrations](#page-database-schema)\n- [API Endpoints Reference](#page-api-endpoints)\n- [Context Assembly & Ranking](#page-context-assembly)\n- [Compilation Services](#page-compilation-services)\n- [Embedding Services](#page-embeddings)\n- [Governance - Receipts & Policy Engine](#page-receipts-policy)\n- [Multi-tenancy & Security](#page-multi-tenancy)\n\n<a id='page-overview'></a>\n\n## Overview - What is Statewave?\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Getting Started](#page-getting-started)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n- [SUPPORT.md](https://github.com/smaramwbc/statewave/blob/main/SUPPORT.md)\n- [DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n- [CONTRIBUTING.md](https://github.com/smaramwbc/statewave/blob/main/CONTRIBUTING.md)\n- [scripts/bootstrap_docs_pack.py](https://github.com/smaramwbc/statewave/blob/main/scripts/bootstrap_docs_pack.py)\n- [scripts/docs_loader.py](https://github.com/smaramwbc/statewave/blob/main/scripts/docs_loader.py)\n- [scripts/eval/eval_docs_support.py](https://github.com/smaramwbc/statewave/blob/main/scripts/eval/eval_docs_support.py)\n- [server/starter_packs/statewave-support-agent/manifest.json](https://github.com/smaramwbc/statewave/blob/main/server/starter_packs/statewave-support-agent/manifest.json)\n</details>\n\n# Overview - What is Statewave?\n\nStatewave is a self-hosted **memory infrastructure** for AI agents. It enables AI systems to store, retrieve, compile, and reason over long-term contextual information across conversations and sessions.\n\n## Core Concept\n\nStatewave solves the memory problem for AI agents by providing:\n\n- **Episode Ingestion** — Capture events, conversations, and real-world signals as structured memory units\n- **Memory Compilation** — Transform raw episodes into refined, actionable memories using LLM or heuristic approaches\n- **Context Assembly** — Retrieve and rank relevant memories within token budgets for inference\n- **Temporal Reasoning** — Track state changes and resolution status over time\n\nThe system operates as a REST API service that agents and applications query to build persistent, evolving memory without hand-writing custom storage and retrieval logic for each use case.\n\n## Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"Sources\"\n        MCP[MCP Server]\n        GH[GitHub]\n        MD[Markdown Docs]\n        SL[Slack]\n        APP[Application]\n    end\n\n    subgraph \"Statewave Core\"\n        INGEST[Ingestion API]\n        COMPILE[Memory Compiler]\n        SEARCH[Search API]\n        CONTEXT[Context Assembly]\n    end\n\n    subgraph \"Storage\"\n        PG[(PostgreSQL<br/>+ pgvector)]\n    end\n\n    MCP --> INGEST\n    GH --> INGEST\n    MD --> INGEST\n    SL --> INGEST\n    APP --> INGEST\n\n    INGEST --> PG\n    COMPILE --> PG\n    SEARCH --> PG\n    CONTEXT --> PG\n\n    APP --> SEARCH\n    APP --> CONTEXT\n```\n\n## Key Components\n\n| Component | Description |\n|-----------|-------------|\n| **Episodes** | Raw, append-only event records captured from sources (conversations, issues, documents, etc.) |\n| **Memories** | Compiled, refined knowledge derived from episodes through LLM or heuristic processing |\n| **Subjects** | Logical namespaces grouping episodes and memories (typically one per user, customer, or agent persona) |\n| **Resolutions** | Tracking of issue/session completion state per subject |\n| **Context Bundle** | Ranked, token-bounded response assembled from relevant memories for inference |\n\n## Data Flow\n\n```mermaid\ngraph LR\n    A[Source Event] --> B[POST /v1/episodes]\n    B --> C[(Episode Store)]\n    C --> D[POST /v1/memories/compile]\n    D --> E[(Memory Store)]\n    E --> F[GET /v1/memories/search]\n    F --> G[POST /v1/context]\n    G --> H[Ranked Context Bundle]\n```\n\n## API Reference\n\n### Core Endpoints\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/episodes` | Ingest a single episode (append-only) |\n| `POST` | `/v1/episodes/batch` | Ingest up to 100 episodes at once |\n| `POST` | `/v1/memories/compile` | Compile memories from episodes (idempotent) |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n\n### Subject Management\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n| `DELETE` | `/v1/subjects/{id}` | Permanently delete all data for a subject |\n| `GET` | `/v1/subjects/{id}/health` | Customer health score with explainable factors |\n| `GET` | `/v1/subjects/{id}/sla` | SLA metrics — response time, resolution time, breaches |\n\n### Resolution Tracking\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/resolutions` | Track issue resolution state per session |\n| `GET` | `/v1/resolutions` | List resolutions for a subject |\n\n### Additional Endpoints\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/handoff` | Generate compact handoff context pack |\n| `GET` | `/healthz` or `/health` | Liveness check |\n| `GET` | `/readyz` or `/ready` | Readiness check |\n\n资料来源：[README.md:26-49](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Connectors\n\nStatewave is not limited to live chat transcripts. **Connectors** feed real-world events into Statewave as episodes, enabling agents to build memory from diverse sources.\n\n| Source | Memory Shape | Status |\n|--------|--------------|--------|\n| MCP server | Copilot / Claude / Cursor / agent memory | ✅ Shipped |\n| GitHub | Issues, PRs, reviews, releases → repo memory | ✅ Shipped |\n| Markdown | Local docs, ADRs, RFCs → decision memory | ✅ Shipped |\n| Slack | Channel messages → conversation memory | ✅ Shipped |\n\n资料来源：[README.md:53-60](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Deployment\n\n### Docker Deployment\n\nStatewave is deployed as a containerized service using Docker Compose:\n\n```yaml\nservices:\n  app:\n    image: statewavedev/statewave:latest\n    ports: [\"8100:8100\"]\n    environment:\n      STATEWAVE_DATABASE_URL: postgresql+asyncpg://statewave:statewave@db:5432/statewave\n      STATEWAVE_LITELLM_API_KEY: sk-...\n    depends_on:\n      db:\n        condition: service_healthy\n```\n\n```bash\ndocker compose up -d\ncurl http://localhost:8100/healthz\n```\n\n资料来源：[DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n\n### Environment Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | — | PostgreSQL connection string (required) |\n| `STATEWAVE_LITELLM_API_KEY` | — | LiteLLM API key for LLM compilation |\n| `STATEWAVE_LOG_LEVEL` | `INFO` | Logging verbosity |\n| `STATEWAVE_MAX_CONTEXT_TOKENS` | `4000` | Default token budget for context assembly |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests/min/IP (0 = disabled) |\n| `STATEWAVE_WEBHOOK_URL` | — | Webhook callback URL |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Header for multi-tenant isolation |\n\n资料来源：[README.md:93-107](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Multi-Tenant Support\n\nStatewave supports multi-tenant deployments through application-layer isolation:\n\n- **Tenant Header**: `X-Tenant-ID` header identifies the tenant (configurable via `STATEWAVE_TENANT_HEADER`)\n- **Query-Scoped Isolation**: Data isolation is enforced at the query layer\n- **Per-Tenant Configuration**: Policy bundles and receipts support tenant-specific settings\n\n资料来源：[README.md:100-107](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Documentation System\n\nStatewave includes a documentation-grounded memory system:\n\n- Curated documentation sections are chunked at heading boundaries\n- Each section becomes an episode with `source=\"statewave-docs\"`, `type=\"doc_section\"`\n- Episodes carry a deterministic content hash for change detection\n- A bundled starter pack provides 276 episodes and 364 compiled memories out of the box\n\n资料来源：[scripts/docs_loader.py](https://github.com/smaramwbc/statewave/blob/main/scripts/docs_loader.py)\n资料来源：[server/starter_packs/statewave-support-agent/manifest.json](https://github.com/smaramwbc/statewave/blob/main/server/starter_packs/statewave-support-agent/manifest.json)\n\n## Evaluation Framework\n\nThe repository includes an evaluation framework for testing docs-grounded retrieval:\n\n```python\n@dataclass\nclass Question:\n    task: str\n    expected_doc_paths: list[str]\n    expected_terms: list[str]\n```\n\nSample evaluation questions verify that the system correctly surfaces documentation for queries about deployment, compilation modes, hardware requirements, and API contracts.\n\n资料来源：[scripts/eval/eval_docs_support.py](https://github.com/smaramwbc/statewave/blob/main/scripts/eval/eval_docs_support.py)\n\n## Starter Packs\n\nStatewave ships with pre-built starter packs:\n\n| Pack | Description |\n|------|-------------|\n| `statewave-support-agent` | Full Statewave Support docs pack with 276 episodes and 364 memories |\n| `demo-support-agent` | Support agent persona |\n| `demo-coding-assistant` | Coding assistant persona |\n| `demo-sales-copilot` | Sales copilot persona |\n| `demo-devops-agent` | DevOps agent persona |\n| `demo-research-assistant` | Research assistant persona |\n\n资料来源：[server/starter_packs/statewave-support-agent/manifest.json](https://github.com/smaramwbc/statewave/blob/main/server/starter_packs/statewave-support-agent/manifest.json)\n资料来源：[scripts/build_demo_packs.py](https://github.com/smaramwbc/statewave/blob/main/scripts/build_demo_packs.py)\n\n## Health Monitoring\n\nStatewave provides subject-level health monitoring:\n\n- **Health Score**: Aggregated customer health with explainable factors\n- **SLA Metrics**: Response time, resolution time, and breach tracking\n- **Snapshot Restore**: Restore subject state from snapshots with timestamp shifting\n\n资料来源：[README.md:46-47](https://github.com/smaramwbc/statewave/blob/main/README.md)\n资料来源：[server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n\n## Getting Started\n\n1. **Quick Start**:\n   ```bash\n   docker compose up db -d\n   python -m venv .venv && source .venv/bin/activate\n   pip install -e \".[dev,llm]\"\n   alembic upgrade head\n   uvicorn server.main:app --host 0.0.0.0 --port 8100\n   ```\n\n2. **Run Tests**:\n   ```bash\n   # Unit tests (no DB required)\n   pytest tests/test_*.py -v\n\n   # Integration tests (requires Postgres)\n   PGPASSWORD=statewave createdb -h localhost -U statewave statewave_test\n   pytest tests/integration/ -v\n   ```\n\n资料来源：[CONTRIBUTING.md](https://github.com/smaramwbc/statewave/blob/main/CONTRIBUTING.md)\n资料来源：[README.md:11-19](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Current Limitations\n\n| Limitation | Description |\n|------------|-------------|\n| Rate limiting per-IP | Distributed (Postgres-backed), but keyed by IP only, not per-tenant or per-API-key |\n| Multi-tenant app-layer | Query-scoped data isolation + per-tenant config, but no Postgres RLS |\n\n资料来源：[README.md:117-122](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Repository Structure\n\n| Repository | Purpose |\n|------------|---------|\n| [statewave](https://github.com/smaramwbc/statewave) | Backend API, server, core |\n| [statewave-py](https://github.com/smaramwbc/statewave-py) | Python SDK (`pip install statewave`) |\n| [statewave-ts](https://github.com/smaramwbc/statewave-ts) | TypeScript SDK (`npm install @statewavedev/sdk`) |\n| [statewave-connectors](https://github.com/smaramwbc/statewave-connectors) | Connectors (GitHub, Markdown, MCP, etc.) |\n| [statewave-docs](https://github.com/smaramwbc/statewave-docs) | Documentation |\n| [statewave-examples](https://github.com/smaramwbc/statewave-examples) | Working code examples |\n| [statewave-web](https://github.com/smaramwbc/statewave-web) | Marketing site + embedded demo |\n| [statewave-admin](https://github.com/smaramwbc/statewave-admin) | Admin dashboard |\n\n资料来源：[SUPPORT.md:73-83](https://github.com/smaramwbc/statewave/blob/main/SUPPORT.md)\n\n---\n\n<a id='page-getting-started'></a>\n\n## Getting Started\n\n### 相关页面\n\n相关主题：[Overview - What is Statewave?](#page-overview), [API Endpoints Reference](#page-api-endpoints)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n- [DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n- [helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n- [scripts/bootstrap_docs_pack.py](https://github.com/smaramwbc/statewave/blob/main/scripts/bootstrap_docs_pack.py)\n- [scripts/seed_demo_subjects.py](https://github.com/smaramwbc/statewave/blob/main/scripts/seed_demo_subjects.py)\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n</details>\n\n# Getting Started\n\n## Overview\n\nThe Getting Started guide provides developers and operators with the essential knowledge to install, configure, and run Statewave — an agent memory system that captures, compiles, and retrieves episodic and semantic memory for AI agents. The guide covers three primary deployment paths: Docker Compose for local development, Helm charts for Kubernetes production environments, and Python packages for programmatic integration.\n\nStatewave operates as an append-only memory store where **episodes** represent raw events (chat messages, commits, support tickets) and **memories** are compiled, high-confidence knowledge units derived from episodes through LLM or heuristic processing. The system enables agents to assemble token-bounded context bundles for RAG (Retrieval-Augmented Generation) workflows.\n\n资料来源：[README.md:1-50]()\n\n## System Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Ingestion Layer\"\n        E[Episodes] --> B[Batch Ingest]\n        E --> S[Single Ingest]\n    end\n    \n    subgraph \"Compilation Layer\"\n        S --> COMP[Memory Compiler]\n        B --> COMP\n        COMP -->|LLM or Heuristic| M[Memories]\n    end\n    \n    subgraph \"Retrieval Layer\"\n        M --> CX[Context Assembler]\n        Q[Query] --> CX\n        CX --> CB[Token-Bounded Context]\n    end\n    \n    subgraph \"Storage Layer\"\n        M --> PG[(PostgreSQL)]\n        E --> PG\n    end\n    \n    subgraph \"Connectors\"\n        MCP[MCP Server]\n        GH[GitHub]\n        MD[Markdown]\n        SL[Slack]\n        MCP --> E\n        GH --> E\n        MD --> E\n        SL --> E\n    end\n```\n\n## Prerequisites\n\nBefore beginning the installation, ensure the following requirements are met:\n\n| Requirement | Minimum Version | Purpose |\n|-------------|-----------------|---------|\n| Python | 3.11+ | SDK and CLI usage |\n| Docker | 24.0+ | Container runtime |\n| Docker Compose | 2.20+ | Multi-container orchestration |\n| PostgreSQL | 15+ | Primary data store |\n| Kubernetes | 1.28+ | Production deployment |\n| Helm | 3.14+ | Chart package manager |\n\n资料来源：[DOCKER.md:1-30]()\n\n## Installation Methods\n\n### Quick Start with Docker Compose\n\nThe fastest path to a running Statewave instance uses Docker Compose:\n\n```yaml\n# docker-compose.yml\nservices:\n  api:\n    image: statewavedev/statewave:latest\n    ports: [\"8100:8100\"]\n    environment:\n      STATEWAVE_DATABASE_URL: postgresql+asyncpg://statewave:statewave@db:5432/statewave\n      STATEWAVE_LITELLM_API_KEY: sk-...\n    depends_on:\n      db:\n        condition: service_healthy\n\nvolumes:\n  pgdata:\n```\n\n资料来源：[DOCKER.md:40-55]()\n\nExecute the following commands to start Statewave:\n\n```bash\n# Start the stack\ndocker compose up -d\n\n# Verify health\ncurl http://localhost:8100/healthz\n```\n\n### Pinning a Specific Version\n\nProduction deployments should pin to a specific version:\n\n```bash\nSTATEWAVE_VERSION=0.7.0 docker compose up -d\n```\n\nAvailable tagging conventions:\n\n| Tag Pattern | Meaning |\n|-------------|---------|\n| `latest` | Tip of `main` branch |\n| `X.Y.Z` | Specific semver release |\n| `X.Y` | Latest in the minor line |\n| `X` | Latest in the major line |\n| `sha-<7>` | Specific git commit |\n\n资料来源：[DOCKER.md:70-85]()\n\n### Verify Build Attestation\n\nFor supply chain security, verify the container image:\n\n```bash\ngh attestation verify \\\n  oci://docker.io/statewavedev/statewave:latest \\\n  --owner smaramwbc\n```\n\n资料来源：[DOCKER.md:90-95]()\n\n## Environment Configuration\n\nStatewave uses environment variables for all configuration. The following table documents the complete set:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | — | PostgreSQL connection string (required) |\n| `STATEWAVE_LITELLM_API_KEY` | — | LLM provider API key |\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Embedding backend (`litellm`, `openai`, `stub`) |\n| `STATEWAVE_COMPILER_TYPE` | `llm` | Compilation method (`llm` or `heuristic`) |\n| `STATEWAVE_AUTH_API_KEY` | — | Static API key for authentication |\n| `STATEWAVE_PORT` | `8100` | HTTP server port |\n| `STATEWAVE_LOG_LEVEL` | `INFO` | Logging verbosity |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests per minute per IP |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | `distributed` (Postgres) or `memory` |\n| `STATEWAVE_WEBHOOK_URL` | — | Callback URL for async events |\n| `STATEWAVE_WEBHOOK_TIMEOUT` | `5.0` | Webhook HTTP timeout (seconds) |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Multi-tenant isolation header |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Enforce tenant header presence |\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Token budget for context assembly |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n\n资料来源：[README.md:180-200]()\n\n## API Endpoints\n\n### Health and Readiness\n\n| Endpoint | Method | Purpose |\n|----------|--------|---------|\n| `/healthz` | GET | Liveness check |\n| `/health` | GET | Liveness check (alias) |\n| `/readyz` | GET | Readiness check |\n| `/ready` | GET | Readiness check (alias) |\n\n### Core Memory Operations\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/v1/episodes` | Ingest a single episode (append-only) |\n| `POST` | `/v1/episodes/batch` | Ingest up to 100 episodes at once |\n| `POST` | `/v1/memories/compile` | Compile memories from episodes (idempotent) |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n| `DELETE` | `/v1/subjects/{id}` | Permanently delete all data for a subject |\n\n### Advanced Operations\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/v1/resolutions` | Track issue resolution state per session |\n| `GET` | `/v1/resolutions` | List resolutions for a subject |\n| `POST` | `/v1/handoff` | Generate compact handoff context pack |\n| `GET` | `/v1/subjects/{id}/health` | Customer health score with explainable factors |\n| `GET` | `/v1/subjects/{id}/sla` | SLA metrics — response time, resolution time, breaches |\n\n资料来源：[README.md:30-60]()\n\n## Connectors Ecosystem\n\nStatewave supports external data sources through modular connectors:\n\n```bash\n# Install connectors individually\nnpm install @statewavedev/connectors-github\nnpm install @statewavedev/connectors-markdown\nnpm install @statewavedev/connectors-slack\nnpm install @statewavedev/connectors-n8n\nnpm install @statewavedev/connectors-zapier\nnpm install @statewavedev/mcp-server\n\n# Meta-package for all connectors\nnpm install @statewavedev/connectors\n```\n\nAvailable connectors and their status:\n\n| Source | Memory Shape | Status |\n|--------|--------------|--------|\n| MCP Server | Copilot/Claude/Cursor/agent memory | ✅ Shipped |\n| GitHub | Issues, PRs, reviews, releases → repo memory | ✅ Shipped |\n| Markdown | Local docs, ADRs, RFCs → decision memory | ✅ Shipped |\n| Slack | Channel conversations | ✅ Shipped |\n\n资料来源：[README.md:250-280]()\n\n### Connector Usage Examples\n\n```bash\n# Sync GitHub data (dry-run first)\nstatewave-connectors sync github \\\n  --repo smaramwbc/statewave \\\n  --subject repo:smaramwbc/statewave \\\n  --dry-run\n\n# Sync Markdown documentation\nstatewave-connectors sync markdown \\\n  --path ./docs \\\n  --subject repo:smaramwbc/statewave \\\n  --dry-run\n\n# Start MCP server\nstatewave-connectors mcp start\n```\n\n## Kubernetes Deployment\n\nFor production environments, use the Helm chart:\n\n```bash\nhelm install statewave ./helm/statewave \\\n  --set database.url='postgresql+asyncpg://...' \\\n  --set llm.apiKey='sk-...' \\\n  --set auth.apiKey='replace-me'\n```\n\nThe Helm chart runs a pre-install Job (`alembic upgrade head`) before any API pod admits traffic. Upgrades repeat migration as a pre-upgrade Job.\n\n资料来源：[helm/statewave/README.md:1-40]()\n\n### Helm Configuration Reference\n\n| Value | Default | Notes |\n|-------|---------|-------|\n| `image.tag` | `\"\"` | Falls back to `Chart.AppVersion` |\n| `replicaCount` | `1` | Check connection-budget math before raising |\n| `database.url` / `database.existingSecret` | — | One is **required** |\n| `compiler.type` | `llm` | `heuristic` for demo/no-LLM mode |\n| `embedding.provider` | `litellm` | `stub` for demo/no-embedding mode |\n| `llm.apiKey` / `llm.existingSecret` | — | Required when `compiler.type=llm` |\n| `auth.apiKey` / `auth.existingSecret` | — | Strongly recommended in production |\n\n资料来源：[helm/statewave/README.md:50-70]()\n\n## Running Tests\n\nStatewave includes unit tests (no database required) and integration tests (requires PostgreSQL):\n\n```bash\n# Unit tests\npytest tests/test_*.py -v\n\n# Integration tests\nPGPASSWORD=statewave createdb -h localhost -U statewave statewave_test\npytest tests/integration/ -v\n\n# All tests\npytest tests/ -v\n```\n\n资料来源：[README.md:210-220]()\n\n## Bootstrap Documentation Pack\n\nAfter initial deployment, bootstrap the documentation memory pack for a self-hosted support agent:\n\n```bash\npython -m scripts.bootstrap_docs_pack [--docs-path PATH] [--purge] [--dry-run]\n```\n\n### Environment Variables for Bootstrap\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `STATEWAVE_URL` | `http://localhost:8100` | API base URL |\n| `STATEWAVE_API_KEY` | — | Authentication key |\n| `STATEWAVE_DOCS_PATH` | — | Override documentation path |\n\n### Bootstrap Behavior\n\n```mermaid\ngraph LR\n    A[Read statewave-docs corpus] --> B[Ingest each section as Episode]\n    B --> C[Compile Episodes to Memories]\n    C --> D[Assemble docs-grounded Knowledge Base]\n    D --> E[Support Agent queries via POST /v1/context]\n    \n    F[--purge] -.->|Wipe and rebuild| A\n    G[--dry-run] -.->|No ingestion| A\n```\n\nThe bootstrap process is idempotent. By default, it fails if the subject already has episodes. Re-run with `--purge` to wipe and rebuild from scratch.\n\n资料来源：[scripts/bootstrap_docs_pack.py:1-50]()\n\n## Seed Demo Subjects\n\nFor development and testing, seed demo subjects with sample data:\n\n```bash\npython -m scripts.seed_demo_subjects [--dry-run]\n```\n\nThis creates sample episodes and memories that reference each other, enabling verification of the compilation and retrieval pipeline.\n\n资料来源：[scripts/seed_demo_subjects.py:1-60]()\n\n## Current Limitations\n\nStatewave v0.8.0 has known limitations:\n\n| Limitation | Description |\n|------------|-------------|\n| Rate limiting | Per-IP only — not yet per-tenant or per-API-key |\n| Multi-tenant isolation | App-layer query-scoped isolation — no Postgres RLS yet |\n\n资料来源：[README.md:225-235]()\n\n## Next Steps\n\n| Resource | Purpose |\n|----------|---------|\n| [API v1 contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md) | Complete API reference |\n| [Connector docs](https://github.com/smaramwbc/statewave-docs/blob/main/connectors/index.md) | Connector configuration |\n| [Horizontal Scaling Guide](https://github.com/smaramwbc/statewave-docs/blob/main/deployment/horizontal-scaling.md) | Production scaling guidance |\n| [Architecture documentation](https://github.com/smaramwbc/statewave-docs/blob/main/architecture/ranking.md) | Context ranking internals |\n\n---\n\n<a id='page-architecture'></a>\n\n## System Architecture\n\n### 相关页面\n\n相关主题：[Overview - What is Statewave?](#page-overview), [Database Schema & Migrations](#page-database-schema), [Compilation Services](#page-compilation-services)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n- [server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/api/timeline.py](https://github.com/smaramwbc/statewave/blob/main/server/api/timeline.py)\n- [server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n- [server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n- [server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n- [DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n</details>\n\n# System Architecture\n\nStatewave is an AI agent memory system designed to ingest real-world events as episodes, compile them into structured memories, and retrieve ranked, token-bounded context for agentic workflows. The system follows a layered architecture with clear separation between API handling, business logic services, data persistence, and external connectors.\n\n## High-Level Architecture Overview\n\n```mermaid\ngraph TD\n    subgraph \"External Clients\"\n        A[Agents / Applications]\n        B[Connectors: GitHub, Slack, MCP]\n        C[SDK Clients]\n    end\n\n    subgraph \"API Layer\"\n        D[FastAPI Application]\n        E[Endpoint Routes]\n        F[Middleware / Auth]\n    end\n\n    subgraph \"Service Layer\"\n        G[Episode Service]\n        H[Memory Service]\n        I[Compiler Service]\n        J[Search Service]\n        K[Snapshot Service]\n    end\n\n    subgraph \"Data Layer\"\n        L[(PostgreSQL)]\n        M[(Vector Embeddings)]\n        N[Starter Packs]\n    end\n\n    A --> D\n    B --> D\n    C --> D\n    D --> F\n    F --> E\n    E --> G\n    E --> H\n    E --> I\n    E --> J\n    E --> K\n    G --> L\n    H --> L\n    H --> M\n    I --> L\n    J --> M\n    K --> L\n    K --> N\n```\n\n## Core Data Models\n\n### Episode\n\nAn **Episode** represents a discrete unit of experience — a chat message, a support ticket update, a GitHub issue event, or a documentation section. Episodes are the atomic ingestion unit in Statewave.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique identifier |\n| `subject_id` | UUID | Parent subject this episode belongs to |\n| `session_id` | str | Session context identifier |\n| `type` | str | Kind of episode (e.g., `doc_section`, `chat`, `ticket`) |\n| `source` | str | Origin system (e.g., `github`, `slack`, `statewave-docs`) |\n| `content` | str | Raw content body |\n| `metadata_` | dict | Arbitrary key-value metadata |\n| `provenance` | dict | Source-specific tracking (e.g., `content_hash` for docs) |\n| `created_at` | datetime | Ingestion timestamp |\n| `valid_from` | datetime | Temporal anchor for memory derivation |\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n### Memory\n\nA **Memory** is a compiled, structured artifact extracted from one or more episodes. Memories have temporal validity windows, confidence scores, and lineage tracking.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique identifier |\n| `subject_id` | UUID | Parent subject |\n| `kind` | str | Memory category (e.g., `episode_summary`, `profile_fact`, `decision`) |\n| `content` | str | Compiled memory content |\n| `summary` | str | Short summary (max 200 chars) |\n| `confidence` | float | Confidence score (0.0-1.0) |\n| `valid_from` | datetime | Start of validity window |\n| `valid_to` | datetime | End of validity window (nullable) |\n| `source_episode_ids` | list[UUID] | Episodes this memory was derived from |\n| `status` | str | Memory lifecycle state |\n| `sensitivity_labels` | list[str] | Optional sensitivity classification |\n\n资料来源：[server/api/timeline.py](https://github.com/smaramwbc/statewave/blob/main/server/api/timeline.py)\n\n### Subject\n\nA **Subject** is the central entity in Statewave — a persona, entity, or concept that accumulates memory over time.\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique identifier |\n| `tenant_id` | str | Multi-tenant isolation key |\n| `name` | str | Human-readable name |\n| `type_` | str | Subject type classification |\n| `metadata_` | dict | Arbitrary metadata |\n| `embedding` | vector | Semantic embedding for similarity search |\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n## API Layer\n\n### REST API v1\n\nThe API is served by FastAPI on port 8100 by default and exposes OpenAPI documentation at `/docs` and ReDoc at `/redoc`.\n\n```mermaid\ngraph LR\n    A[Client] --> B[\"POST /v1/episodes\"]\n    A --> C[\"POST /v1/episodes/batch\"]\n    A --> D[\"POST /v1/memories/compile\"]\n    A --> E[\"GET /v1/memories/search\"]\n    A --> F[\"POST /v1/context\"]\n    A --> G[\"GET /v1/timeline\"]\n    A --> H[\"GET /v1/subjects\"]\n    A --> I[\"DELETE /v1/subjects/{id}\"]\n    A --> J[\"POST /v1/resolutions\"]\n    A --> K[\"POST /v1/handoff\"]\n    A --> L[\"GET /v1/subjects/{id}/health\"]\n    A --> M[\"GET /v1/subjects/{id}/sla\"]\n```\n\n### Core Endpoints\n\n| Method | Path | Purpose |\n|--------|------|---------|\n| `POST` | `/v1/episodes` | Ingest a single episode (append-only) |\n| `POST` | `/v1/episodes/batch` | Ingest up to 100 episodes at once |\n| `POST` | `/v1/memories/compile` | Compile memories from episodes (idempotent) |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n| `DELETE` | `/v1/subjects/{id}` | Permanently delete all data for a subject |\n| `POST` | `/v1/resolutions` | Track issue resolution state per session |\n| `GET` | `/v1/resolutions` | List resolutions for a subject |\n| `POST` | `/v1/handoff` | Generate compact handoff context pack |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n### Health Endpoints\n\n| Endpoint | Purpose |\n|----------|---------|\n| `GET /healthz` or `GET /health` | Liveness check |\n| `GET /readyz` or `GET /ready` | Readiness check |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Service Layer\n\n### Compiler Service\n\nThe compiler extracts memories from episodes. Statewave supports two compilation modes:\n\n| Mode | Description | Use Case |\n|------|-------------|----------|\n| `llm` | Uses an LLM provider (via LiteLLM) to extract structured memories | Production with semantic understanding |\n| `heuristic` | Rule-based extraction for basic facts and summaries | Demo mode, no API key required |\n\n#### Heuristic Compiler\n\nThe heuristic compiler extracts two memory kinds from episodes:\n\n1. **episode_summary**: A 500-character truncation of the episode text with 0.8 confidence\n2. **profile_fact**: Extracted profile facts with 0.6 confidence\n\n```python\nMemoryRow(\n    kind=\"episode_summary\",\n    content=text[:500],\n    summary=text[:200],\n    confidence=0.8,\n    valid_from=ep_valid_from,\n    valid_to=compute_valid_to(\"episode_summary\", ep_valid_from, ttl),\n    source_episode_ids=[ep.id],\n    status=\"active\",\n)\n```\n\n资料来源：[server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n\n#### Temporal Anchoring\n\nThe compiler determines episode temporal anchors with the following priority:\n\n1. `payload.event_time` — Explicit client override for historical data replay\n2. `payload.messages[0].timestamp` — First message timestamp in chat-shaped payloads (used by LoCoMo, Slack, Zendesk connectors)\n3. `created_at` — Fallback to ingestion timestamp\n\n```mermaid\ngraph TD\n    A[Episode Ingestion] --> B{event_time present?}\n    B -->|Yes| C[Use event_time]\n    B -->|No| D{messages timestamp present?}\n    D -->|Yes| E[Use messages[0].timestamp]\n    D -->|No| F[Use created_at]\n```\n\n资料来源：[server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n\n### Snapshot Service\n\nSnapshots enable point-in-time restoration of subject data, including episodes, memories, and resolutions.\n\n| Feature | Description |\n|---------|-------------|\n| Create Snapshot | Captures all subject data with version metadata |\n| Restore Snapshot | Clones data with optional time-shifting for temporal consistency |\n| Metadata Tracking | Records `restored_from_snapshot` in restored records |\n\n```python\nsnapshot = SubjectSnapshotRow(\n    name=name,\n    version=version,\n    source_subject_id=snapshot_subject,\n    episode_count=len(eps),\n    memory_count=len(mems),\n    metadata_=metadata or {},\n)\n```\n\n资料来源：[server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n\n### Timeline Service\n\nThe timeline service provides chronological event merging across episodes and resolutions within a session.\n\n```mermaid\ngraph TD\n    A[Session Request] --> B[Fetch Episodes]\n    A --> C[Fetch Resolutions]\n    B --> D[Merge Events Chronologically]\n    C --> D\n    D --> E[TimelineResponse]\n    \n    E --> F[TimelineEpisodeEvent]\n    E --> G[TimelineResolutionEvent]\n    \n    F --> H[id]\n    F --> I[source]\n    F --> J[type]\n    F --> K[payload]\n    F --> L[created_at]\n    F --> M[citing_memory_count]\n    \n    G --> N[resolved_at]\n    G --> O[status]\n```\n\n#### Timeline Response Model\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `session_id` | str | Session identifier |\n| `status` | str | Overall session status |\n| `first_message_at` | str | Timestamp of first user message |\n| `first_response_at` | str | Timestamp of first agent response |\n| `resolved_at` | str | Resolution timestamp |\n| `first_response_seconds` | float | Time to first response |\n| `resolution_seconds` | float | Total resolution time |\n| `first_response_breached` | bool | SLA breach indicator |\n| `resolution_breached` | bool | Resolution SLA breach indicator |\n| `episode_count` | int | Total episodes in session |\n| `events` | list | Chronologically merged events |\n\n资料来源：[server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n\n### Handoff Service\n\nThe handoff endpoint generates compact context packs for transferring conversation context between agents or sessions.\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `subject_id` | UUID | Yes | Target subject |\n| `session_id` | str | No | Optional session context |\n| `reason` | str | No | Handoff reason |\n| `max_tokens` | int | No | Token budget for context |\n| `caller_id` | str | Conditional | Required when tenant config mandates it |\n| `caller_type` | str | Conditional | Required when tenant config mandates it |\n\n资料来源：[server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n\n## Data Layer\n\n### Database Schema\n\nStatewave uses PostgreSQL with SQLAlchemy async for data persistence. Key tables:\n\n| Table | Purpose |\n|-------|---------|\n| `subjects` | Central entity registry with embeddings |\n| `episodes` | Raw experience ingestion records |\n| `memories` | Compiled memory artifacts with validity windows |\n| `resolutions` | Issue resolution tracking per session |\n| `policy_bundles` | Immutable policy YAML bundles |\n| `policy_receipts` | Compliance receipts for policy enforcement |\n| `subject_snapshots` | Point-in-time backup metadata |\n\n### Multi-Tenancy\n\nMulti-tenant isolation is implemented at the application layer:\n\n| Configuration | Default | Description |\n|---------------|--------|-------------|\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Header for multi-tenant isolation |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant header |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n> **Current Limitation**: Multi-tenant isolation is query-scoped (application-layer) with no PostgreSQL Row-Level Security (RLS) enforcement.\n\n## Connectors\n\nConnectors feed external data sources into Statewave as episodes without requiring custom ingestion code.\n\n```mermaid\ngraph LR\n    A[GitHub] -->|Issues, PRs, Reviews| B[Connector]\n    C[Slack] -->|Messages, Threads| B\n    D[MCP Server] -->|Agent Memory| B\n    E[Markdown] -->|Docs, RFCs| B\n    F[n8n] -->|Workflow Events| B\n    G[Zapier] -->|Automation Triggers| B\n    \n    B --> H[Episodes]\n    H --> I[Statewave API]\n```\n\n### Available Connectors\n\n| Source | Memory Shape | Status |\n|--------|--------------|--------|\n| MCP Server | Copilot / Claude / Cursor / agent memory | ✅ Shipped |\n| GitHub | Issues, PRs, reviews, releases → repo memory | ✅ Shipped |\n| Markdown | Local docs, ADRs, RFCs → decision memory | ✅ Shipped |\n| Slack | Channel messages → conversation memory | ✅ Shipped |\n| n8n | Workflow events → process memory | ✅ Shipped |\n| Zapier | Automation triggers → event memory | ✅ Shipped |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | — | PostgreSQL connection string (required) |\n| `STATEWAVE_LITELLM_API_KEY` | — | LiteLLM API key for LLM compilation |\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Embedding provider |\n| `STATEWAVE_COMPILER_TYPE` | `llm` | Compiler mode: `llm` or `heuristic` |\n| `STATEWAVE_API_KEY` | — | API authentication key |\n| `STATEWAVE_PORT` | `8100` | HTTP server port |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests/min/IP (0 = disabled) |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | `distributed` (Postgres) or `memory` |\n| `STATEWAVE_WEBHOOK_URL` | — | Webhook callback URL |\n| `STATEWAVE_WEBHOOK_TIMEOUT` | `5.0` | Webhook HTTP timeout (seconds) |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Tenant isolation header |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant |\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Default token budget for context |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n## Deployment\n\n### Docker Deployment\n\nStatewave is distributed as a Docker image and can be deployed using Docker Compose.\n\n```yaml\nservices:\n  statewave:\n    image: statewavedev/statewave:latest\n    ports: [\"8100:8100\"]\n    environment:\n      STATEWAVE_DATABASE_URL: postgresql+asyncpg://statewave:statewave@db:5432/statewave\n      STATEWAVE_LITELLM_API_KEY: sk-...\n    depends_on:\n      db:\n        condition: service_healthy\n```\n\n#### Image Tags\n\n| Tag | Meaning |\n|-----|---------|\n| `latest` | Tip of `main` |\n| `X.Y.Z` | Semver release |\n| `X.Y` | Latest in the minor line |\n| `X` | Latest in the major line |\n| `sha-<7>` | Specific commit |\n\n资料来源：[DOCKER.md](https://github.com/smaramwbc/statewave/blob/main/DOCKER.md)\n\n### Helm Chart\n\nKubernetes deployment is supported via Helm:\n\n| Value | Default | Notes |\n|-------|---------|-------|\n| `image.tag` | `\"\"` | Falls back to Chart.AppVersion |\n| `replicaCount` | `1` | See horizontal scaling guide |\n| `database.url` | — | Required |\n| `database.existingSecret` | — | Alternative to url |\n| `compiler.type` | `llm` | `heuristic` for demo mode |\n| `embedding.provider` | `litellm` | `stub` for no-embedding mode |\n| `llm.apiKey` | — | Required for LLM mode |\n| `auth.apiKey` | — | Recommended for production |\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n## Testing\n\n### Test Execution\n\n```bash\n# Unit tests (no DB required)\npytest tests/test_*.py -v\n\n# Integration tests (requires Postgres)\nPGPASSWORD=statewave createdb -h localhost -U statewave statewave_test\npytest tests/integration/ -v\n\n# All tests\npytest tests/ -v\n```\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n<a id='page-database-schema'></a>\n\n## Database Schema & Migrations\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture), [Governance - Receipts & Policy Engine](#page-receipts-policy)\n\n<details>\n<summary>Relevant Source Files</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n- [alembic/env.py](https://github.com/smaramwbc/statewave/blob/main/alembic/env.py)\n- [alembic/versions](https://github.com/smaramwbc/statewave/blob/main/alembic/versions)\n- [server/db/engine.py](https://github.com/smaramwbc/statewave/blob/main/server/db/engine.py)\n- [server/services/backup.py](https://github.com/smaramwbc/statewave/blob/main/server/services/backup.py)\n- [alembic/versions/0016_memory_status_tombstoned.py](https://github.com/smaramwbc/statewave/blob/main/alembic/versions/0016_memory_status_tombstoned.py)\n</details>\n\n# Database Schema & Migrations\n\n## Overview\n\nThe Statewave application uses PostgreSQL as its primary data store, managed through SQLAlchemy ORM with Alembic for schema migrations. The database layer provides persistent storage for the core domain entities: **Subjects**, **Episodes**, **Memories**, **Resolutions**, and **Snapshots**.\n\nAll tables use UUID v4 as primary keys and include automatic timestamp tracking (`created_at`, `updated_at`) with timezone-aware `DateTime(timezone=True)` columns. The schema is designed to support multi-tenant isolation through a `tenant_id` column on relevant entities.\n\n资料来源：[server/db/tables.py]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Database Layer\"\n        T[PostgreSQL]\n        ORM[SQLAlchemy ORM]\n        MIG[Alembic Migrations]\n    end\n    \n    subgraph \"Core Tables\"\n        SUBJ[subjects]\n        EP[episodes]\n        MEM[memories]\n        RES[resolutions]\n        SNAP[snapshots]\n        POL[policy_bundles]\n        SES[sessions]\n    end\n    \n    T --> ORM\n    ORM --> SUBJ\n    ORM --> EP\n    ORM --> MEM\n    ORM --> RES\n    ORM --> SNAP\n    ORM --> POL\n    ORM --> SES\n    \n    MIG -.->|manage schema| T\n```\n\n## Core Table Definitions\n\n### subjects\n\nThe central entity representing a user, entity, or concept that episodes and memories are associated with.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | `uuid.uuid4()` | Primary key |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `name` | String(512) | Yes | — | Display name |\n| `metadata_` | JSONB | No | `{}` | Flexible metadata |\n| `version` | Integer | No | `1` | Optimistic locking |\n| `created_at` | DateTime | No | `server_default=func.now()` | Creation timestamp |\n| `updated_at` | DateTime | No | `server_default + onupdate` | Last modification |\n\n资料来源：[server/db/tables.py]()\n\n### episodes\n\nImmutable event records representing interactions, activities, or data points fed into the system via connectors.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `subject_id` | UUID | No | — | FK → subjects |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `source` | String(64) | No | — | Origin (e.g., `slack`, `github`, `mcp`) |\n| `type` | String(64) | No | — | Event type (e.g., `doc_section`, `chat_message`) |\n| `payload` | JSONB | No | — | Raw event data |\n| `metadata_` | JSONB | No | `{}` | Extracted metadata |\n| `provenance` | JSONB | No | `{}` | Source attribution (hashes, URLs) |\n| `occurred_at` | DateTime | Yes | — | When the event actually occurred |\n| `created_at` | DateTime | No | Auto | Ingestion timestamp |\n| `session_id` | UUID | Yes | — | Optional session grouping |\n\n资料来源：[server/db/tables.py]()\n资料来源：[server/services/context.py]()\n\n### memories\n\nCompiled, semantically indexed summaries derived from episodes. Memories have temporal validity windows and confidence scores.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `subject_id` | UUID | No | — | FK → subjects |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `kind` | String(32) | No | — | Memory category (e.g., `episode_summary`, `profile_fact`) |\n| `content` | Text | No | — | Full memory content |\n| `summary` | String(512) | Yes | — | Abbreviated summary |\n| `confidence` | Float | No | — | LLM-assigned confidence (0.0-1.0) |\n| `valid_from` | DateTime | No | — | When the memory becomes relevant |\n| `valid_to` | DateTime | Yes | — | When the memory expires (TTL) |\n| `source_episode_ids` | Array[UUID] | Yes | — | Episodes this memory was compiled from |\n| `embedding` | Array[Float] | Yes | — | Vector embedding for semantic search |\n| `metadata_` | JSONB | No | `{}` | Additional metadata |\n| `status` | String(32) | No | — | `active`, `superseded`, or `tombstoned` |\n| `sensitivity_labels` | Array[String] | Yes | — | Privacy/classification labels |\n| `created_at` | DateTime | No | Auto | Creation timestamp |\n| `updated_at` | DateTime | No | Auto | Last modification |\n\n资料来源：[server/db/tables.py]()\n\n**Status Values:**\n\n| Status | Description |\n|--------|-------------|\n| `active` | Currently valid and usable |\n| `superseded` | Replaced by a newer memory covering the same scope |\n| `tombstoned` | Soft-deleted, retained for audit trail |\n\n资料来源：[alembic/versions/0016_memory_status_tombstoned.py]()\n\n### resolutions\n\nTracks issue or conversation resolution state per session.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `subject_id` | UUID | No | — | FK → subjects |\n| `session_id` | UUID | No | — | Session identifier |\n| `tenant_id` | String(256) | No | — | Tenant isolation |\n| `status` | String(32) | No | — | Resolution status |\n| `resolution_summary` | Text | Yes | — | Summary of resolution |\n| `resolved_at` | DateTime | Yes | — | When resolution occurred |\n| `metadata_` | JSONB | No | `{}` | Additional metadata |\n| `created_at` | DateTime | No | Auto | Creation timestamp |\n| `updated_at` | DateTime | No | Auto | Last modification |\n\n资料来源：[server/db/tables.py]()\n资料来源：[server/services/snapshots.py]()\n\n### subject_snapshots\n\nImmutable snapshots capturing a point-in-time state of a subject for backup/restore purposes.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `name` | String(512) | No | — | Snapshot name |\n| `version` | Integer | No | — | Snapshot version |\n| `source_subject_id` | UUID | No | — | Original subject being snapshotted |\n| `episode_count` | Integer | No | — | Number of episodes captured |\n| `memory_count` | Integer | No | — | Number of memories captured |\n| `metadata_` | JSONB | No | `{}` | Snapshot metadata |\n| `created_at` | DateTime | No | Auto | Creation timestamp |\n\n资料来源：[server/db/tables.py]()\n\n### policy_bundles\n\nImmutable policy YAML bundles content-addressed by `bundle_hash`.\n\n| Column | Type | Nullable | Default | Description |\n|--------|------|----------|---------|-------------|\n| `id` | UUID | No | Auto | Primary key |\n| `bundle_hash` | String(64) | No | — | SHA-256 content hash (indexed) |\n| `yaml_content` | Text | No | — | Full YAML policy content |\n| `active` | Boolean | No | `False` | Whether this bundle is active |\n| `tenant_id` | String(256) | Yes | — | Tenant isolation |\n\n资料来源：[server/db/tables.py]()\n\n**Design Note:** Composite unique index on `(tenant_id, bundle_hash) NULLS NOT DISTINCT` ensures one bundle per (scope, content) combination while allowing multiple tenants to install the same policy independently.\n\n## Migration System\n\nStatewave uses **Alembic** for database schema versioning. Migrations are located in the `alembic/versions/` directory and follow a sequential naming convention (e.g., `0016_memory_status_tombstoned.py`).\n\n### Migration Workflow\n\n```mermaid\ngraph LR\n    A[Development] --> B[Create Migration]\n    B --> C[Review SQL]\n    C --> D[Apply: alembic upgrade head]\n    D --> E[Production Deploy]\n    E --> F[Rollback if needed: alembic downgrade]\n```\n\n### Migration Naming Convention\n\nMigrations use the format `XXXX_<short_description>.py` where `XXXX` is a zero-padded sequence number. This ensures deterministic ordering across distributed development.\n\n### Migration Example: Status Rename\n\nThe migration `0016_memory_status_tombstoned.py` demonstrates the migration pattern:\n\n```python\n\"\"\"memories.status — rename `deleted` to `tombstoned` (defensive)\n\nRevision ID: 0016_memory_status_tombstoned\nRevises: 0015_episode_occurred_at\nCreate Date: 2026-05-10\n```\n\n**Purpose:**\n1. Normalize any existing `deleted` values to `tombstoned`\n2. Align vocabulary with issue #49 (State-assembly receipts specify `supersession_status: active | superseded | tombstoned`)\n3. Provide a visible breadcrumb for future developers tracing the change\n\n资料来源：[alembic/versions/0016_memory_status_tombstoned.py]()\n\n### Key Migration Characteristics\n\n| Characteristic | Description |\n|----------------|-------------|\n| **Reversible** | All migrations include `downgrade` paths |\n| **Idempotent checks** | Migrations verify existing state before modifying |\n| **Server defaults** | Timestamps use `server_default=func.now()` for consistency |\n| **Zero-downtime aware** | Helm chart runs pre-upgrade Jobs for migrations |\n\n## Data Import/Export\n\nThe backup service (`server/services/backup.py`) provides import/export functionality that serializes and deserializes subjects, episodes, and memories.\n\n### Import Process\n\n```mermaid\ngraph TD\n    A[JSON Archive] --> B[Parse episodes_data]\n    B --> C[Parse memories_data]\n    C --> D[Resolve subject_id]\n    D --> E[Insert Episodes]\n    E --> F[Insert Memories]\n    F --> G[Return Import Result]\n    \n    E -->|preserve_ids| E1[Use original UUIDs]\n    E -->|new_ids| E2[Generate new UUIDs]\n```\n\n**Import Flow:**\n1. Validate archive structure\n2. Resolve target `subject_id` based on `conflict_strategy`\n3. Insert episodes with optional ID preservation\n4. Insert memories with source episode ID remapping\n5. Commit transaction\n\n资料来源：[server/services/backup.py]()\n\n### Snapshot Restore Process\n\nSnapshots preserve the complete state of a subject including temporal offsets:\n\n```python\n# Timestamp shifting during restore\ntime_shift = restore_time - snapshot.created_at\nvalid_from = mem_valid_from + time_shift\nvalid_to = (mem_valid_to + time_shift) if mem_valid_to else None\n```\n\nThe `metadata_` field receives `\"restored_from_snapshot\": str(snapshot_id)` for audit tracking.\n\n资料来源：[server/services/snapshots.py]()\n\n## Schema Design Patterns\n\n### Temporal Modeling\n\nMemories use `valid_from` and `valid_to` columns for temporal validity:\n\n```python\ndef compute_valid_to(kind: str, valid_from: datetime, ttl: dict) -> datetime | None:\n    \"\"\"Compute expiration based on memory kind TTL.\"\"\"\n    ttl_hours = ttl.get(kind, DEFAULT_TTL_HOURS)\n    return valid_from + timedelta(hours=ttl_hours)\n```\n\n资料来源：[server/services/compilers/heuristic.py]()\n\n### Temporal Anchoring\n\nThe system extracts temporal anchors from episodes with priority:\n\n1. `payload.event_time` — explicit client override\n2. `payload.messages[0].timestamp` — first message timestamp in chat payloads\n3. `created_at` — fallback to ingestion time\n\n资料来源：[server/services/compilers/heuristic.py]()\n\n### JSONB Flexibility\n\nColumns like `payload`, `metadata_`, and `provenance` use PostgreSQL's `JSONB` type for schema flexibility:\n\n- **payload**: Raw event data varying by source connector\n- **metadata_**: Extracted structured data\n- **provenance**: Source attribution with content hashes\n\nThis allows the system to evolve connectors without schema migrations.\n\n### Composite Indexes\n\nKey indexes for query performance:\n\n| Index | Columns | Purpose |\n|-------|---------|---------|\n| `policy_bundles.bundle_hash` | `bundle_hash` | Content-addressed lookups |\n| `memories.subject_id + kind` | (implied) | Subject memory filtering |\n| `episodes.subject_id + occurred_at` | (implied) | Timeline queries |\n\n## See Also\n\n- [API v1 Contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md) — Database operations via REST API\n- [Deployment Guide](https://github.com/smaramwbc/statewave-docs/blob/main/deployment/guide.md) — Database configuration\n- [Helm Chart Configuration](../helm/statewave/README.md) — Migration job settings\n\n---\n\n<a id='page-api-endpoints'></a>\n\n## API Endpoints Reference\n\n### 相关页面\n\n相关主题：[Context Assembly & Ranking](#page-context-assembly)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/api/episodes.py](https://github.com/smaramwbc/statewave/blob/main/server/api/episodes.py)\n- [server/api/memories.py](https://github.com/smaramwbc/statewave/blob/main/server/api/memories.py)\n- [server/api/context.py](https://github.com/smaramwbc/statewave/blob/main/server/api/context.py)\n- [server/api/subjects.py](https://github.com/smaramwbc/statewave/blob/main/server/api/subjects.py)\n- [server/api/resolutions.py](https://github.com/smaramwbc/statewave/blob/main/server/api/resolutions.py)\n- [server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n- [server/api/sla.py](https://github.com/smaramwbc/statewave/blob/main/server/api/sla.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n- [server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n</details>\n\n# API Endpoints Reference\n\n## Overview\n\nThe Statewave API provides a comprehensive set of RESTful endpoints for managing agent memory, tracking session context, and enabling multi-tenant workspace isolation. The API is built on FastAPI and follows OpenAPI standards with automatic documentation at `/docs` (Swagger UI) and `/redoc` (ReDoc).\n\n**Base URL:** `http://localhost:8100`\n\n**API Version:** v1\n\nAll endpoints support multi-tenant isolation through the `X-Tenant-ID` header, configurable via the `STATEWAVE_TENANT_HEADER` environment variable. The API enforces query-scoped data isolation for multi-tenant deployments. 资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n## Health & Readiness\n\n### Liveness Check\n\n```\nGET /healthz\nGET /health\n```\n\nReturns `200 OK` when the service is running. Use this for basic liveness probes in container orchestration.\n\n### Readiness Check\n\n```\nGET /readyz\nGET /ready\n```\n\nReturns `200 OK` when the service is ready to accept traffic, including database connectivity validation.\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n## Episodes API\n\nEpisodes are the atomic, append-only units of memory ingestion. Each episode represents a discrete event, message, or interaction associated with a subject.\n\n### Ingest Single Episode\n\n```\nPOST /v1/episodes\n```\n\nIngests a single episode under a subject. The episode is stored with provenance metadata and becomes available for memory compilation.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"session_id\": \"string (optional)\",\n  \"source\": \"string (e.g., 'live-chat', 'mcp-server', 'github')\",\n  \"type\": \"string (e.g., 'message', 'doc_section', 'issue')\",\n  \"payload\": {\n    \"messages\": [...],\n    \"event_time\": \"ISO8601 datetime (optional)\"\n  },\n  \"metadata\": {},\n  \"provenance\": {\n    \"content_hash\": \"string (optional)\"\n  }\n}\n```\n\n### Batch Ingest Episodes\n\n```\nPOST /v1/episodes/batch\n```\n\nIngests up to 100 episodes in a single request. This is the recommended endpoint for bulk data loading or connector imports.\n\n**Request Body:**\n```json\n{\n  \"episodes\": [\n    { /* Episode object */ }\n  ]\n}\n```\n\n**Constraints:**\n- Maximum 100 episodes per batch\n- Each episode requires a valid `subject_id`\n- All episodes are processed atomically\n\n资料来源：[server/api/episodes.py](https://github.com/smaramwbc/statewave/blob/main/server/api/episodes.py)\n\n---\n\n## Memories API\n\nMemories are compiled, queryable representations derived from episodes through the heuristic or LLM compiler.\n\n### Compile Memories\n\n```\nPOST /v1/memories/compile\n```\n\nTriggers memory compilation from episodes. This operation is idempotent—re-running compiles only processes new episodes.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"force\": false\n}\n```\n\n### Search Memories\n\n```\nGET /v1/memories/search\n```\n\nSearches memories by kind, text content, or semantic similarity.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `subject_id` | string | required | Target subject UUID |\n| `kind` | string | - | Filter by memory kind (e.g., `episode_summary`, `profile_fact`) |\n| `q` | string | - | Full-text search query |\n| `limit` | int | 50 | Maximum results (1-200) |\n| `offset` | int | 0 | Pagination offset |\n\n### Memory Evolution Tracking\n\nThe system maintains memory lineage through `source_episode_ids` relationships, enabling:\n- **Supersession**: When new memories deprecate older ones\n- **Sibling relationships**: Memories derived from the same source episodes\n- **Provenance tracing**: Track which episodes contributed to each memory\n\n资料来源：[server/api/memories.py](https://github.com/smaramwbc/statewave/blob/main/server/api/memories.py)\n\n---\n\n## Context API\n\nThe context API assembles ranked, token-bounded context bundles optimized for LLM consumption.\n\n### Assemble Context\n\n```\nPOST /v1/context\n```\n\nGenerates a ranked context bundle suitable for passing to an LLM. The system considers:\n- Memory relevance and confidence scores\n- Token budget constraints (configurable via `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS`)\n- Temporal validity of memories\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"query\": \"string (optional)\",\n  \"max_tokens\": 4000,\n  \"include_episodes\": false,\n  \"kinds\": [\"episode_summary\", \"profile_fact\"]\n}\n```\n\n**Response:**\n```json\n{\n  \"subject_id\": \"string\",\n  \"query\": \"string\",\n  \"context\": \"string (assembled text)\",\n  \"token_count\": 1234,\n  \"memories_included\": [\n    {\n      \"id\": \"string\",\n      \"kind\": \"string\",\n      \"content\": \"string\",\n      \"summary\": \"string\",\n      \"confidence\": 0.8\n    }\n  ]\n}\n```\n\nThe context assembly uses a scoring algorithm that weighs relevance, recency, and confidence to produce optimal results within the token budget. 资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n---\n\n## Subjects API\n\nSubjects are the primary entity representing a user, session, or workspace that maintains memory.\n\n### List Subjects\n\n```\nGET /v1/subjects\n```\n\nReturns all subjects with episode and memory counts.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `tenant_id` | string | - | Filter by tenant (for multi-tenant deployments) |\n| `limit` | int | 50 | Results per page (1-200) |\n| `offset` | int | 0 | Pagination offset |\n\n### Delete Subject\n\n```\nDELETE /v1/subjects/{id}\n```\n\nPermanently deletes all episodes, memories, and resolutions for a subject. This operation is irreversible.\n\n**Path Parameters:**\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `id` | UUID | Subject identifier |\n\n### Get Subject Health\n\n```\nGET /v1/subjects/{id}/health\n```\n\nReturns a customer health score with explainable factors based on recent activity, resolution rates, and memory density.\n\n### Get Subject SLA\n\n```\nGET /v1/subjects/{id}/sla\n```\n\nReturns SLA metrics including:\n- Response time\n- Resolution time\n- SLA breaches\n\n资料来源：[server/api/subjects.py](https://github.com/smaramwbc/statewave/blob/main/server/api/subjects.py)\n\n---\n\n## Timeline API\n\n### Get Subject Timeline\n\n```\nGET /v1/timeline\n```\n\nReturns a chronological timeline of events for a subject.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `subject_id` | UUID | required | Target subject |\n| `session_id` | string | - | Filter by session |\n| `limit` | int | 50 | Maximum events |\n| `offset` | int | 0 | Pagination offset |\n\n**Response includes:**\n- Episode events with full payload and metadata\n- Resolution events with status transitions\n- Temporal metadata (first/last message timestamps)\n- SLA breach indicators\n\n资料来源：[server/api/timeline.py](https://github.com/smaramwbc/statewave/blob/main/server/api/timeline.py)\n\n---\n\n## Resolutions API\n\nResolutions track issue resolution state per session, enabling workflow tracking and SLA measurement.\n\n### Create Resolution\n\n```\nPOST /v1/resolutions\n```\n\nRecords a resolution event for a session.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"session_id\": \"string\",\n  \"status\": \"resolved | escalated | pending\",\n  \"resolution_summary\": \"string (optional)\",\n  \"metadata\": {}\n}\n```\n\n### List Resolutions\n\n```\nGET /v1/resolutions\n```\n\nLists resolutions for a subject.\n\n**Query Parameters:**\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `subject_id` | UUID | required | Target subject |\n| `session_id` | string | - | Filter by session |\n| `status` | string | - | Filter by status |\n\n资料来源：[server/api/resolutions.py](https://github.com/smaramwbc/statewave/blob/main/server/api/resolutions.py)\n\n---\n\n## Handoff API\n\n### Generate Handoff Context\n\n```\nPOST /v1/handoff\n```\n\nGenerates a compact, self-contained context pack for transferring conversation context between agents or sessions.\n\n**Request Body:**\n```json\n{\n  \"subject_id\": \"string (UUID)\",\n  \"session_id\": \"string (optional)\",\n  \"include_full_history\": false,\n  \"max_tokens\": 2000\n}\n```\n\nThis endpoint produces a lightweight JSON payload containing:\n- Recent memory summaries\n- Pending context items\n- Session state indicators\n- Structured for immediate agent consumption\n\n资料来源：[server/api/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/api/handoff.py)\n\n---\n\n## SLA API\n\n### Get SLA Metrics\n\n```\nGET /v1/subjects/{id}/sla\n```\n\nReturns structured SLA metrics for monitoring and reporting.\n\n**Response:**\n```json\n{\n  \"subject_id\": \"string\",\n  \"period\": \"string (e.g., '30d')\",\n  \"response_time_p50\": 120.5,\n  \"response_time_p95\": 450.0,\n  \"resolution_time_avg\": 1800.0,\n  \"total_sessions\": 150,\n  \"resolved_sessions\": 142,\n  \"breach_count\": 8,\n  \"breach_rate\": 0.053\n}\n```\n\n资料来源：[server/api/sla.py](https://github.com/smaramwbc/statewave/blob/main/server/api/sla.py)\n\n---\n\n## Admin API\n\nThe admin endpoints provide extended visibility and management capabilities for system operators.\n\n### List Episodes (Admin)\n\n```\nGET /admin/subjects/{subject_id}/episodes\n```\n\nAdministrative endpoint for listing episodes with pagination.\n\n### List Citing Memories\n\n```\nGET /admin/subjects/{subject_id}/episodes/{episode_id}/citing-memories\n```\n\nReturns all memories that cite a specific episode as a source. This enables reverse provenance lookup.\n\n### List All Subjects (Admin)\n\n```\nGET /admin/subjects\n```\n\nAdministrative listing of all subjects with optional pagination.\n\n### Import Subject Data\n\n```\nPOST /admin/import\n```\n\nImports episodes and memories for a subject from JSONL format.\n\n### Export Subject Data\n\n```\nGET /admin/subjects/{id}/export\n```\n\nExports all subject data (episodes, memories, resolutions) to JSONL format.\n\n### Create Snapshot\n\n```\nPOST /admin/snapshots\n```\n\nCreates a point-in-time snapshot of a subject's state.\n\n### Restore Snapshot\n\n```\nPOST /admin/snapshots/{id}/restore\n```\n\nRestores a subject from a previously created snapshot.\n\n### List Snapshots\n\n```\nGET /admin/snapshots\n```\n\nLists available snapshots with metadata.\n\n资料来源：[server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n\n---\n\n## Request/Response Schemas\n\n### Core Request Schema Fields\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `subject_id` | UUID | Yes | Target subject identifier |\n| `session_id` | string | No | Associated session |\n| `source` | string | No | Origin of data (e.g., 'mcp-server', 'github') |\n| `type` | string | No | Data type discriminator |\n| `payload` | object | Yes | Type-specific payload data |\n| `metadata` | object | No | Arbitrary metadata |\n| `provenance` | object | No | Source tracking information |\n\n### Core Response Schema Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | UUID | Unique resource identifier |\n| `created_at` | ISO8601 | Creation timestamp |\n| `updated_at` | ISO8601 | Last modification timestamp |\n| `status` | string | Resource status (active, archived, etc.) |\n\n资料来源：[server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n\n---\n\n## API Flow Diagram\n\n```mermaid\ngraph TD\n    A[Client] -->|POST /v1/episodes| B[Episodes API]\n    A -->|POST /v1/memories/compile| C[Memory Compiler]\n    A -->|GET /v1/memories/search| D[Memory Search]\n    A -->|POST /v1/context| E[Context Assembler]\n    \n    B --> F[(PostgreSQL<br/>episodes table)]\n    C --> G[Heuristic or LLM Compiler]\n    G --> H[(PostgreSQL<br/>memories table)]\n    D --> H\n    E --> H\n    E --> I[Ranked Context Bundle]\n    \n    A -->|GET /v1/timeline| J[Timeline Service]\n    J --> F\n    J --> H\n    \n    A -->|POST /v1/resolutions| K[(PostgreSQL<br/>resolutions table)]\n    \n    A -->|POST /v1/handoff| L[Handoff Generator]\n    L --> H\n    L --> M[Compact Handoff Pack]\n```\n\n---\n\n## Environment Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DATABASE_URL` | required | PostgreSQL connection string |\n| `STATEWAVE_API_KEY` | - | API authentication key |\n| `STATEWAVE_LITELLM_API_KEY` | - | LLM provider API key |\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Multi-tenant isolation header |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant header |\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Token budget for context assembly |\n| `STATEWAVE_RATE_LIMIT` | `0` | Requests per minute per IP |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | Rate limiting strategy |\n| `STATEWAVE_WEBHOOK_URL` | - | Webhook callback URL |\n| `STATEWAVE_CORS_ORIGINS` | `[\"*\"]` | Allowed CORS origins |\n\n资料来源：[README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n\n---\n\n## OpenAPI Documentation\n\nInteractive API documentation is available at:\n\n| URL | Format |\n|-----|--------|\n| `http://localhost:8100/docs` | Swagger UI |\n| `http://localhost:8100/redoc` | ReDoc |\n\nFull API contract documentation: [API v1 contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md)\n\n---\n\n<a id='page-context-assembly'></a>\n\n## Context Assembly & Ranking\n\n### 相关页面\n\n相关主题：[API Endpoints Reference](#page-api-endpoints), [Embedding Services](#page-embeddings), [Governance - Receipts & Policy Engine](#page-receipts-policy)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n- [server/api/context.py](https://github.com/smaramwbc/statewave/blob/main/server/api/context.py)\n- [server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n- [README.md](https://github.com/smaramwbc/statewave/blob/main/README.md)\n</details>\n\n# Context Assembly & Ranking\n\nContext Assembly & Ranking is the core mechanism that transforms raw episodic memory into a curated, token-bounded context bundle for LLM consumption. When an agent queries Statewave for context, the system retrieves relevant memories and episodes, scores them by relevance, and assembles them within a configurable token budget.\n\n## Architecture Overview\n\nThe context assembly system operates as a multi-stage pipeline:\n\n1. **Retrieval** — Query memories and episodes by subject, kind, text, or semantic similarity\n2. **Scoring** — Assign relevance scores to each item using configurable strategies\n3. **Ranking** — Sort items by score and enforce token budget constraints\n4. **Assembly** — Build the final context bundle with proper formatting and ordering\n\n```mermaid\ngraph TD\n    A[Client Request: POST /v1/context] --> B[ContextService.assemble]\n    B --> C[Retrieve Memories by Query]\n    B --> D[Retrieve Episodes by Query]\n    C --> E[_ScoredItem Scoring Loop]\n    D --> E\n    E --> F[Apply Ranking Strategy]\n    F --> G[Token Budget Enforcement]\n    G --> H[Context Bundle Response]\n    \n    E -->|score, kind, text, section| E\n```\n\n## Core Data Model\n\n### `_ScoredItem` Class\n\nThe fundamental unit used throughout the ranking pipeline is the `_ScoredItem` class, defined in `server/services/context.py`:\n\n```python\nclass _ScoredItem:\n    \"\"\"An item (memory or episode) with its computed relevance score.\"\"\"\n\n    __slots__ = (\"score\", \"kind\", \"memory_row\", \"episode_row\", \"text\", \"section\")\n\n    def __init__(\n        self,\n        score: float,\n        kind: str,\n        text: str,\n        section: str,\n        memory_row: Any = None,\n        episode_row: Any = None,\n    ) -> None:\n        self.score = score\n        self.kind = kind\n        self.memory_row = memory_row\n        self.episode_row = episode_row\n        self.text = text\n        self.section = section\n```\n\n| Attribute | Type | Description |\n|-----------|------|-------------|\n| `score` | `float` | Computed relevance score (higher = more relevant) |\n| `kind` | `str` | Item type: `\"memory\"` or `\"episode\"` |\n| `memory_row` | `Any` | `MemoryRow` instance when `kind == \"memory\"` |\n| `episode_row` | `Any` | `EpisodeRow` instance when `kind == \"episode\"` |\n| `text` | `str` | Extracted text content for scoring |\n| `section` | `str` | Section identifier for display/breadcrumb |\n\n资料来源：[server/services/context.py:49-67]()\n\n### Memory Response Model\n\nWhen context is assembled, memories are returned with full provenance:\n\n```python\nMemoryResponse(\n    id=m.id,\n    subject_id=m.subject_id,\n    kind=m.kind,\n    content=m.content,\n    summary=m.summary,\n    confidence=m.confidence,\n    valid_from=m.valid_from,\n    valid_to=m.valid_to,\n    source_episode_ids=m.source_episode_ids or [],\n    metadata=m.metadata_,\n    status=m.status,\n    sensitivity_labels=list(m.sensitivity_labels or []),\n    created_at=m.created_at,\n    updated_at=m.updated_at,\n)\n```\n\n资料来源：[server/api/timeline.py:1-20]()\n\n## Context Assembly Flow\n\n### Endpoint: `POST /v1/context`\n\nAssembles a ranked, token-bounded context bundle from a subject's episodic memory.\n\n```mermaid\nsequenceDiagram\n    participant Client\n    participant API as /v1/context\n    participant ContextService\n    participant MemoryStore\n    participant EpisodeStore\n\n    Client->>API: POST /v1/context {subject_id, query, max_tokens}\n    API->>ContextService: assemble(request)\n    ContextService->>MemoryStore: search_memories(query)\n    MemoryStore-->>ContextService: [MemoryRow...]\n    ContextService->>EpisodeStore: search_episodes(query)\n    EpisodeStore-->>ContextService: [EpisodeRow...]\n    ContextService->>ContextService: score_and_rank(items)\n    ContextService->>ContextService: enforce_token_budget(items, max_tokens)\n    ContextService-->>API: ContextResponse\n    API-->>Client: 200 OK\n```\n\n### Token Budget Enforcement\n\nThe system enforces a configurable token budget via the `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` environment variable (default: 4000 tokens). This ensures that:\n\n- Large subjects don't overwhelm LLM context windows\n- The most relevant items are prioritized\n- Lower-scored items are truncated when budget is exhausted\n\n| Parameter | Default | Description |\n|-----------|---------|-------------|\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Default token budget for context assembly |\n\n资料来源：[README.md:1-100]()\n\n## Ranking Strategies\n\nThe ranking system supports multiple strategies that can be applied in combination:\n\n### 1. Semantic Similarity Ranking\n\nFor queries with semantic intent, memories are ranked by vector similarity against the query embedding. This is the default strategy when using `kind=\"semantic\"` in search requests.\n\n### 2. Confidence-Based Ranking\n\nMemories include a `confidence` field (0.0–1.0) that reflects the compiler's certainty. Higher-confidence memories are ranked higher by default.\n\n| Memory Kind | Typical Confidence Range |\n|-------------|-------------------------|\n| `episode_summary` | 0.8 |\n| `profile_fact` | 0.6 |\n| `key_event` | 0.7–0.9 |\n| Custom | Variable |\n\n资料来源：[server/services/compilers/heuristic.py:1-100]()\n\n### 3. Temporal Recency Ranking\n\nFor timeline-sensitive queries, items can be weighted by recency (`valid_from`, `created_at`). Recent memories receive higher ranking weights.\n\n### 4. Composite Scoring\n\nThe `_ScoredItem` system enables composite scoring:\n\n```python\nfinal_score = (\n    semantic_weight * semantic_score +\n    confidence_weight * confidence +\n    recency_weight * recency_score\n)\n```\n\n## Memory Kinds and Their Role in Context\n\nStatewave supports structured memory kinds that inform ranking behavior:\n\n| Kind | Description | Ranking Priority |\n|------|-------------|-------------------|\n| `episode_summary` | Auto-generated summary of an episode | High |\n| `profile_fact` | Extracted subject facts | Medium-High |\n| `key_event` | Significant events in subject history | High |\n| `resolution` | Issue resolution tracking | Context-dependent |\n| Custom kinds | User-defined memory types | User-defined |\n\n资料来源：[server/services/compilers/heuristic.py:50-100]()\n\n## Configuration Options\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_DEFAULT_MAX_CONTEXT_TOKENS` | `4000` | Token budget for context assembly |\n| `STATEWAVE_LITELLM_API_KEY` | — | LLM API key for embedding-based ranking |\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Provider for semantic embeddings |\n\n资料来源：[README.md:100-150]()\n\n### Helm Chart Configuration\n\nFor Kubernetes deployments:\n\n```yaml\ncompiler:\n  type: llm  # or 'heuristic' for no-LLM mode\nembedding:\n  provider: litellm  # or 'stub' for demo mode\n```\n\n资料来源：[helm/statewave/README.md:1-50]()\n\n## API Response Structure\n\n### Success Response: `200 OK`\n\n```json\n{\n  \"subject_id\": \"uuid\",\n  \"query\": \"user query string\",\n  \"memories\": [\n    {\n      \"id\": \"uuid\",\n      \"subject_id\": \"uuid\",\n      \"kind\": \"episode_summary\",\n      \"content\": \"...\",\n      \"summary\": \"...\",\n      \"confidence\": 0.8,\n      \"valid_from\": \"2024-01-15T10:00:00Z\",\n      \"valid_to\": \"2024-01-20T10:00:00Z\",\n      \"source_episode_ids\": [\"uuid1\", \"uuid2\"],\n      \"metadata\": {},\n      \"status\": \"active\",\n      \"sensitivity_labels\": [],\n      \"created_at\": \"2024-01-15T10:30:00Z\",\n      \"updated_at\": \"2024-01-15T10:30:00Z\"\n    }\n  ],\n  \"episodes\": [],\n  \"total_tokens\": 3500,\n  \"truncated\": false\n}\n```\n\n## Snapshot Integration\n\nContext assembly respects snapshot-restored memories. When memories are restored from snapshots, they carry provenance:\n\n```python\nmetadata_={\n    **mem.metadata_,\n    \"restored_from_snapshot\": str(snapshot_id),\n}\n```\n\n资料来源：[server/services/snapshots.py:1-50]()\n\n## Memory Evolution and Context\n\nThe memory evolution system tracks superseding relationships:\n\n```python\nclass MemoryEvolutionResponse(BaseModel):\n    memory_id: str\n    status: str\n    created_at: str\n    superseding_memory: Optional[MemoryRelation]\n    superseded_memories: list[MemoryRelation]\n    sibling_memories: list[MemoryRelation]\n    source_episode_count: int\n```\n\nWhen assembling context, superseded memories may be excluded or marked, ensuring agents see the most current information.\n\n资料来源：[server/api/admin.py:1-100]()\n\n## Evaluation and Testing\n\nThe `scripts/eval/eval_docs_support.py` module provides evaluation patterns for context quality:\n\n```python\nQuestion(\n    task=\"How does context ranking work?\",\n    expected_doc_paths=[\"architecture/ranking.md\"],\n    expected_terms=[\"ranking\", \"score\"],\n)\n```\n\nThis validates that the ranking system correctly surfaces relevant memories for queries.\n\n资料来源：[scripts/eval/eval_docs_support.py:1-50]()\n\n## Best Practices\n\n1. **Set Appropriate Token Budgets**: Balance context richness against LLM limits. Start with 4000 and adjust based on model context window.\n\n2. **Use Semantic Search for Complex Queries**: When users ask complex questions, semantic similarity ranking outperforms keyword matching.\n\n3. **Leverage Memory Kinds**: Structure memories with appropriate kinds to enable kind-filtered context retrieval.\n\n4. **Monitor Confidence Scores**: Low-confidence memories may indicate compilation issues or ambiguous data.\n\n5. **Snapshot Before Major Changes**: Use snapshots to preserve context state before bulk operations.\n\n## Related Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/v1/context` | Assemble ranked, token-bounded context bundle |\n| `GET` | `/v1/memories/search` | Search by kind, text, or semantic similarity |\n| `GET` | `/v1/timeline` | Chronological subject timeline |\n| `GET` | `/v1/subjects` | List known subjects with episode/memory counts |\n\n资料来源：[README.md:50-80]()\n\n---\n\n<a id='page-compilation-services'></a>\n\n## Compilation Services\n\n### 相关页面\n\n相关主题：[System Architecture](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/compiler.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compiler.py)\n- [server/services/compilers/heuristic.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/heuristic.py)\n- [server/services/compilers/llm.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compilers/llm.py)\n- [server/services/conflicts.py](https://github.com/smaramwbc/statewave/blob/main/server/services/conflicts.py)\n- [server/services/compile_jobs.py](https://github.com/smaramwbc/statewave/blob/main/server/services/compile_jobs.py)\n</details>\n\n# Compilation Services\n\nCompilation Services transform raw episodes into structured memories within Statewave. This process extracts meaningful information from conversation events, resolves conflicts between overlapping facts, and produces durable knowledge representations that agents can retrieve during context assembly.\n\n## Overview\n\nStatewave's compilation pipeline operates as a multi-stage process that converts incoming episode data into memory entities. The system supports two distinct compilation modes — heuristic and LLM — allowing deployments to choose between performance and intelligence based on infrastructure constraints.\n\n```mermaid\ngraph TD\n    A[Episode Ingest] --> B{Compilation Mode}\n    B -->|Heuristic| C[Heuristic Compiler]\n    B -->|LLM| D[LLM Compiler]\n    C --> E[Memory Rows]\n    D --> E\n    E --> F[Conflict Resolution]\n    F --> G[Finalized Memories]\n    \n    H[Context Assembly] --> I[Memory Retrieval]\n    G --> I\n```\n\n## Compilation Modes\n\nStatewave ships with two compiler implementations, each suited to different operational contexts.\n\n### Heuristic Compiler\n\nThe heuristic compiler performs rule-based extraction without external AI dependencies. It analyzes episode text using pattern matching and natural language heuristics to identify structured facts.\n\n**Supported Memory Kinds:**\n\n| Kind | Description | Confidence | TTL |\n|------|-------------|------------|-----|\n| `episode_summary` | Concise summary of episode content | 0.8 | 30 days |\n| `profile_fact` | Extracted user profile attributes | 0.6 | 90 days |\n| `preference` | User-stated preferences | 0.7 | 60 days |\n| `fact` | General factual statements | 0.65 | 60 days |\n\nThe heuristic compiler processes each episode independently, extracting profile facts through pattern recognition and generating episode summaries through text truncation and normalization.\n\n### LLM Compiler\n\nThe LLM compiler leverages large language models to perform semantic understanding of episodes. This mode produces higher-quality memories with better contextual awareness but requires external LLM infrastructure.\n\n**Key Capabilities:**\n- Multi-episode summarization across conversation turns\n- Inference of implicit facts not explicitly stated\n- Better handling of ambiguous or complex dialogue\n- Cross-episode fact consolidation\n\n## Temporal Anchoring\n\nEvery memory requires a temporal anchor to support time-bounded queries and historical reasoning. The compilation system determines validity windows using a priority cascade.\n\n```mermaid\ngraph LR\n    A[Temporal Anchor Priority] --> B[payload.event_time]\n    B --> C[payload.messages[0].timestamp]\n    C --> D[Episode created_at]\n    \n    E[compute_valid_to] --> F[Memory.valid_from]\n    F --> G[Memory.valid_to]\n```\n\n**Anchor Resolution Order:**\n1. Explicit `event_time` in episode payload (connector replay scenarios)\n2. First message timestamp in chat-shaped payloads\n3. Episode creation timestamp (fallback)\n\nThe `valid_to` date derives from the memory kind's configured TTL (time-to-live), ensuring automatic expiration of transient information.\n\n## Conflict Resolution\n\nWhen multiple episodes produce overlapping memories, the conflict resolution service determines which information takes precedence.\n\n```mermaid\ngraph TD\n    A[New Memory] --> B{Same Subject?}\n    B -->|No| C[Insert Directly]\n    B -->|Yes| D{Overlapping Time Range?}\n    D -->|No| E[Insert Directly]\n    D -->|Yes| F{Conflicting Content?}\n    F -->|No| G[Insert as Sibling]\n    F -->|Yes| H[Apply Resolution Strategy]\n    \n    H --> I{Strategy: Supersede}\n    H --> J{Strategy: Merge}\n    H --> K{Strategy: Retain Both}\n    \n    I --> L[Mark Older as Superseded]\n    J --> M[Combine Content]\n    K --> N[Link as Alternatives]\n```\n\n**Resolution Strategies:**\n\n| Strategy | Behavior | Use Case |\n|----------|----------|----------|\n| `supersede` | Replace older conflicting memory | Corrected information |\n| `merge` | Combine facts from both memories | Complementary details |\n| `retain_both` | Keep both as alternatives | Ambiguous or opinion-based |\n\n## Compilation Job Management\n\nLong-running compilation tasks are managed through an asynchronous job system that prevents API timeouts and supports retry logic.\n\n```mermaid\ngraph TD\n    A[POST /v1/memories/compile] --> B{Currently Compiling?}\n    B -->|Yes| C[Return 409 Conflict]\n    B -->|No| D[Queue Job]\n    D --> E[Job Created]\n    E --> F[Background Processing]\n    F --> G{Success?}\n    G -->|Yes| H[Memories Created]\n    G -->|No| I{Retryable?}\n    I -->|Yes| J[Retry with Backoff]\n    I -->|No| K[Mark Failed]\n    J --> F\n```\n\n**Job States:**\n- `pending` — Queued for processing\n- `running` — Actively compiling\n- `completed` — Successfully finished\n- `failed` — Unrecoverable error\n- `cancelled` — Manually aborted\n\n## Data Models\n\n### Episode to Memory Flow\n\n```\nEpisodeRow\n├── id: UUID\n├── subject_id: UUID\n├── source: str (e.g., \"mcp-server\", \"github\", \"statewave-docs\")\n├── type: str (e.g., \"conversation\", \"doc_section\", \"issue\")\n├── payload: dict\n│   ├── title: str\n│   ├── text: str\n│   ├── messages: list[dict]\n│   └── ...\n├── metadata_: dict\n├── provenance: dict\n│   └── content_hash: str\n└── created_at: datetime\n\n         ↓ Compilation\n\nMemoryRow\n├── id: UUID\n├── subject_id: UUID\n├── kind: str (e.g., \"episode_summary\", \"profile_fact\")\n├── content: str\n├── summary: str\n├── confidence: float (0.0 - 1.0)\n├── valid_from: datetime\n├── valid_to: datetime\n├── source_episode_ids: list[UUID]\n├── metadata_: dict\n├── status: str (\"active\", \"superseded\", \"redacted\")\n├── sensitivity_labels: list[str]\n├── embedding: vector (optional)\n└── created_at, updated_at: datetime\n```\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `STATEWAVE_COMPILER_TYPE` | `llm` | Compiler mode: `llm` or `heuristic` |\n| `STATEWAVE_LLM_API_KEY` | — | API key for LLM provider |\n| `STATEWAVE_LLM_MODEL` | `gpt-4o` | Model identifier for LLM compiler |\n| `STATEWAVE_COMPILE_TIMEOUT` | `300` | Compilation timeout in seconds |\n\n### Helm Chart Configuration\n\n| Value | Default | Notes |\n|-------|---------|-------|\n| `compiler.type` | `llm` | `heuristic` for no-LLM mode |\n| `llm.apiKey` | — | Required when `compiler.type=llm` |\n| `llm.model` | `gpt-4o` | Override default model |\n\n## Idempotency\n\nCompilation is designed to be idempotent. Re-running compilation on episodes that have already been compiled will not create duplicate memories. The system tracks `source_episode_ids` to prevent reprocessing and uses content hashing in provenance metadata to detect unchanged source material.\n\nThis design supports:\n- Safe re-compilation after configuration changes\n- Incremental updates from connector replay\n- Bootstrap and refresh workflows\n\n## API Integration\n\nCompilation is triggered through the REST API:\n\n```bash\nPOST /v1/memories/compile\n```\n\nThe endpoint accepts a `subject_id` and initiates asynchronous processing. Polling the job status or receiving webhooks (if configured) provides completion feedback.\n\n**Request Example:**\n```json\n{\n  \"subject_id\": \"550e8400-e29b-41d4-a716-446655440000\",\n  \"force\": false\n}\n```\n\n**Response:**\n```json\n{\n  \"status\": \"queued\",\n  \"job_id\": \"660e8400-e29b-41d4-a716-446655440001\"\n}\n\n---\n\n<a id='page-embeddings'></a>\n\n## Embedding Services\n\n### 相关页面\n\n相关主题：[Context Assembly & Ranking](#page-context-assembly)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/embeddings/litellm.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/litellm.py)\n- [server/services/embeddings/stub.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/stub.py)\n- [server/services/embeddings/query_cache.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/query_cache.py)\n- [server/services/embeddings/backfill.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/backfill.py)\n</details>\n\n# Embedding Services\n\nEmbedding Services provide semantic vector representations for memories and episodes in Statewave, enabling similarity-based search, context ranking, and retrieval-augmented generation workflows.\n\n## Overview\n\nThe embedding layer is a pluggable component that converts textual content into high-dimensional vector embeddings. These vectors power the semantic search capabilities of the `/v1/memories/search` endpoint and the relevance scoring in context assembly (`POST /v1/context`).\n\nStatewave supports two embedding providers:\n\n| Provider | Purpose | Use Case |\n|----------|---------|----------|\n| `litellm` | Real embeddings via LiteLLM proxy | Production deployments with LLM API access |\n| `stub` | Zero vectors (all dimensions = 0) | Development, demos, or when embeddings are disabled |\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Embedding Services Layer\"\n        LLM[LiteLLM Embeddings<br/>litellm.py]\n        STUB[Stub Embeddings<br/>stub.py]\n        CACHE[Query Cache<br/>query_cache.py]\n    end\n    \n    subgraph \"Backfill Operations\"\n        BF[Backfill Service<br/>backfill.py]\n    end\n    \n    subgraph \"Consumers\"\n        SEARCH[Memory Search<br/>/v1/memories/search]\n        CONTEXT[Context Assembly<br/>/v1/context]\n        COMPILER[Memory Compiler]\n    end\n    \n    LLM --> CACHE\n    STUB --> CACHE\n    CACHE --> SEARCH\n    CACHE --> CONTEXT\n    CACHE --> COMPILER\n    BF --> LLM\n    BF --> STUB\n```\n\n## Configuration\n\nEmbedding behavior is controlled via environment variables:\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `STATEWAVE_EMBEDDING_PROVIDER` | `litellm` | Embedding provider: `litellm` or `stub` |\n| `STATEWAVE_LITELLM_API_KEY` | — | API key for LiteLLM |\n| `STATEWAVE_LITELLM_BASE_URL` | — | Custom LiteLLM base URL (for proxy deployments) |\n| `STATEWAVE_EMBEDDING_MODEL` | provider default | Specific embedding model to use |\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n## Providers\n\n### LiteLLM Provider\n\nThe LiteLLM provider (`server/services/embeddings/litellm.py`) routes embedding requests through the LiteLLM proxy library, which standardizes access to multiple LLM backends including OpenAI, Azure, Cohere, and custom providers.\n\n**Key responsibilities:**\n\n- Accept text input and return normalized embedding vectors\n- Handle API authentication via `STATEWAVE_LITELLM_API_KEY`\n- Support custom base URLs via `STATEWAVE_LITELLM_BASE_URL`\n- Model selection via `STATEWAVE_EMBEDDING_MODEL`\n- Normalize embedding dimensions across providers\n\n### Stub Provider\n\nThe stub provider (`server/services/embeddings/stub.py`) returns zero vectors for all inputs. This is useful for:\n\n- Development environments without API access\n- Demo deployments where semantic search is not required\n- Testing the rest of the system without embedding dependencies\n\n资料来源：[server/services/embeddings/stub.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/stub.py)\n\n## Query Cache\n\nThe query cache (`server/services/embeddings/query_cache.py`) reduces redundant embedding computations by caching the results of previously generated embeddings.\n\n### Cache Strategy\n\n```mermaid\ngraph LR\n    A[Embedding Request] --> B{Hit in Cache?}\n    B -->|Yes| C[Return Cached Vector]\n    B -->|No| D[Compute Embedding]\n    D --> E[Store in Cache]\n    E --> F[Return Vector]\n    C --> F\n```\n\n### Cache Behavior\n\n- Cache key is derived from the text content being embedded\n- Cached vectors are returned directly on cache hit\n- Reduces API calls and latency for repeated queries\n- Particularly effective for search queries that repeat across requests\n\n资料来源：[server/services/embeddings/query_cache.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/query_cache.py)\n\n## Backfill Operations\n\nThe backfill service (`server/services/embeddings/backfill.py`) handles bulk embedding regeneration for existing data.\n\n### Use Cases\n\n- **Model migration**: When switching embedding models, regenerate all existing embeddings\n- **Corruption recovery**: Rebuild embeddings for data with missing or corrupted vectors\n- **Schema changes**: When embedding schema or normalization changes\n\n### Backfill Process\n\n```mermaid\ngraph TD\n    A[Start Backfill] --> B[Query Rows Missing Embeddings]\n    B --> C{Process Batch}\n    C -->|Has More| D[Fetch Batch]\n    D --> E[Generate Embeddings]\n    E --> F[Update Database]\n    F --> C\n    C -->|Complete| G[Backfill Complete]\n```\n\n资料来源：[server/services/embeddings/backfill.py](https://github.com/smaramwbc/statewave/blob/main/server/services/embeddings/backfill.py)\n\n## Integration with Memory System\n\nEmbeddings are stored alongside memory records and used for relevance scoring:\n\n```mermaid\ngraph LR\n    subgraph \"Memory Row Schema\"\n        M1[id]\n        M2[content]\n        M3[embedding]\n        M4[source_episode_ids]\n    end\n    \n    subgraph \"Usage Flow\"\n        S[Search Query] --> E[Generate Query Embedding]\n        E --> SC[Compute Similarity Scores]\n        M3 --> SC\n        SC --> R[Ranked Results]\n    end\n```\n\nThe `embedding` field in `MemoryRow` stores the vector representation of memory content, enabling:\n\n1. **Semantic similarity search** via cosine similarity\n2. **Context relevance scoring** during context assembly\n3. **Deduplication** by detecting high-similarity memory candidates\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n## API Endpoints Using Embeddings\n\n| Endpoint | Embedding Usage |\n|----------|-----------------|\n| `GET /v1/memories/search` | Query embedding vs stored memory embeddings |\n| `POST /v1/context` | Rank episode and memory candidates by relevance |\n| `POST /v1/memories/compile` | Generate embeddings for new memories |\n\n## Deployment Considerations\n\n### Production Deployment\n\nFor production with semantic search enabled:\n\n1. Set `STATEWAVE_EMBEDDING_PROVIDER=litellm`\n2. Configure `STATEWAVE_LITELLM_API_KEY` with appropriate permissions\n3. Optionally specify `STATEWAVE_EMBEDDING_MODEL` for a specific model\n4. For proxy deployments, set `STATEWAVE_LITELLM_BASE_URL`\n\n### Demo Mode\n\nFor demos or development without API costs:\n\n1. Set `STATEWAVE_EMBEDDING_PROVIDER=stub`\n2. Full functionality except semantic search (returns zero similarity)\n\n资料来源：[helm/statewave/README.md](https://github.com/smaramwbc/statewave/blob/main/helm/statewave/README.md)\n\n### Helm Configuration\n\n```yaml\nembedding:\n  provider: litellm  # or \"stub\" for demo mode\n  model: \"\"          # optional: specify model\n```\n\n## Related Services\n\n- **Compiler Services**: Use embeddings during memory compilation\n- **Context Assembly**: Uses embeddings for relevance scoring\n- **Memory Search**: Primary consumer of embedding similarity\n- **Snapshots**: Preserves embeddings when snapshotting subject state\n\n资料来源：[server/services/snapshots.py](https://github.com/smaramwbc/statewave/blob/main/server/services/snapshots.py)\n\n---\n\n<a id='page-receipts-policy'></a>\n\n## Governance - Receipts & Policy Engine\n\n### 相关页面\n\n相关主题：[Multi-tenancy & Security](#page-multi-tenancy), [Context Assembly & Ranking](#page-context-assembly)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py) - Context assembly with receipt emission\n- [server/services/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/services/handoff.py) - Handoff service with receipt support\n- [server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py) - Response schemas including receipt fields\n- [server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py) - Request schemas with receipt and policy parameters\n- [server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py) - Database schema including PolicyBundleRow\n</details>\n\n# Governance - Receipts & Policy Engine\n\n## Overview\n\nThe Governance layer in Statewave provides two interrelated mechanisms for operational accountability and data access control:\n\n1. **State Assembly Receipts** — Immutable audit records that capture exactly which memories and episodes were included in a `/v1/context` or `/v1/handoff` response, enabling full traceability of AI-generated context.\n2. **Policy Engine** — A content-addressed bundle system that enforces sensitivity-label-based filtering on memories before they appear in responses, with configurable enforcement modes.\n\nThese systems work together to ensure that when a context bundle is assembled for downstream AI consumption, there is a verifiable record of what was included, why it was included, and what policy rules were applied.\n\n资料来源：[server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n\n---\n\n## State Assembly Receipts\n\n### Purpose\n\nReceipts address the \"black box\" problem in RAG-based AI systems. When an agent receives a context bundle, receipts provide cryptographic proof of:\n\n- Which specific memories and episodes were selected\n- The ranking scores used for selection\n- What policy filters were applied\n- The token budget consumed\n- Which policy bundle version governed the decision\n\nThis enables auditing, debugging, compliance reporting, and reproducibility of AI decisions that depend on Statewave's memory layer.\n\n### Receipt Data Model\n\nReceipts are persisted to the database and linked to the request via a unique `receipt_id`. The core receipt structure captures the complete assembly decision:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `receipt_id` | `uuid.UUID` | Unique identifier for this receipt |\n| `subject_id` | `str` | The subject whose context was assembled |\n| `task` | `str` | The task/retrieval purpose |\n| `tenant_id` | `str \\| None` | Tenant context for multi-tenant deployments |\n| `as_of` | `datetime` | Timestamp of the assembly request |\n| `context_hash` | `str` | Hash of the assembled context for integrity verification |\n| `context_size_bytes` | `int` | Size of the assembled context in bytes |\n| `token_estimate` | `int` | Estimated token count consumed |\n| `selected_memories` | `list` | Memory IDs with scores that were included |\n| `selected_episodes` | `list` | Episode IDs with scores that were included |\n| `policy_bundle_hash` | `str \\| None` | Hash of the policy bundle applied |\n| `policy_mode` | `str` | Mode used (`log_only` or `enforce`) |\n| `filters_applied` | `list` | Policy rules that resulted in exclusions |\n| `filters_skipped` | `list` | Policy rules not triggered |\n| `query_id` | `str \\| None` | External correlation ID |\n| `task_id` | `str \\| None` | Task correlation ID |\n| `parent_receipt_id` | `str \\| None` | For nested/derived requests |\n| `caller_id` | `str \\| None` | Identity of the calling service |\n| `caller_type` | `str \\| None` | Type of caller (service, user, etc.) |\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n### Receipt Emission Modes\n\nReceipts support three emission policies configurable at the tenant level:\n\n| Mode | Behavior |\n|------|----------|\n| `on_request` (default) | Callers opt in per-request via `emit_receipt: true` |\n| `always` | Every context/handoff request generates a receipt, overriding `emit_receipt: false` |\n| `never` | No receipts are generated, regardless of request flags |\n\n配置来源：[server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py)\n\n### Receipt Response Fields\n\nWhen a receipt is successfully written, the response includes:\n\n```python\nreceipt_id: str | None  # UUID of the written receipt, None if emission failed\nreceipt_emitted: bool   # True iff receipt was successfully persisted\n```\n\nThe `receipt_emitted` field distinguishes between three states:\n\n1. **True** — Receipt was successfully written\n2. **False with `receipt_id = None`** — Receipt emission was not requested\n3. **False with `receipt_id = ...`** — Emission was attempted but failed; the response is still authoritative\n\n资料来源：[server/schemas/responses.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/responses.py)\n\n### Receipt Emission Workflow\n\n```mermaid\nsequenceDiagram\n    participant Caller\n    participant ContextService\n    participant PolicyEngine\n    participant ReceiptsService\n    participant Database\n\n    Caller->>ContextService: POST /v1/context (emit_receipt=true)\n    ContextService->>PolicyEngine: Filter memories by sensitivity labels\n    PolicyEngine-->>ContextService: Filtered memories + applied/skipped rules\n    \n    ContextService->>ContextService: Assemble context bundle\n    ContextService->>ReceiptsService: Build receipt body\n    ReceiptsService->>Database: Write receipt record\n    Database-->>ReceiptsService: receipt_id\n    \n    ContextService-->>Caller: ContextBundleResponse + receipt_id, receipt_emitted=true\n```\n\nThe `_maybe_emit_receipt` helper in the context service implements this flow, accepting parameters for memory rows, episode rows, policy decisions, and caller identity.\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n---\n\n## Policy Engine\n\n### Architecture Overview\n\nThe Policy Engine operates on an immutable, content-addressed bundle model. Each policy bundle is:\n\n1. **Content-addressed** — Identified by `bundle_hash` (SHA-256 of YAML content)\n2. **Tenant-scoped** — Same YAML can be installed by different tenants as independent rows\n3. **Activatable** — Only one bundle per tenant can be active at a time\n\n```mermaid\ngraph TD\n    A[YAML Policy File] --> B[Compute bundle_hash]\n    B --> C[PolicyBundleRow]\n    C --> D{Tenant A}\n    C --> E{Tenant B}\n    D --> F[Active Bundle]\n    E --> G[Active Bundle]\n    \n    H[Context Request] --> I[Lookup active bundle]\n    I --> F\n    F --> J[Apply filters to memories]\n    J --> K[Filtered response]\n```\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n### PolicyBundleRow Schema\n\n| Column | Type | Description |\n|--------|------|-------------|\n| `id` | `UUID` | Synthetic primary key (allows multiple tenants to install same bundle) |\n| `bundle_hash` | `String(64)` | SHA-256 of YAML content, indexed |\n| `yaml_content` | `Text` | Full YAML policy definition |\n| `active` | `Boolean` | Whether this is the tenant's active policy |\n| `tenant_id` | `String(256)` | Tenant scope (NULL for system-wide) |\n| `config` | `JSONB` | Additional configuration |\n| `version` | `Integer` | Row version for optimistic locking |\n| `created_at` | `DateTime` | Creation timestamp |\n| `updated_at` | `DateTime` | Last modification timestamp |\n\nThe composite unique index on `(tenant_id, bundle_hash) NULLS NOT DISTINCT` enforces \"one bundle per (scope, content)\" — two tenants can independently install identical policy YAML.\n\n资料来源：[server/db/tables.py](https://github.com/smaramwbc/statewave/blob/main/server/db/tables.py)\n\n### Policy Modes\n\nThe policy engine operates in two modes:\n\n| Mode | Behavior | Use Case |\n|------|----------|----------|\n| `log_only` (default) | Records what *would* be filtered into receipts without removing memories | Initial deployment, auditing, compliance review |\n| `enforce` | Drops denied memories and redacts marked ones from the response | Production enforcement after validating log_only behavior |\n\n```python\npolicy_mode: Literal[\"log_only\", \"enforce\"] | None = Field(\n    None,\n    description=(\n        \"Sensitivity-label policy enforcement mode (#50). `log_only` \"\n        \"(the default) records what *would* be filtered into receipts \"\n        \"without removing memories from the response. `enforce` drops \"\n        \"denied memories and redacts marked ones. Flip to enforce only \"\n        \"after auditing the log_only receipts for a few days.\"\n    ),\n)\n```\n\n配置来源：[server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py)\n\n### Policy Filter Tracking\n\nWhen a context bundle is assembled, the policy engine records:\n\n- **`filters_applied`** — List of policy rules that resulted in memory exclusions or modifications\n- **`filters_skipped`** — List of policy rules that were evaluated but not triggered\n\nThis data is written to receipts, enabling operators to:\n\n1. Verify that policies are being evaluated correctly\n2. Identify false positives in `enforce` mode before full deployment\n3. Generate compliance reports on data access patterns\n\n资料来源：[server/services/context.py](https://github.com/smaramwbc/statewave/blob/main/server/services/context.py)\n\n---\n\n## Integration Points\n\n### Context Assembly (`/v1/context`)\n\nThe primary integration point where receipts are emitted and policy is enforced:\n\n```\nPOST /v1/context\n{\n  \"subject_id\": \"customer-123\",\n  \"task\": \"support_response\",\n  \"emit_receipt\": true,\n  \"policy_mode\": \"enforce\",\n  ...\n}\n```\n\nResponse includes `receipt_id` and `receipt_emitted` fields.\n\n### Handoff Service (`/v1/handoff`)\n\nThe handoff service also supports receipt emission for agent-to-agent transitions:\n\n```python\nhandoff_notes=handoff_notes,\ntoken_estimate=token_estimate,\nactive_fact_rows=[row for row in fact_rows if row.status == \"active\"],\nsession_episode_rows=current_session_eps[:10],\nemit_receipt=emit_receipt,\npolicy_bundle=active_bundle,\npolicy_mode=policy_mode,\n```\n\n资料来源：[server/services/handoff.py](https://github.com/smaramwbc/statewave/blob/main/server/services/handoff.py)\n\n### Tenant Configuration\n\nReceipts and policy settings can be configured at the tenant level:\n\n| Configuration | Type | Default | Description |\n|--------------|------|---------|-------------|\n| `receipts` | `Literal[\"always\", \"on_request\", \"never\"]` | `on_request` | Global receipt emission policy |\n| `receipt_retention_days` | `int` | `0` (forever) | Days to retain receipts before purge (0 = never purge) |\n| `policy_mode` | `Literal[\"log_only\", \"enforce\"]` | `log_only` | Default policy enforcement mode |\n| `require_caller_identity` | `bool` | `false` | Require `caller_id`/`caller_type` for context/handoff |\n\n配置来源：[server/schemas/requests.py](https://github.com/smaramwbc/statewave/blob/main/server/schemas/requests.py)\n\n---\n\n## Security Considerations\n\n### Caller Identity\n\nWhen `require_caller_identity` is enabled, the `/v1/context` and `/v1/handoff` endpoints will:\n\n- Reject anonymous callers (missing both `caller_id` and `caller_type`)\n- Record caller identity in receipts for audit purposes\n\nThis ensures that every context assembly can be traced to a specific service or user.\n\n### Immutable Receipts\n\nReceipts are append-only by design. Once written, they cannot be modified. This provides:\n\n- Non-repudiation for compliance audits\n- Reproducibility of AI decisions\n- Historical tracking of policy changes\n\n### Policy Bundle Integrity\n\nThe content-addressed nature of policy bundles means:\n\n- Any modification to the YAML content produces a different `bundle_hash`\n- The old bundle remains accessible by its hash\n- The `bundle_hash` recorded in receipts provides proof of which policy version was applied\n\n---\n\n## Related Documentation\n\n- [API v1 Contract](https://github.com/smaramwbc/statewave-docs/blob/main/api/v1-contract.md)\n- [Getting Started Guide](https://github.com/smaramwbc/statewave-docs/blob/main/getting-started.md)\n- [Architecture Overview](https://github.com/smaramwbc/statewave-docs/blob/main/architecture/overview.md)\n\n---\n\n<a id='page-multi-tenancy'></a>\n\n## Multi-tenancy & Security\n\n### 相关页面\n\n相关主题：[Governance - Receipts & Policy Engine](#page-receipts-policy)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [server/core/tenant.py](https://github.com/smaramwbc/statewave/blob/main/server/core/tenant.py)\n- [server/core/auth.py](https://github.com/smaramwbc/statewave/blob/main/server/core/auth.py)\n- [server/core/ratelimit.py](https://github.com/smaramwbc/statewave/blob/main/server/core/ratelimit.py)\n- [server/services/webhooks.py](https://github.com/smaramwbc/statewave/blob/main/server/services/webhooks.py)\n- [server/api/admin.py](https://github.com/smaramwbc/statewave/blob/main/server/api/admin.py)\n- [server/services/ratelimit.py](https://github.com/smaramwbc/statewave/blob/main/server/services/ratelimit.py)\n</details>\n\n# Multi-tenancy & Security\n\n## Overview\n\nStatewave implements a multi-tenant architecture with comprehensive security controls for enterprise deployments. The system provides query-scoped data isolation, per-tenant policy enforcement, caller identity validation, and distributed rate limiting—all coordinated through a Postgres-backed shared infrastructure.\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"API Layer\"\n        A[Incoming Request] --> B[Tenant Resolution]\n        B --> C[Auth Middleware]\n        C --> D[Rate Limiter]\n        D --> E[Policy Engine]\n        E --> F[Business Logic]\n    end\n    \n    subgraph \"Security Components\"\n        C -->|API Key| Auth[Auth Service]\n        D -->|Distributed| RL[Rate Limit Store]\n        E -->|Bundle Hash| PB[Policy Bundles]\n        E -->|caller_id/caller_type| CI[Caller Identity]\n    end\n    \n    subgraph \"Tenant Isolation\"\n        B -->|tenant_id| TI[Tenant Isolation Layer]\n        TI -->|query scoping| DB[(Postgres)]\n        PB -->|per-tenant| TI\n    end\n```\n\n## Tenant Resolution\n\n### Tenant Header Configuration\n\nStatewave uses a configurable HTTP header for tenant identification. The header name defaults to `X-Tenant-ID` but can be customized via environment variables.\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `STATEWAVE_TENANT_HEADER` | `X-Tenant-ID` | Header for multi-tenant isolation |\n| `STATEWAVE_REQUIRE_TENANT` | `false` | Reject requests without tenant header |\n\nWhen `STATEWAVE_REQUIRE_TENANT` is set to `true`, any request missing the tenant header receives a `400 Bad Request` response. When `false`, requests without a tenant header are processed with an anonymous tenant context.\n\n资料来源：[README.md:env-vars]() (configuration documentation)\n\n### Tenant Resolution Flow\n\n```mermaid\nsequenceDiagram\n    participant C as Client\n    participant A as API Server\n    participant T as Tenant Resolver\n    participant DB as Postgres\n    \n    C->>A: Request + X-Tenant-ID header\n    A->>T: Extract tenant_id\n    T->>DB: Lookup tenant config\n    DB-->>T: TenantConfigResponse\n    T-->>A: Tenant context\n    A->>A: Apply tenant-scoped logic\n```\n\n## Tenant Configuration API\n\n### Configuration Schema\n\nThe `TenantConfigResponse` schema defines the tenant configuration structure:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `tenant_id` | `str` | Unique tenant identifier |\n| `config` | `dict[str, Any]` | Full configuration document |\n| `version` | `int` | Optimistic-concurrency counter |\n| `created_at` | `datetime \\| None` | First configuration timestamp |\n| `updated_at` | `datetime \\| None` | Last modification timestamp |\n\n### Configuration Keys\n\n| Key | Type | Description |\n|-----|------|-------------|\n| `receipts` | `string` | Emission mode: `\"always\"`, `\"never\"`, `\"on_request\"` |\n| `receipt_retention_days` | `int` | Days to retain receipts before cleanup |\n| `policy_mode` | `string` | `\"log_only\"` or `\"enforce\"` |\n| `require_caller_identity` | `bool` | Enforce caller_id/caller_type presence |\n\n资料来源：[server/schemas/responses.py:tenant-config-schema]() (response schema definition)\n\n### Admin Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `GET` | `/admin/tenants/{id}/config` | Retrieve tenant configuration |\n| `PATCH` | `/admin/tenants/{id}/config` | Update tenant configuration |\n\n#### PATCH Request Shape\n\nThe PATCH operation performs a merge update with optimistic concurrency control:\n\n```python\n# Expected version must match current state\n{\n    \"expected_version\": 5,\n    \"config\": {\n        \"policy_mode\": \"enforce\",\n        \"receipt_retention_days\": 90\n    }\n}\n```\n\nIf `expected_version` does not match the current database version, the update fails with a `409 Conflict` response.\n\n资料来源：[server/api/admin.py:config-endpoints]() (admin API implementation)\n\n## Authentication & Authorization\n\n### API Key Authentication\n\nStatewave supports API key authentication via the `Authorization` header:\n\n```http\nAuthorization: Bearer <api_key>\n```\n\nOr via query parameter for specific integration scenarios:\n\n```http\nGET /v1/context?api_key=<api_key>\n```\n\n### Caller Identity Validation\n\nWhen `require_caller_identity` is enabled in tenant config, every context and handoff request must include:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `caller_id` | `str` | Unique identifier of the calling agent/user |\n| `caller_type` | `str` | Type classification (e.g., `\"agent\"`, `\"user\"`, `\"system\"`) |\n\nRequests missing these fields receive a `401 Unauthorized` response:\n\n```json\n{\n    \"detail\": \"tenant config requires caller_id and caller_type on every context call\"\n}\n```\n\n资料来源：[server/api/handoff.py:identity-validation]() (identity enforcement)\n\n## Rate Limiting\n\n### Rate Limit Strategy\n\nStatewave supports two rate limiting backends:\n\n| Strategy | Backend | Use Case |\n|----------|---------|----------|\n| `distributed` | Postgres | Multi-instance deployments |\n| `memory` | In-process | Single instance / development |\n\n### Configuration\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `STATEWAVE_RATE_LIMIT` | `1000` | Requests per window |\n| `STATEWAVE_RATE_WINDOW` | `60` | Window duration in seconds |\n| `STATEWAVE_RATE_LIMIT_STRATEGY` | `distributed` | Backend strategy selection |\n\n### Current Limitations\n\n> **Note**: Rate limiting is currently keyed by IP address only, not per-tenant or per-API-key. This is a known limitation in v0.8.0.\n\n资料来源：[README.md:rate-limiting-limits]() (documentation of limitations)\n\n## Policy Engine\n\n### Policy Bundle Structure\n\nPolicy bundles are declarative YAML/JSON documents that define filtering rules. Each bundle is:\n\n- **Immutable**: Once created, content cannot be modified\n- **Content-addressed**: Identified by `bundle_hash` (SHA-256)\n- **Per-tenant**: Same bundle content can exist independently per tenant\n\n```yaml\n# Example policy bundle\nversion: 1\nrules:\n  - id: redact_sensitive\n    predicates:\n      - kind: label_match\n        args:\n          label: PII\n      - kind: caller_type\n        args:\n          type: external_agent\n    action: redact\n```\n\n### Predicate Types\n\n| Predicate | Description |\n|-----------|-------------|\n| `label_match` | Match memory by sensitivity label |\n| `caller_type` | Match by calling agent type |\n| `caller_id` | Match by specific caller identifier |\n\n### Actions\n\n| Action | Behavior |\n|--------|----------|\n| `deny` | Reject the memory from context |\n| `redact` | Remove sensitive content, keep metadata |\n\n### Policy Modes\n\n| Mode | Behavior |\n|------|----------|\n| `log_only` | Record decisions to receipts, no filtering applied |\n| `enforce` | Drop denied memories before ranking |\n\n资料来源：[server/db/tables.py:policy-bundle-row]() (database schema)\n\n## Receipts System\n\n### Receipt Emission Logic\n\nReceipts record policy decisions for audit and compliance. The emission decision follows a priority cascade:\n\n```mermaid\nflowchart TD\n    A[Receipt Request] --> B{Global Kill Switch?}\n    B -->|Enabled| E[Emit = False]\n    B -->|Disabled| C{Bundle Force Off?}\n    C -->|Yes| E\n    C -->|No| D{Tenant Mode?}\n    D -->|always| F[Emit = True]\n    D -->|never| E\n    D -->|on_request| G{Request Flag?}\n    G -->|True| F\n    G -->|False| E\n```\n\n### Kill Switch\n\nGlobal environment variable disables all receipt emission:\n\n```bash\nSTATEWAVE_RECEIPTS_DISABLED=true  # or \"1\", \"yes\"\n```\n\n### Receipt Data Model\n\n| Field | Description |\n|-------|-------------|\n| `id` | ULID identifier |\n| `tenant_id` | Associated tenant |\n| `policy_bundle_hash` | Hash of applied policy bundle |\n| `policy_mode` | Mode at time of decision |\n| `filters_applied` | List of applied filter rules |\n| `filters_skipped` | List of bypassed filter rules |\n| `caller_id` | Identity of requesting agent |\n| `caller_type` | Type of requesting agent |\n\n资料来源：[server/services/receipts.py:emission-decision]() (emission logic)\n\n## Multi-Tenant Data Isolation\n\n### Query-Scoped Isolation\n\nAll database queries include tenant_id in their WHERE clauses. This is enforced at the service layer:\n\n```python\n# Example isolation pattern\nquery = select(MemoryRow).where(\n    MemoryRow.tenant_id == tenant_id,\n    MemoryRow.subject_id == subject_id\n)\n```\n\n### Composite Unique Index\n\nPolicy bundles use a composite unique index to enforce:\n\n```sql\nUNIQUE (tenant_id, bundle_hash) NULLS NOT DISTINCT\n```\n\nThis allows multiple tenants to install identical policy content while maintaining row-level separation.\n\n资料来源：[server/db/tables.py:composite-index]() (index definition)\n\n## Security Best Practices\n\n### Recommended Configuration\n\nFor production deployments:\n\n```yaml\n# Kubernetes/Helm values\nauth:\n  apiKey: <use-external-secret>\n  \ndatabase:\n  url: <use-external-secret>\n  existingSecret: statewave-db\n  existingSecretKey: STATEWAVE_DATABASE_URL\n\n# Tenant configuration\npolicy_mode: enforce\nrequire_caller_identity: true\nreceipts: always\nreceipt_retention_days: 90\n```\n\n### Secret Management\n\nThe Helm chart supports two patterns:\n\n1. **Inline secrets**: Set via `--set` for development\n2. **External secrets**: Reference existing secrets (recommended for production)\n\n| Secret | Purpose |\n|--------|---------|\n| `statewave-db` | Database connection URL |\n| `statewave-llm` | LLM provider API key |\n| `statewave-auth` | API authentication key |\n\n资料来源：[helm/statewave/README.md:secret-management]() (Helm documentation)\n\n## Current Limitations\n\n| Feature | Status | Notes |\n|---------|--------|-------|\n| Rate limiting per-IP | ✅ Shipped | Distributed but IP-only |\n| Rate limiting per-tenant | 🔜 Planned | Not yet implemented |\n| Rate limiting per-API-key | 🔜 Planned | Not yet implemented |\n| Postgres RLS | 🔜 Planned | App-layer isolation only |\n| Multi-tenant policy bundles | ✅ v0.8 | Content-hashed, per-tenant |\n| Caller identity validation | ✅ v0.8 | Configurable per tenant |\n\n资料来源：[README.md:current-limitations]() (version 0.8.0 status)\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：smaramwbc/statewave\n\n摘要：发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1219923941 | https://github.com/smaramwbc/statewave | README/documentation is current enough for a first validation pass.\n\n## 2. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | last_activity_observed missing\n\n## 3. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n\n## 4. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n\n## 5. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | issue_or_pr_quality=unknown\n\n## 6. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | release_recency=unknown\n\n<!-- canonical_name: smaramwbc/statewave; human_manual_source: deepwiki_human_wiki -->\n",
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "Human Manual / 人类版说明书"
    },
    "pitfall_log": {
      "asset_id": "pitfall_log",
      "filename": "PITFALL_LOG.md",
      "markdown": "# Pitfall Log / 踩坑日志\n\n项目：smaramwbc/statewave\n\n摘要：发现 6 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1219923941 | https://github.com/smaramwbc/statewave | README/documentation is current enough for a first validation pass.\n\n## 2. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | last_activity_observed missing\n\n## 3. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n\n## 4. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1219923941 | https://github.com/smaramwbc/statewave | no_demo; severity=medium\n\n## 5. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | issue_or_pr_quality=unknown\n\n## 6. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1219923941 | https://github.com/smaramwbc/statewave | release_recency=unknown\n",
      "summary": "用户实践前最可能遇到的身份、安装、配置、运行和安全坑。",
      "title": "Pitfall Log / 踩坑日志"
    },
    "prompt_preview": {
      "asset_id": "prompt_preview",
      "filename": "PROMPT_PREVIEW.md",
      "markdown": "# statewave - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 statewave 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的软件开发与交付任务。\n我常用的宿主 AI：Local CLI\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: Open-source memory runtime for AI agents. Durable, structured context with provenance — so your AI stops forgetting across sessions. Self-hosted on Postgres. 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. page-overview：Overview - What is Statewave?。围绕“Overview - What is Statewave?”模拟一次用户任务，不展示安装或运行结果。\n2. page-getting-started：Getting Started。围绕“Getting Started”模拟一次用户任务，不展示安装或运行结果。\n3. page-architecture：System Architecture。围绕“System Architecture”模拟一次用户任务，不展示安装或运行结果。\n4. page-database-schema：Database Schema & Migrations。围绕“Database Schema & Migrations”模拟一次用户任务，不展示安装或运行结果。\n5. page-api-endpoints：API Endpoints Reference。围绕“API Endpoints Reference”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. page-overview\n输入：用户提供的“Overview - What is Statewave?”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. page-getting-started\n输入：用户提供的“Getting Started”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. page-architecture\n输入：用户提供的“System Architecture”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. page-database-schema\n输入：用户提供的“Database Schema & Migrations”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. page-api-endpoints\n输入：用户提供的“API Endpoints Reference”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / page-overview：Step 1 必须围绕“Overview - What is Statewave?”形成一个小中间产物，并等待用户确认。\n- Step 2 / page-getting-started：Step 2 必须围绕“Getting Started”形成一个小中间产物，并等待用户确认。\n- Step 3 / page-architecture：Step 3 必须围绕“System Architecture”形成一个小中间产物，并等待用户确认。\n- Step 4 / page-database-schema：Step 4 必须围绕“Database Schema & Migrations”形成一个小中间产物，并等待用户确认。\n- Step 5 / page-api-endpoints：Step 5 必须围绕“API Endpoints Reference”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/smaramwbc/statewave\n- https://github.com/smaramwbc/statewave#readme\n- README.md\n- server/domain/models.py\n- docker-compose.yml\n- alembic/env.py\n- server/app.py\n- server/main.py\n- server/services/__init__.py\n- server/core/dependencies.py\n- server/db/tables.py\n- alembic/versions\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 statewave 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "summary": "不安装项目也能感受能力节奏的安全试用 Prompt。",
      "title": "Prompt Preview / 安装前试用 Prompt"
    },
    "quick_start": {
      "asset_id": "quick_start",
      "filename": "QUICK_START.md",
      "markdown": "# Quick Start / 官方入口\n\n项目：smaramwbc/statewave\n\n## 官方安装入口\n\n### Python / pip · 官方安装入口\n\n```bash\npip install statewave\n```\n\n来源：https://github.com/smaramwbc/statewave#readme\n\n## 来源\n\n- repo: https://github.com/smaramwbc/statewave\n- docs: https://github.com/smaramwbc/statewave#readme\n",
      "summary": "从项目官方 README 或安装文档提取的开工入口。",
      "title": "Quick Start / 官方入口"
    }
  },
  "validation_id": "dval_710ffdadb42e4d4ca81c22901be11584"
}
