Potpie Context Engine 契约详解:单一发行版、上下文绑定的公共门面与显式宿主组合
【免费下载链接】potpieContext Graph for AI Native SDLC项目地址: https://gitcode.com/GitHub_Trending/po/potpie
导读
本文以 Potpie 仓库的规格变更记录 SPEC-CHANGE-0005 及其绑定的模块契约 Context Engine Contract 为核心,系统讲解 Context Engine 作为"可导入的上下文领域库"应具备的边界:一个发行版、一个绑定单一上下文身份的有限门面、显式宿主组合、类型化且传输中立的返回结果,以及明确的迁移终点。读完本文,你将掌握 CE-001 至 CE-034 这 34 条规范性要求的完整语义与分组逻辑,理解其背后的 ADR 决策脉络,并能结合potpie-context-engine源码定位每一类约束的实际实现。
一、契约要解决的问题:为什么需要一份"Context Engine 契约"
在引入本契约之前,Potpie 的产品布局存在三类结构性隐患:
- Context Core 与 Context Engine 拆分造成的公共边界混乱。Context Core 被独立发布,Context Engine 既依赖它,又暴露了一个混入产品关注点的宽泛 HostShell,导致"库的公共边界"难以理解,Potpie 宿主的职责容易伪装成引擎能力(见 ADR-0002)。
- 隐式环境发现、进程全局选择与按调用传上下文选择器。这让"引擎到底使用哪些资源、哪个身份"变得不可判定,也使多个隔离引擎无法在同一进程内安全共存(见 ADR-0003)。
- 引擎侧宿主接线与设置编排混入产品关注点。pot 选择、凭据、资源供给、安装、daemon 生命周期与领域服务纠缠在一起(见 ADR-0004)。
SPEC-CHANGE-0005 正是为回答这些问题而提出:建立唯一可导入的 Context Engine 发行版,以及一个上下文绑定的公共门面,配以显式宿主组合和传输中立的领域边界。它被标记为change_type: normative、change_status: accepted,于2026-08-20由user:dsantra接受,绑定 revision 1 作为目标契约。
二、核心意图与四个锚点
契约的 Intent 一句话可概括为:
Establish one importable Context Engine distribution and one context-bound public façade with explicit host composition and a transport-neutral domain boundary.
它由四个相互咬合的锚点构成:
| 锚点 | 含义 | 对应决策 |
|---|---|---|
| 一个可导入发行版 | 公共契约所需的类型与行为全部归属potpie-context-engine | ADR-0002 |
| 上下文绑定门面 | ContextEngine永久绑定一个不可变逻辑身份 | ADR-0003 |
| 显式宿主组合 | 身份、依赖、所有权模式由宿主在构造时显式提供 | ADR-0003 |
| 传输中立领域边界 | 操作返回类型化领域值或类型化错误,与传输层无关 | ADR-0005 |
该变更属于初始契约(from_revision: 0、to_revision: 1),不替换任何已接受契约,也不声明当前 HostShell 或包布局已符合该边界——这是后续迁移的目标态。
三、职责边界:Context Engine 拥有什么、排除什么
契约的 Ownership And Boundaries 用"拥有"与"排除"双向划定边界。
Context Engine 拥有:
- 上下文领域的操作、值、错误与不变量;
- 公共门面背后聚焦的领域模块;
- 已声明的引擎所有端口(engine-owned ports)及这些端口的包内适配器;
- 引擎内部状态以及显式转移给它的依赖;
- 适合直接使用或宿主使用的传输中立引擎结果。
它明确排除:
- Potpie 选择(selection);
- 调用者安全策略;
- 宿主资源供给(provisioning);
- daemon 行为;
- CLI 展示;
- 安装与产品生命周期。
这一"拥有/排除"结构直接落实为 CE-011(领域语义唯一所有者)、CE-013(禁止终端展示)、CE-014(禁止认证与产品授权)、CE-015(禁止隐式资源发现与供给)。对应实现可见 context_engine.py 中门面只依赖EngineDependencies中显式注入的操作组,而 pyproject.toml 的基础依赖仅声明pydantic>=2.0,交付面与存储后端全部放在 extras 之后,保证"导入即轻量"。
3.1 参与者模型
契约定义了四种参与方(详见模块契约的 Actors And Permissions 表):
| 参与者 | 交互方式 |
|---|---|
| Compatible host(兼容宿主) | 提供上下文身份、依赖、所有权模式与允许调用的操作集合 |
| Potpie Resource Manager | 作为 Potpie 宿主,组合或获取放入授权上下文租约(authorized context lease)中的引擎 |
| Domain caller(领域调用方) | 在宿主授权后,对门面调用有限的操作 |
| Context Engine | 为绑定的身份强制实施领域不变量 |
关键设计在于:Context Engine 信任宿主建立调用者身份与权限,但自身仍会校验领域输入,并保持其不可变的上下文身份。也就是说,安全边界在宿主,领域正确性在引擎。
四、34 条规范性要求的完整解读(CE-001 ~ CE-034)
模块契约 context-engine.md 是这些行为的权威定义。SPEC-CHANGE-0005 的行为操作表(Behavior Operations)以add操作一次性建立了 CE-001 至 CE-034 共 34 条行为。按主题可将它们归为十组,便于记忆与实施。
4.1 单一发行版与有限门面(CE-001 ~ CE-004)
- CE-001:Context Engine 必须把
ContextEngine暴露为有限、薄的公共门面,显式命名的方法即上下文领域操作。 - CE-002:兼容宿主必须能在不导入 Potpie daemon 或 CLI 内部实现的前提下使用该门面。
- CE-003:公共契约所需的类型与行为必须归属唯一的
potpie-context-engine发行版。 - CE-004:迁移终点不得保留
potpie-context-core作为独立的架构或公共发行边界。
源码印证:当前仓库已不存在potpie/context-core目录,conformance 记录 也明确记录"Context Core remains absent"(CE-004 passed);发行版名称potpie-context-engine定义于 pyproject.toml 的[project] name字段。公共门面导出集中在 api.py,而potpie_context_engine包自身(__init__.py)只导出工厂、生命周期、outcomes 与默认图定义,保持依赖轻量。
4.2 上下文身份绑定与实例隔离(CE-005 ~ CE-009)
- CE-005:宿主必须在构造时显式提供上下文身份、每个必需依赖,以及每个携带资源依赖的所有权模式。
- CE-006:一个引擎实例在其整个生命周期内永久绑定恰好一个逻辑上下文身份。
- CE-007:引擎操作不得接受覆盖实例绑定身份的第二选择器。
- CE-008:宿主需要不同身份时,必须构造或获取另一个引擎实例。
- CE-009:不同身份的实例必须能无进程全局上下文状态地共存。
源码印证:ContextIdentity是冻结数据类,只含value字段且构造时校验非空(context_engine.py);ContextEngine.__init__仅接受context、config、dependencies三个关键字参数,构造后context属性只读。请求模型层面,契约要求操作请求不接受上下文选择器,conformance 记录中 CE-007 的验证结果为"Request models reject context selectors"。
4.3 依赖所有权与生命周期(CE-010、CE-022 ~ CE-025、CE-032)
这是"显式组合"原则在资源管理上的落点:
- CE-010:引擎所有资源的清理必须可安全重复请求,且不产生重复的破坏性效果。
- CE-022:宿主提供的资源型依赖默认视为借用(borrowed),除非类型化构造契约显式转移所有权。
- CE-023:引擎不得关闭或释放借用依赖。
- CE-024:对于转移(transferred)或引擎创建的依赖,引擎关闭时必须按声明的生命周期释放。
- CE-025:终态关闭后尝试操作必须返回
EngineLifecycleError。 - CE-032:失败的构造不得产出可用引擎实例。
源码印证(均为 context_engine.py 的真实行为):
ResourceOwnership = Literal["borrowed", "transferred"],EngineResource冻结数据类在ownership == "transferred"且缺少close回调时直接抛ValueError(CE-032 的构造期校验);ContextEngine.close()用_close_lock保证并发安全,已关闭且无待清理资源时幂等返回Success(None);清理失败会保留在_pending_close_resources中并在下次 close 重试,返回retry_posture="safe"的EngineLifecycleError(CE-010);close()只遍历ownership == "transferred"的资源(CE-023),且按reversed(dependencies.resources)逆序关闭(CE-024 的"按序释放");_invoke()在操作执行前检查_closed,关闭后直接返回engine_closed的EngineLifecycleError(CE-025);close()会先置_closed = True并等待_active_operations == 0,实现"排水后释放资源";create_engine()是唯一的公开构造入口(异步函数),构造前校验五个必需操作组是否缺失,缺失则返回Failure(CE-032)。
4.4 领域所有权与类型化结果(CE-011、CE-012、CE-028 ~ CE-031)
- CE-011:Context Engine 必须是本系统中上下文领域语义与不变量的唯一所有者。
- CE-012:每个操作必须返回类型化、传输中立的领域值,或类型化的
DomainError/DependencyError/EngineLifecycleError。 - CE-028:公共操作请求、结果与错误必须使用引擎所有类型,而非 Potpie 选择记录、daemon 协议 DTO 或 CLI 展示类型。
- CE-029:上下文领域语义失败必须返回
DomainError。 - CE-030:履行声明的引擎所有端口时的依赖失败必须返回
DependencyError。 - CE-031:引擎错误与可观测性输出默认排除秘密。
源码印证:outcomes 定义于 outcomes.py,三类错误均为冻结数据类,带code、message、details、recommended_next_action、retry_posture与category字面量字段("domain"/"dependency"/"engine_lifecycle");Success[T]/Failure[E]构成Outcome联合类型。_invoke()把依赖抛出的任意异常统一包装为engine_dependency_failed的DependencyError,把领域语义拒绝留给领域模块返回DomainError——这正是 CE-029 与 CE-030 的执行点。
4.5 边界排除:终端、认证、资源供给与产品关注点(CE-013 ~ CE-015、CE-026)
- CE-013:引擎不得提示、打印、渲染终端展示,或选择进程退出码。
- CE-014:引擎不得认证调用者或强制 Potpie 产品授权策略。
- CE-015:引擎不得静默发现或供给宿主管理的资源。
- CE-026:包内适配器不得实现或依赖 Potpie 的选择、产品授权、资源供给、安装、daemon、CLI 或产品生命周期模块。
这四条共同保证引擎可作为纯库被任意兼容宿主复用。conformance 记录的 CE2-E4 引用了反向导入门禁测试(test_cli_package_boundary.py、test_potpie_capability_ownership.py)来验证"引擎生产代码不导入根potpie命名空间"。
4.6 适配器约束:只实现引擎所有端口,由宿主显式选择(CE-016、CE-033)
- CE-016:包内适配器只能实现已声明的引擎所有端口。
- CE-033:包内适配器必须由宿主显式选择与组合。
组合示例见 composition.py 的build_graph_service():它接受GraphBackend、GraphDefinition、GraphMutationPolicy与可选的ReconciliationConfig,全部由调用方显式传入(后端选择在宿主侧),并支持从环境读取 reconcile 配置(reconciliation_config_from_env)作为显式策略的一部分。
4.7 破坏性操作:显式、非默认(CE-017、CE-034)
- CE-017:破坏性操作必须表示为显式的破坏性领域命令。
- CE-034:破坏性操作不得通过默认或推断操作触达。
在门面方法中,破坏性语义(如reset_context)是独立命名的方法,位于 context_engine.py,调用方必须显式构造ResetContextRequest并显式调用,不存在"默认即破坏"的推断路径。这与 ADR-0005 中"CLI 的人类确认成为不受信任的类型化断言,由 Resource Manager 验证后再调用显式破坏性领域命令"的产品级安全链相衔接。
4.8 延期范围:插件与解析(CE-018、CE-019)
- CE-018:本修订不得暴露公共插件、扩展注册或清单契约。
- CE-019:本边界下的工作不得重新设计解析行为。
这是 ADR-0006 的直接体现:第一份迁移提交只绑定稳定的所有权边界,插件体系、外部宿主传输协议、精确方法编组、同步/异步暴露等全部显式延期。potpie_context_engine包的公开导出(__init__.py)中不存在任何扩展注册入口,印证 CE-018。
4.9 门面形态:拒绝服务定位器与万能宿主(CE-020、CE-021)
- CE-020:门面不得暴露动态分发、任意服务查找、服务容器图,或内部服务的透传镜像。
- CE-021:门面必须委托给聚焦的上下文领域模块,而不是累积成万能宿主或服务实现。
源码印证:ContextEngine内部只有_invoke()一个统一执行通道,将每个显式命名的方法委托给EngineDependencies中对应的操作组(context/graph/workbench/ingestion/nudge五个Protocol),没有任何反射、服务定位器或容器图。EngineDependencies的每个字段类型均为具名Protocol(如GraphOperations、WorkbenchOperations),方法签名固定,天然阻止动态分发。
4.10 迁移终点:移除而非重命名 HostShell(CE-027)
- CE-027:Context Engine 边界迁移完成时,必须移除HostShell 与 Potpie 所有的宿主接线,而不是在
ContextEngine后面保留或重命名它们。
契约在 CE-027 中引用的迁移证据路径为potpie/context-engine/src/potpie_context_engine/host/shell.py与potpie/context-engine/src/potpie_context_engine/bootstrap/host_wiring.py。从当前仓库目录结构看,potpie_context_engine下只有adapters/application/benchmarks/bootstrap/core/domain/testing,已不存在host/目录——可以推断 HostShell 相关文件已被移除而非改名,与契约要求的迁移方向一致。这也与 conformance 记录中 CE-027"HostShell and engine-owned root wiring remain absent"的验证结论吻合。
五、生命周期状态机:construction → usable → closing → closed
模块契约用一段状态草图总结了 CE-010、CE-023、CE-024、CE-025 与 CE-032:
construction -> usable -> closing -> closed | -> construction failure, with no usable instance- construction:
create_engine()校验显式组合;任一必需操作组缺失即返回Failure,不产出可用实例(CE-032)。 - usable:
ContextEngine可执行有限操作;操作前检查_closed,借用依赖可被使用但不会被关闭。 - closing:
close()置_closed = True、等待活跃操作归零(排水),然后逆序关闭 transferred 资源;失败的资源保留待重试,close 可安全重复调用(CE-010)。 - closed:任何操作返回
engine_closed的EngineLifecycleError(CE-025)。
特别注意:改变上下文身份不是生命周期转换。身份在构造时绑定,之后不可重定向(CE-006/CE-007)。
六、类型化结果模型(Outcome Summary)
模块契约的结果汇总表是全契约最实用的速查表,原文完整如下:
| 条件 | 类型化结果 |
|---|---|
| 领域输入、状态、能力或不变量拒绝操作 | DomainError |
| 引擎所有端口在正常操作期间失败 | DependencyError |
| 终态关闭后尝试操作 | EngineLifecycleError |
| Potpie 选择、认证、授权、资源、协议或展示失败 | 不由 Context Engine 产生 |
该表概括了 CE-012、CE-025、CE-029 与 CE-030。最后一行尤其关键:它把"引擎边界之外"的错误类型明确划给宿主侧。配套的 glossary(SPEC-GLOSSARY)进一步规定十类错误必须保持互异——SelectionError、AuthenticationError、AuthorizationError、ResourceLifecycleError、DomainError、DependencyError、EngineLifecycleError、ProtocolTransportError、DaemonInternalError、PresentationError——其中前三类与ResourceLifecycleError属于 Potpie 边界,中间三类属于 Context Engine 边界。
在 outcomes.py 中,Outcome被定义为Success[T] | Failure[EngineError]联合类型,EngineError = DomainError | DependencyError | EngineLifecycleError,与契约的三类引擎错误严格一一对应。
七、对宿主系统的计算影响(Computed Impact Review)
SPEC-CHANGE-0005 还明确了三个关联契约的必改项(摘自文档的 Computed Impact Review 表):
| 关联契约 | 要求的变化 | 评审方 |
|---|---|---|
| SPEC-POTPIE-RESOURCE-MANAGER | 负责显式引擎组合与宿主资源生命周期 | agent:codex |
| SPEC-DAEMON | 类型化上下文域处理器在调用显式引擎操作前,必须先获取授权上下文租约 | agent:codex |
| SPEC-CLI | 托管路径避免直接构造引擎 | agent:codex |
也就是说,引擎构造从 CLI 与 daemon 侧上移到 Potpie Resource Manager:Resource Manager 解析选择、应用授权、获取宿主资源、构造或复用上下文绑定引擎,并返回带显式所有权与释放语义的授权上下文租约。这正对应 ADR-0004 的决策——Resource Manager 是"职责"而非某个强制类或包。
同时文档的 Compatibility, Security, And Failure Impact 指出:该边界在保持直接库可用性的同时,把产品认证、选择、安装、供给、进程与展示关注点外移;要求显式依赖所有权并移除 HostShell 而非改名;精确的兼容性垫片(compatibility shims)仍被延期。
八、验证、一致性记录与实现状态
SPEC-CHANGE-0005 的 Validation 区块记录了结构、语义、权威/溯源、依赖/一致性四类评审全部通过,并注明"Current implementation characterization: passed(11 tests;非目标一致性)"与"Implementation conformance: unclaimed"——即该变更本身只绑定目标契约,不声称当前实现已符合。
后续的 Context Engine Conformance Record 则提供了实现侧的最终验证:在选定实现 ref 上,CE-001 至 CE-034 全部标记complete且验证结果为passed,其中:
- CE2-E1:对
potpie/context-engine/src/potpie_context_engine下的公共门面、组合、请求、结果与导出做固定源码评审; - CE2-E2:在
potpie/context-engine下运行uv run --project . pytest tests -m "not premerge_journey",结果为1153 passed, 32 skipped(32 个跳过项依赖外部集成服务); - CE2-E3:构建根包与 Context Engine 的 wheel/sdist,将引擎 wheel 装入全新环境后,成功导入公共包与
ContextEngine,同时find_spec("potpie")返回None——证明引擎发行版完全独立于根potpie命名空间(CE-002/CE-026 的强证据); - CE2-E4:反向导入门禁(test_cli_package_boundary.py、test_potpie_capability_ownership.py)所在的特征化测试车道报告
31 passed。
九、发行版边界与安装视角
从使用者视角,契约的"单一发行版"体现在 pyproject.toml:
[project] name = "potpie-context-engine" version = "0.2.0" requires-python = ">=3.12,<3.15" dependencies = ["pydantic>=2.0"]基础依赖只有pydantic,保证公共 API 面导入轻量;存储后端与交付面全部作为 extras 提供:
local:FalkorDB / FalkorDBLite 本地图后端(Python 3.12+ 默认 FalkorDBLite),并带hiredis加速 RESP 解析;http:FastAPI / httpx / uvicorn 交付面;neo4j、postgres:可选图/关系后端;embeddings、github、reconciliation-agent、hatchet、observability:能力扩展;all:本地 potpie 体验所需的完整集合(不含基准测试与开发工具)。
这从包结构上落实了 CE-003(公共类型与行为归属单一发行版)与"交付面与存储后端延迟加载"的设计意图:引擎核心不因某个后端而变重。
十、迁移路径与验收标准
模块契约的 Compatibility, Migration, And Rollout 明确:后续提交将把 Context Core 所需类型并入 Context Engine,并移除 Potpie 所有的组合代码;临时导入垫片只能作为迁移机制存在,不构成最终边界。
验收标准(Acceptance Criteria)原文要点:
- 公共门面不能变成服务定位器或改名后的 HostShell;
- 一个实例不能被重定向;
- 借用与转移所有权不能混淆;
- 包内适配器只能实现引擎所有端口;
- 引擎结果保持类型化且传输中立;
- 产品认证、供给、daemon 与展示保持在发行版之外。
模块契约的 Implementation Notes 也特别提醒:当前的 HostShell、宿主接线、独立的 Context Core 包、CLI 认证、安装器、设置与技能相关端口,都是迁移证据而非目标架构——"这些说明不产生任何一致性声明"。
结语
SPEC-CHANGE-0005 是一次典型的"先定边界、再谈实现"的架构治理:用 34 条规范性要求把一个原本混入产品关注点的运行时,收敛为"单一发行版 + 上下文绑定门面 + 显式宿主组合 + 类型化传输中立结果"的可导入库,并为其定义了移除 HostShell、废弃 Context Core 的迁移终点。对库的集成者而言,它意味着清晰的构造契约(create_engine+ContextIdentity+EngineConfig+EngineDependencies)与可预期的三类错误;对 Potpie 产品侧而言,它把选择、授权、资源供给与展示责任明确交给 Resource Manager、daemon 与 CLI。当前仓库的 conformance 记录已证明这 34 条行为在实现侧全部落地,是理解 Potpie 上下文图架构的最佳起点。
【免费下载链接】potpieContext Graph for AI Native SDLC项目地址: https://gitcode.com/GitHub_Trending/po/potpie
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考