diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json
index 706b1e7..60c8949 100644
--- a/.codex-plugin/plugin.json
+++ b/.codex-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "2718lab-devkit",
- "version": "1.1.3",
+ "version": "1.1.4",
"description": "Local MCP server for developer workflow coordination, indexing, and evidence handling.",
"author": {
"name": "2718lab",
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index b4e8d9f..a94ae82 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -28,7 +28,7 @@ body:
id: version
attributes:
label: DevKit version
- placeholder: "v1.1.3"
+ placeholder: "v1.1.4"
validations:
required: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84801d9..ccf7473 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,31 @@ only after the CI and artifact checks pass.
## [Unreleased]
+## [1.1.4] - 2026-09-04
+
+### Added
+
+- Added a hostless, compile-only MCP Fast Lane planning path. Caller-supplied
+ workspace and snapshot identifiers remain selectors: a read-only local
+ RuntimeRoot resolves the registered workspace, requires the exact current
+ `INDEX_READY` snapshot and Git binding, and emits a bounded, exact-key
+ `team-efficiency/fast-lane-plan-v2` descriptor.
+
+### Fixed
+
+- Normalize the no-null public plan before calculating assignment and plan
+ identities, so `plan_item_id` and `plan_hash` can be recomputed exactly from
+ inactive plans and read-only as well as writer assignments.
+- Fail closed with the snapshot's precise stable error whenever local planning
+ observes any Project Index state other than `INDEX_READY`.
+
+### Security
+
+- Plan-v2 is planning data only: it fixes `plan_only=true`,
+ `dispatch_state="not_dispatched"`, and `execution_authorized=false`. It does
+ not spawn an agent, claim a lease, create a worktree, mutate Git, or dispatch
+ work; those actions remain outside the compiler contract.
+
## [1.1.3] - 2026-09-01
### Added
diff --git a/README.md b/README.md
index af285d6..66888db 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,26 @@
[简体中文](README.zh-CN.md)
-# 2718lab DevKit — Codex + MCP v1.1.3
+# 2718lab DevKit — Codex + MCP v1.1.4
-[](./.codex-plugin/plugin.json)
+[](./.codex-plugin/plugin.json)
[](LICENSE)
2718lab DevKit is a Codex-first engineering toolkit: a local, stdio-only MCP
runtime for bounded project indexing, Atlas evidence, Relay lifecycle
coordination, and deterministic Fast Lane planning, plus a compact Skill bundle
-of reference manuals. This repository carries the versioned v1.1.3 package.
+of reference manuals. This repository carries the versioned v1.1.4 package.
The checked-in manifest and allowlist define the executable runtime surface;
the manual map, install, build, and verification sections below describe the
supported workflow.
-The current release retains a deliberately fail-closed Fast Lane preview. The public compiler
-and CLI return `NO_SAFE_WORK` with zero assignments: they do not consume host
-status or live-account inputs, and have no worktree execution path. Host
-execution remains an external Desktop-host bridge requirement.
+The public Python compiler and CLI retain the deliberately fail-closed
+`team-efficiency/fast-lane-plan-v1` preview. The MCP `fastlane_compile` tool
+instead resolves caller-supplied workspace/snapshot selectors through its local
+RuntimeRoot and returns a verified `team-efficiency/fast-lane-plan-v2` planning
+descriptor. That descriptor is `plan_only`: it never dispatches, claims a
+lease, creates a worktree, or authorizes execution.
-For storage-governed execution, v1.1.3 references compatible Host source only
+The prior v1.1.3 storage-governance integration references compatible Host source only
on Ayleovelle's user-fork
[`codex/host-1.1.3-storage-governance-upstream`](https://github.com/Ayleovelle/codex/tree/codex/host-1.1.3-storage-governance-upstream)
branch, pinned to immutable commit
@@ -59,12 +61,12 @@ and continue to fail closed.
- The optional Codex Skill bundle is part of DevKit's documentation surface. It
provides short, module-specific manuals without becoming a second runtime or
an executable prompt/agent surface.
-- Fast Lane is a pure MCP runtime compiler. Its public surface is presently
- authority-inert and fail-closed: it emits no assignments and never spawns
- agents, edits Git, runs commands, or executes worktrees. Host execution is
- reserved for a future external Desktop-host bridge contract. The RuntimeRoot
- host-private V2/V3 bootstrap path is covered with injected test doubles only;
- no external host embedding or operational/host-integrated GO is claimed.
+- Fast Lane is a pure planning compiler. The MCP tool can emit bounded
+ `team-efficiency/fast-lane-plan-v2` assignments only after its private
+ RuntimeRoot verifies a registered `INDEX_READY` snapshot, Git HEAD, and full
+ write-scope coverage. Every result remains `plan_only`; no agent, Git command,
+ lease, or worktree action is executed. The public Python compiler/CLI remains
+ the authority-inert plan-v1 diagnostic surface.
## Module overview
@@ -82,11 +84,11 @@ and continue to fail closed.
## Overall workflow
The repository workflow defaults to Fast Lane. `workflow-design` prepares a
-bounded input; `fastlane_compile` or `team_efficiency.py` then returns an
-authority-inert, fail-closed plan. `fast-lane-routing` documents the intended
-future host-consumption boundary; neither a skill nor the current compiler
-starts agents or creates/executes cross-session worktrees. The current path is
-to inspect the blocked plan and retain authority outside this repository.
+bounded input. MCP `fastlane_compile` verifies the persisted local project
+snapshot and returns a plan-v2 descriptor; `team_efficiency.py` retains the
+blocked plan-v1 diagnostic path. Neither path starts agents or creates/executes
+cross-session worktrees. A coordinator must separately validate route
+availability, claim a lease, and dispatch any selected work.
```mermaid
flowchart TD
@@ -95,9 +97,9 @@ flowchart TD
C["mcp-tools/server.py
stdio entry"] --> D["Project Index / Checkpoint
Atlas / Relay"] --> E["Bounded result
host action"]
end
subgraph FAST["Fast Lane"]
- F["fast-lane request"] --> G["team_efficiency.py
public compiler"]
- G --> X["Fail closed
NO_SAFE_WORK, zero assignments"]
- H["Future external Desktop-host bridge
contract only"] -. "not shipped or invoked" .-> G
+ F["fast-lane request"] --> G["MCP fastlane_compile
private RuntimeRoot verification"]
+ G --> X["plan-v2
plan_only, not dispatched"]
+ F --> H["public Python / CLI"] --> I["plan-v1
NO_SAFE_WORK"]
end
B -->|MCP tools| C
B -->|Fast Lane| F
@@ -177,7 +179,7 @@ source of record remains `main` and immutable release tags.
Maintainers build that snapshot with the dedicated marketplace allowlist:
- python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output /2718lab-devkit-marketplace-v1.1.3.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output /2718lab-devkit-marketplace-v1.1.4.zip
## Install and run locally
@@ -224,7 +226,7 @@ handles or falls back to an unrelated local start.
The allowlisted builder creates a deterministic ZIP outside the plugin source
tree. Choose an output directory outside the source tree:
- python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.3.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.4.zip
The artifact contains the manifest, .mcp.json, LICENSE, the locked Python
project, and the runtime files selected by
@@ -334,24 +336,27 @@ cleanup target.
The Fast Lane compiler is in
mcp-tools/devkit_fastlane/scripts/fastlane_routing.py and
-mcp-tools/devkit_fastlane/scripts/team_efficiency.py. The public MCP entry is
-`fastlane_compile`; every current invocation is deliberately blocked with
-`NO_SAFE_WORK` and zero assignments unless the request is the closed
-`fastlane-host-dispatch-request-v1` shape and this MCP process owns an
-authenticated inherited host bridge. In that private case the host supplies
-one-time registry-bound compiler evidence and receives a typed dispatch batch.
+mcp-tools/devkit_fastlane/scripts/team_efficiency.py. The MCP `fastlane_compile`
+entry returns `team-efficiency/fast-lane-plan-v2` only after a read-only
+RuntimeRoot unit of work resolves the registered workspace and snapshot. The
+snapshot must be current, `INDEX_READY`, bound to the repository Git HEAD, and
+its persisted `include_paths` must fully cover every writer `write_scope`.
- `reasoning_effort` is required and accepts only `low`, `medium`, `high`,
- `xhigh`, or `max`; worker dispatch never accepts `ultra`.
-- The public compiler/CLI does not consume host status, account usage, index
- evidence, or a worktree root.
-- The compiler never creates a worktree, selects a route, or runs a command.
- The authenticated session ACKs terminal slots and requests refill only at the
- next host boundary. The compiler can only commit the fully hash-bound batch to the private
- host bridge; the host remains the execution authority.
-- Missing, stale, mismatched, replayed, or caller-supplied evidence keeps the
- result at `NO_SAFE_WORK`. Filesystem paths are never accepted as compiler
- evidence.
+ `xhigh`, or `max`; the MCP output never dispatches a worker.
+- `team-efficiency/fast-lane-plan-v2` fixes `plan_only=true`,
+ `dispatch_state="not_dispatched"`, and `execution_authorized=false`.
+ Assignments use `team-efficiency/local-writer-plan-v1`; path-free
+ `index_evidence` includes snapshot/binding hashes, `include_paths_hash`, and
+ the compiled `scope_hash`.
+- `INDEX_STALE` rejects filesystem or Git drift. `INDEX_PARTIAL` rejects either
+ a partial snapshot or any snapshot whose include roots omit a writer scope.
+- Caller IDs are selectors, not authority material. The public MCP request and
+ public `compile_fast_lane` Python API accept no local index root, Git HEAD, or
+ private planning material.
+- The public Python compiler/CLI still does not consume host status, account
+ usage, index evidence, or a worktree root and remains the blocked plan-v1
+ diagnostic boundary.
### Account-usage boundary
@@ -390,7 +395,7 @@ freeze a transient regression count.
## Version
-This repository represents the versioned v1.1.3 package. Release notes are
+This repository represents the versioned v1.1.4 package. Release notes are
in [CHANGELOG.md](CHANGELOG.md); build and install from the checked-in manifest,
artifact allowlist, and locked dependency set. A maintainer dispatches Release
from current `main`; it validates all declared gates, creates the annotated tag,
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 5f2d4e5..be8c255 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -1,21 +1,23 @@
[English](README.md)
-# 2718lab DevKit —— Codex + MCP v1.1.3
+# 2718lab DevKit —— Codex + MCP v1.1.4
-[](./.codex-plugin/plugin.json)
+[](./.codex-plugin/plugin.json)
[](LICENSE)
2718lab DevKit 是一个 Codex-first 工程工具包:它包含一个本地、仅 stdio
传输的 MCP 运行时,用于有边界的项目索引、Atlas 证据、Relay 生命周期协调和
确定性的 Fast Lane 规划;同时还包含一组精简的 Skill 说明书。本仓库承载版本化的
-v1.1.3 包;已提交的 manifest 和 allowlist 定义可执行运行时范围,说明书导航、
+v1.1.4 包;已提交的 manifest 和 allowlist 定义可执行运行时范围,说明书导航、
安装、构建和验证章节共同给出支持的工作流。
-当前版本保留刻意 fail-closed 的 Fast Lane 预览。公共编译器和 CLI 固定返回
-`NO_SAFE_WORK` 与零 assignments:不会消费 host-status 或实时账号输入,也没有
-worktree 执行路径。宿主执行属于未来外部 Desktop-host bridge 合同的要求。
+公共 Python 编译器和 CLI 继续保留刻意 fail-closed 的
+`team-efficiency/fast-lane-plan-v1` 预览。MCP `fastlane_compile` 则通过本地
+RuntimeRoot 解析 caller 提供的 workspace/snapshot selector,并返回已验证的
+`team-efficiency/fast-lane-plan-v2` 规划描述符。该描述符固定为 `plan_only`:不会
+派发、领取 lease、创建 worktree 或授权执行。
-对于受存储治理的执行,v1.1.3 只引用 Ayleovelle 用户 fork 上的兼容 Host 源码:
+此前 v1.1.3 的存储治理集成只引用 Ayleovelle 用户 fork 上的兼容 Host 源码:
[`codex/host-1.1.3-storage-governance-upstream`](https://github.com/Ayleovelle/codex/tree/codex/host-1.1.3-storage-governance-upstream)
分支,固定到不可变提交
[`c3dde23bec21c45d10740f2eec09d9a1b87cd329`](https://github.com/Ayleovelle/codex/commit/c3dde23bec21c45d10740f2eec09d9a1b87cd329)。
@@ -45,11 +47,11 @@ stock Codex Host 没有经过证明的 protected broker,继续 fail-closed。
静态 prompt agent 或模型运行器。
- 可选的 Codex Skill bundle 是 DevKit 的说明书表面,提供简短的模块化手册;
它不构成第二个运行时,也不是可执行的 prompt/agent 表面。
-- Fast Lane 是 MCP runtime 中的纯本地编译器。其公共面当前没有调度权限并且
- fail-closed:不会产生 assignment,也不会 spawn agent、修改 Git、运行命令或
- 执行 worktree。宿主执行预留给未来的外部 Desktop-host bridge 合同。
- RuntimeRoot 的 host-private V2/V3 bootstrap 仅由注入的测试替身覆盖;
- 没有 external host embedding 实证,也不声称 operational/host-integrated GO。
+- Fast Lane 是纯规划编译器。只有 server 私有 RuntimeRoot 验证已注册的
+ `INDEX_READY` snapshot、Git HEAD 和完整 writer scope 覆盖后,MCP 工具才会
+ 产出有界的 `team-efficiency/fast-lane-plan-v2` assignments。所有结果仍为
+ `plan_only`,不执行 agent、Git 命令、lease 或 worktree 动作。公共 Python
+ 编译器/CLI 继续作为无 authority 的 plan-v1 诊断面。
## 核心模块速览
@@ -66,11 +68,11 @@ stock Codex Host 没有经过证明的 protected broker,继续 fail-closed。
## 整体工作流
-仓库级默认工作流是 Fast Lane。`workflow-design` 准备有界输入;
-`fastlane_compile` 或 `team_efficiency.py` 随后只返回无权限、fail-closed 的计划。
-`fast-lane-routing` 记录的是预期的未来宿主消费边界;skill 和当前编译器均不会
-启动 agent,也不会创建或执行跨会话工作树。当前路径只用于检查被阻断的计划,
-权限仍保留在本仓库之外。
+仓库级默认工作流是 Fast Lane。`workflow-design` 准备有界输入;MCP
+`fastlane_compile` 验证持久化本地项目 snapshot 后返回 plan-v2 描述符,
+`team_efficiency.py` 则保留被阻断的 plan-v1 诊断路径。两条路径都不会启动 agent,
+也不会创建或执行跨会话工作树。协调器必须另行验证 route availability、领取 lease
+并派发所选工作。
```mermaid
flowchart TD
@@ -79,9 +81,9 @@ flowchart TD
C["mcp-tools/server.py
stdio 入口"] --> D["Project Index / Checkpoint
Atlas / Relay"] --> E["有界结果
宿主动作"]
end
subgraph FAST["Fast Lane"]
- F["fast-lane request"] --> G["team_efficiency.py
公共编译器"]
- G --> X["失败关闭
NO_SAFE_WORK,零 assignments"]
- H["未来外部 Desktop-host bridge
仅合同"] -. "未交付或调用" .-> G
+ F["fast-lane request"] --> G["MCP fastlane_compile
私有 RuntimeRoot 验证"]
+ G --> X["plan-v2
plan_only,未派发"]
+ F --> H["公共 Python / CLI"] --> I["plan-v1
NO_SAFE_WORK"]
end
B -->|MCP 工具| C
B -->|Fast Lane| F
@@ -155,7 +157,7 @@ Fast Lane 不含额度协调器合同;公共编译器和 CLI 不读取、协
维护者使用专用的 marketplace allowlist 构建该快照:
- python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output /2718lab-devkit-marketplace-v1.1.3.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output /2718lab-devkit-marketplace-v1.1.4.zip
## 本地安装与运行
@@ -195,7 +197,7 @@ RELAY_CAPABILITY_BROKER_UNAVAILABLE。服务器不会暴露原始 handle,也
allowlist builder 会在插件源码树之外生成确定性的 ZIP。请选择源码树之外的输出目录:
- python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.3.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.4.zip
产物包含 manifest、.mcp.json、LICENSE、锁定的 Python 项目,以及
.codex-plugin/main-artifact-allowlist.json 选中的运行时文件。它的可执行运行时
@@ -289,20 +291,24 @@ embedding 或本地路径放宽的证据。
Fast Lane 编译器位于
mcp-tools/devkit_fastlane/scripts/fastlane_routing.py 和
-mcp-tools/devkit_fastlane/scripts/team_efficiency.py。公共 MCP 入口为
-`fastlane_compile`;当前每一次调用都会刻意以 `NO_SAFE_WORK` 和零 assignments
-被阻断;唯一例外是 exact-key 的 `fastlane-host-dispatch-request-v1`,且当前 MCP
-进程确实持有经过认证的 inherited host bridge。此时宿主通过一次性、registry-bound
-的 compiler evidence 回传精确事实,并接收 typed dispatch batch。
+mcp-tools/devkit_fastlane/scripts/team_efficiency.py。MCP `fastlane_compile` 只有在
+只读 RuntimeRoot UoW 解析已注册 workspace/snapshot 后才返回
+`team-efficiency/fast-lane-plan-v2`。snapshot 必须 current、处于 `INDEX_READY`、
+绑定仓库 Git HEAD,且持久化 `include_paths` 完整覆盖每个 writer `write_scope`。
- `reasoning_effort` 必填且只接受 `low`、`medium`、`high`、`xhigh` 或
- `max`;worker 调度永不接受 `ultra`。
-- 公共编译器/CLI 不消费 host-status、账号用量、index evidence 或 worktree root。
-- 编译器不会创建 worktree、选择路由或运行命令;认证 session 只在 terminal ACK
- 后请求下一宿主边界补位。编译器只能把完整 hash-bound batch 提交给私有宿主桥,
- 真正执行权限仍属于宿主。
-- evidence 缺失、过期、错配、重放或来自 caller 自报时仍保持 `NO_SAFE_WORK`;
- filesystem path 永远不能充当 compiler evidence。
+ `max`;MCP 输出永不派发 worker。
+- `team-efficiency/fast-lane-plan-v2` 固定 `plan_only=true`、
+ `dispatch_state="not_dispatched"`、`execution_authorized=false`。
+ assignment 使用 `team-efficiency/local-writer-plan-v1`;无路径的
+ `index_evidence` 包含 snapshot/binding hashes、`include_paths_hash` 与已编译
+ `scope_hash`。
+- filesystem 或 Git 漂移返回 `INDEX_STALE`;snapshot 本身 partial,或其 include
+ roots 遗漏任一 writer scope,均返回 `INDEX_PARTIAL`。
+- caller ID 只是 selector,不是 authority material。公共 MCP request 与公共
+ `compile_fast_lane` Python API 均不接受本地 index root、Git HEAD 或私有规划材料。
+- 公共 Python 编译器/CLI 仍不消费 host-status、账号用量、index evidence 或
+ worktree root,并继续作为被阻断的 plan-v1 诊断边界。
### 账号用量边界
@@ -336,7 +342,7 @@ CI 和全新产物检查才是当前测试计数的唯一来源。它们验证
## 版本
-本仓库代表版本化的 v1.1.3 包。发布说明见
+本仓库代表版本化的 v1.1.4 包。发布说明见
[CHANGELOG.md](CHANGELOG.md);构建和安装请以已提交的 manifest、产物 allowlist
和锁定依赖为准。维护者从 current `main` 手动 dispatch Release;它通过全部 gates
后才创建注释 tag 并发布匹配的 GitHub Release。单独 push tag 不会触发发布。
diff --git a/mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md b/mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md
index 08947b6..59a374b 100644
--- a/mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md
+++ b/mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md
@@ -106,30 +106,48 @@ does not weaken host capability, lease, worktree, review, or safety gates.
source-plan hash 必须包含该整个 binding,因此相同 task/workflow 在不同项目、workspace 或输入
snapshot 下不能共用计划、lease、receipt 或恢复状态。
-manifest 中的 fence 只是可验证的结构与 hash 输入,绝不是 authority。DevKit 不拥有 Desktop-host
-durable registry;已认证 inherited host bridge 只能按一次性 nonce/expiry 向宿主 registry 请求
-compiler evidence。因此没有任何同进程 provider、module
-attribute、closure、环境变量、请求 JSON、repo/task root、路径名或 caller-supplied ID 可被当作
-live authority。公开 `compile_fast_lane` 与 `fast-lane` CLI 对 structurally valid V2 一律产出
-`NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE`,零本地 assignment、零队列、零外部派发;V2
+manifest 中的 fence 只是可验证的结构与 hash 输入,绝不是执行 authority。没有任何 module
+attribute、closure、环境变量、请求 JSON、repo/task root、路径名或 caller-supplied ID 可以授权
+spawn、lease、worktree 或 Git mutation。公开 Python `compile_fast_lane` 与 `fast-lane` CLI 对
+structurally valid V2 继续产出 `team-efficiency/fast-lane-plan-v1` 的
+`NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE`,零 assignment、零队列、零外部派发;V2
envelope/hash 无效、其内层 canonical v1 `package` 不能完成纯诊断解析,或 fast-lane request
壳的 schema/key/字节边界无效时,必须是 `PROJECT_BINDING_INVALID`;v1 保持
-`LEGACY_PROJECT_UNBOUND`。这些结构预检不读取 host、账号用量或 index 输入,也不触及 scheduler。
-公开 MCP request 若试图携带明确的 host-private 字段(如 `host_status`、账号用量或 index
-evidence),则是适配器输入违规,必须在编译前以 `FASTLANE_REQUEST_INVALID` 拒绝,而不是把
-该值当作可诊断的计划输入。
-`compiler-evidence-request-v1/response-v1` 与 typed dispatch batch 是唯一跨进程
-authority 通道:request/response 必须 exact-key、同 bridge generation、一次性且完整绑定 route、
-lease、scope、context、predecessor、worktree identity 与 registry hash。它不接受 actual path,
-也不能由工作包 JSON、环境变量值或 Python 私有命名伪造。
+`LEGACY_PROJECT_UNBOUND`。
+
+MCP `fastlane_compile` 使用不同的 server-private planning path。公开 request 中的
+`workspace_id` 与 `input_snapshot_id` 只作为 selector;server 在只读 RuntimeRoot UoW 内解析
+持久 registry,并由 Project Index service 读取 current snapshot、canonical `include_paths` 与
+真实 Git HEAD,再把这些事实直接交给 module-private 编译入口。该材料入口不是公开 Python API
+参数,也不从 `devkit_fastlane/__init__.py` 导出。公开 MCP request 若携带 `host_status`、账号
+用量、index evidence、root 或 Git HEAD 等 caller 自报材料,必须在编译前以
+`FASTLANE_REQUEST_INVALID` 拒绝。
+
+server-private 编译在创建任何 planned assignment 前必须同时证明:workspace/snapshot binding
+匹配 selector;snapshot 为 current `INDEX_READY`;snapshot head、scheduler integration commit
+与每个 bootstrap base commit 都等于真实 Git HEAD;bootstrap repo 等于 registry root;持久化
+`include_paths` 为 canonical 且完整覆盖 source plan 中每个 writer `write_scope`。空
+`include_paths` 表示完整 workspace snapshot;非空 include root 必须等于 scope 或是 scope 的
+祖先。snapshot 自身有 gap,或任一 writer scope 未被覆盖,均精确返回 `INDEX_PARTIAL`;文件或
+Git 漂移返回 `INDEX_STALE`;binding、root、snapshot 或 HEAD 错配必须 fail closed,不能产生
+部分计划。
+
+成功响应 schema 为 `team-efficiency/fast-lane-plan-v2`。顶层固定
+`plan_only=true`、`dispatch_state="not_dispatched"`、`execution_authorized=false`;assignment
+使用 `team-efficiency/local-writer-plan-v1`,固定 `execution_state="plan_only"`、
+`lease_state="unclaimed"` 与 `worktree.state="planned"`。path-free `index_evidence` 使用
+`team-efficiency/local-index-evidence-v1`,包含 workspace/snapshot/head/manifest/parser binding
+hash、`include_paths_hash`、所有 writer scopes 的 `scope_hash` 与最终 `evidence_hash`,但不返回
+registry root、raw Git HEAD 或 include path 文本。`workflow_policy` 只说明协调器后续必须显式
+验证 route、领取 lease 并调用 dispatch tool;它不是执行许可,编译器也不调用该工具。
同一限制覆盖 `bootstrap --apply` 及 import-callable `apply_bootstrap_plan`:当前公开入口在构建
caller-supplied bootstrap plan 或调用 worktree mutation 前,无条件以
`NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE` 失败关闭,因而不能到达
`git worktree add`。不带 `--apply` 的 `bootstrap` 仍只输出 dry-run 诊断计划;其中的 project、
root、worktree 和任何 JSON 都不是 sealed V2 execution context。DevKit 仍不存在自行创建 worktree
-的可执行路径;authenticated compiler evidence 只允许将 typed batch 提交给宿主,不能绕过宿主的
-worktree broker、Git probe 或 coordinator gate。
+的可执行路径;plan-v2 不是 typed dispatch batch,也不能绕过外部宿主的 worktree broker、Git
+probe 或 coordinator gate。
### 4. 接地后再写
@@ -147,7 +165,10 @@ worktree broker、Git probe 或 coordinator gate。
python scripts/team_efficiency.py fast-lane --input --host-status --reasoning-effort ultra
```
-`ultra` 自动激活(Ultra automatic activation);低于 Ultra 的 effort 必须由 host 显式传入 `--enable`,否则得到 inactive plan。公开 `fast-lane` CLI/API 不消费 host-status、额度或 index 输入,因此仍输出 `NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE` 的零 assignment/队列预览。只有 MCP 进程持有已认证 inherited bridge 且宿主返回 exact registry binding 时,私有 adapter 才能机械提交 `dispatch_all`;worker effort 禁止 `ultra`。编译器本身不调用模型、不启动 agent、不创建会话或工作树、不运行 gate、不改写 Git、不领取或完成 workflow。协调器 lane 保有设计、集成、风险决策和最终验收责任。
+`ultra` 自动激活(Ultra automatic activation);低于 Ultra 的 effort 必须显式传入 `--enable`,否则得到 inactive plan。这个 CLI/API 不消费 host-status、额度或 index 输入,因此仍输出 plan-v1 的 `NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE` 零 assignment/队列预览。MCP 工具只接受 `low`、`medium`、`high`、`xhigh`、`max`,并在 `enable=true` 时返回上述 plan-v2;`enable=false` 返回同 schema 的 inactive、零 assignment 计划,但仍先验证 registry/index/Git binding。两种编译路径都不调用模型、不启动 agent、不创建会话或工作树、不运行 gate、不改写 Git、不领取或完成 workflow。协调器 lane 保有设计、集成、风险决策和最终验收责任;同时负责 route availability 与 dispatch。
+
+以下 host-status、`host_dispatch`、cross-session projection 与 refill 规则只描述 plan-v1 的外部
+host contract;它们不由当前 MCP `fastlane_compile` 调用,也不能把 plan-v2 变成 dispatch receipt。
host 通过不超过 3 MiB、有 exact-key 的 `--host-status` 传入 `workflow_id`、当前 lease/binding 与
`routing_context`。后者按 `(task_id, scheduler_role)` 唯一关联完整
diff --git a/mcp-tools/devkit_fastlane/references/efficiency-automation.md b/mcp-tools/devkit_fastlane/references/efficiency-automation.md
index b26f017..dc343d0 100644
--- a/mcp-tools/devkit_fastlane/references/efficiency-automation.md
+++ b/mcp-tools/devkit_fastlane/references/efficiency-automation.md
@@ -158,23 +158,26 @@ still canonical diagnostic input and the required future external-host contract:
}
```
-The diagnostic decomposition and inert public blocked-plan hash incorporate
-this full binding into `source_plan_hash`. The manifest provides structural fence data, never
+The diagnostic decomposition and plan hash incorporate this full binding into
+`source_plan_hash`. The manifest provides structural fence data, never execution
authority; no environment project ID, root path, worktree path, task-root
component, caller-supplied identifier, Python module attribute, or closure can
-replace a live host record. This repository has no Desktop-host durable
-registry or external private bridge, so its public `compile_fast_lane` and
-`fast-lane` CLI do not compare against an in-process provider and cannot
-activate V2: a structurally valid V2 request always yields
-`NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE` with zero assignments, local
-queues, and external-session assignments. An invalid V2 envelope/hash yields
+authorize execution. The public Python `compile_fast_lane` and `fast-lane` CLI
+remain plan-v1 diagnostics: a structurally valid V2 request yields
+`NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE` with zero assignments, local queues,
+and external-session assignments. An invalid V2 envelope/hash yields
`PROJECT_BINDING_INVALID`; so does an inner canonical-v1 `package` that fails
pure diagnostic parsing, or an invalid fast-lane request schema/key/byte shell.
-Those checks occur before any host, account-usage, or index input is read. V1 yields
-`NO_SAFE_WORK/LEGACY_PROJECT_UNBOUND`.
-An MCP request that explicitly carries host-private fields such as `host_status`,
-account-usage, or index evidence is not a diagnostic plan shell: the public adapter must
-reject it as `FASTLANE_REQUEST_INVALID` before compilation.
+V1 yields `NO_SAFE_WORK/LEGACY_PROJECT_UNBOUND`.
+
+MCP `fastlane_compile` resolves the same caller IDs only as selectors through a
+read-only RuntimeRoot UoW. Its server-private path requires a current,
+`INDEX_READY`, Git-HEAD-bound snapshot whose persisted `include_paths` fully
+cover every writer `write_scope`, then emits
+`team-efficiency/fast-lane-plan-v2`. The private index/root/Git material is not a
+public Python argument or package export. An MCP request that explicitly carries
+`host_status`, account usage, index evidence, a root, or Git HEAD is rejected as
+`FASTLANE_REQUEST_INVALID` before compilation.
Public `bootstrap --apply` and import-callable `apply_bootstrap_plan` are both
blocked before any caller plan, path, provider override, closure, or JSON can
reach a worktree helper, because no such helper exists in this repository.
@@ -319,7 +322,7 @@ workspace, trace id, or snapshot id from Atlas evidence.
## Ultra Fast Lane
-`fast-lane` compiles the exact
+The public Python/CLI `fast-lane` path compiles the exact
`team-efficiency/fast-lane-request-v1` request into a deterministic
`team-efficiency/fast-lane-plan-v1` result. It is a pure compiler: all target gates,
contexts, receipts, tokens, and workflow operations are inert dispatch descriptors. The
@@ -327,6 +330,15 @@ helper performs no model call, agent spawn, remote service contact, gate run,
Git mutation, workflow call, lease claim, endpoint bind, or workflow
completion.
+The MCP tool response uses `team-efficiency/fast-lane-plan-v2`. It fixes
+`plan_only=true`, `dispatch_state="not_dispatched"`, and
+`execution_authorized=false`; each `team-efficiency/local-writer-plan-v1`
+assignment is planned/unclaimed, and path-free
+`team-efficiency/local-index-evidence-v1` exposes only binding hashes including
+`include_paths_hash` and the compiled writer `scope_hash`. `INDEX_PARTIAL`
+rejects both an incomplete snapshot and omitted writer-scope coverage;
+`INDEX_STALE` rejects filesystem or Git drift.
+
The host invokes `fast-lane` with an explicit reasoning effort. `ultra` is the
automatic activation path (`ultra_auto`); lower efforts require explicit
`--enable` (`explicit_opt_in`) and otherwise return an inactive plan.
diff --git a/mcp-tools/devkit_fastlane/scripts/team_efficiency.py b/mcp-tools/devkit_fastlane/scripts/team_efficiency.py
index 99938ee..591f33c 100644
--- a/mcp-tools/devkit_fastlane/scripts/team_efficiency.py
+++ b/mcp-tools/devkit_fastlane/scripts/team_efficiency.py
@@ -708,6 +708,120 @@
"complex": "Terra Max",
"exceptional": "Sol High",
}
+_LOCAL_ROUTE_MODELS = {
+ "Luna": "gpt-5.6-luna",
+ "Terra": "gpt-5.6-terra",
+ "Sol": "gpt-5.6-sol",
+}
+_LOCAL_ROUTE_FLOOR_RANKS = {
+ "low": 20,
+ "medium": 40,
+ "high": 60,
+ "xhigh": 80,
+ "max": 100,
+}
+_LOCAL_PLAN_MATERIAL_FIELDS = frozenset(
+ {
+ "workspace_id",
+ "root_identity_hash",
+ "workspace_binding_hash",
+ "snapshot_id",
+ "snapshot_attestation_hash",
+ "head_hash",
+ "manifest_hash",
+ "parser_set_hash",
+ "workspace_root",
+ "git_head",
+ "include_paths",
+ "include_paths_hash",
+ }
+)
+_LOCAL_PLAN_V2_FIELDS = frozenset(
+ {
+ "schema",
+ "status",
+ "decision_code",
+ "plan_only",
+ "dispatch_state",
+ "execution_authorized",
+ "activation",
+ "source_plan_hash",
+ "phase",
+ "subagent_capacity",
+ "assignments",
+ "idle_slots",
+ "index_evidence",
+ "workflow_policy",
+ "plan_hash",
+ }
+)
+_LOCAL_PLAN_ASSIGNMENT_FIELDS = frozenset(
+ {
+ "schema",
+ "slot_id",
+ "task_id",
+ "role",
+ "goal",
+ "output_boundary",
+ "execution_state",
+ "dispatch_state",
+ "execution_authorized",
+ "lease_state",
+ "worktree",
+ "model",
+ "reasoning_effort",
+ "routing_context_hash",
+ "routing_result_hash",
+ "task_fingerprint",
+ "routing_reason_codes",
+ "depends_on",
+ "required_evidence",
+ "index_evidence",
+ "plan_item_id",
+ }
+)
+_LOCAL_PLAN_WORKTREE_FIELDS = frozenset(
+ {
+ "state",
+ "identity_hash",
+ "base_commit",
+ "branch",
+ "write_scope",
+ "write_scope_hash",
+ }
+)
+_LOCAL_PLAN_READ_WORKTREE_FIELDS = frozenset(
+ {"state", "identity_hash", "write_scope", "write_scope_hash"}
+)
+_LOCAL_PLAN_POLICY_FIELDS = frozenset(
+ {
+ "schema",
+ "consumer",
+ "dispatch_tool",
+ "explicit_route_required",
+ "lease_claim_required_before_execution",
+ "compiler_side_effects",
+ }
+)
+_LOCAL_PLAN_INDEX_EVIDENCE_FIELDS = frozenset(
+ {
+ "schema",
+ "workspace_id",
+ "root_identity_hash",
+ "workspace_binding_hash",
+ "snapshot_id",
+ "snapshot_attestation_hash",
+ "head_hash",
+ "manifest_hash",
+ "parser_set_hash",
+ "include_paths_hash",
+ "scope_hash",
+ "evidence_hash",
+ }
+)
+_LOCAL_PLAN_ACTIVATION_FIELDS = frozenset({"reasoning_effort", "reason"})
+_LOCAL_PLAN_INACTIVE_ACTIVATION_FIELDS = frozenset({"reasoning_effort"})
+_LOCAL_PLAN_IDLE_SLOT_FIELDS = frozenset({"slot_id", "reason_code"})
_ARTIFACT_SOURCE_KINDS = frozenset({"explicit_artifact_boundaries"})
_ATLAS_SOURCE_KINDS = frozenset({"code_atlas_packet", "task_episode_graph"})
_ATLAS_PACKET_FIELDS = frozenset(
@@ -9443,6 +9557,535 @@ def _fast_lane_apply_index_evidence(
return bound
+class _FastLaneLocalPlanError(ValueError):
+ """One precise local planning failure safe to expose at the MCP boundary."""
+
+ def __init__(self, code: str) -> None:
+ self.code = code
+ super().__init__(code)
+
+
+def _fast_lane_local_selector(request: Mapping[str, Any]) -> tuple[str, str]:
+ """Return registry selectors from a fully validated indexed V2 envelope.
+
+ The opaque values select persisted local state only. They do not grant
+ execution, lease, worktree, or dispatch authority.
+ """
+
+ reason_code, source_identity = _project_execution_block_details(request)
+ if reason_code != "PROJECT_AUTHORITY_UNAVAILABLE" or source_identity is None:
+ raise _FastLaneLocalPlanError(reason_code)
+ authority = _mapping(
+ source_identity.get("project_authority"), "project authority selector"
+ )
+ return (
+ _hash(authority.get("workspace_id"), "project authority.workspace_id"),
+ _hash(
+ authority.get("input_snapshot_id"),
+ "project authority.input_snapshot_id",
+ ),
+ )
+
+
+def _fast_lane_public_value(value: object) -> Any:
+ """Apply the MCP no-null projection before any public identity is hashed."""
+
+ if type(value) is dict:
+ return {
+ key: _fast_lane_public_value(item)
+ for key, item in value.items()
+ if item is not None
+ }
+ if type(value) is list:
+ return [_fast_lane_public_value(item) for item in value if item is not None]
+ return value
+
+
+def _validated_fast_lane_local_index_evidence(value: object) -> dict[str, Any]:
+ evidence = _mapping(value, "local plan index evidence")
+ _exact_keys(
+ evidence,
+ _LOCAL_PLAN_INDEX_EVIDENCE_FIELDS,
+ "local plan index evidence",
+ )
+ if evidence["schema"] != "team-efficiency/local-index-evidence-v1":
+ raise ValueError("local plan index evidence schema is invalid")
+ supplied_hash = _hash(
+ evidence["evidence_hash"], "local plan index evidence.evidence_hash"
+ )
+ normalized = {key: item for key, item in evidence.items() if key != "evidence_hash"}
+ if supplied_hash != _sha256_json(normalized):
+ raise ValueError("local plan index evidence hash is invalid")
+ for field in _LOCAL_PLAN_INDEX_EVIDENCE_FIELDS - {"schema", "evidence_hash"}:
+ _hash(evidence[field], f"local plan index evidence.{field}")
+ return dict(evidence)
+
+
+def _validated_fast_lane_local_worktree(value: object, *, role: str) -> dict[str, Any]:
+ worktree = _mapping(value, "local planned worktree")
+ expected = (
+ _LOCAL_PLAN_WORKTREE_FIELDS
+ if role == "execution"
+ else _LOCAL_PLAN_READ_WORKTREE_FIELDS
+ )
+ _exact_keys(worktree, expected, "local planned worktree")
+ if worktree["state"] != "planned":
+ raise ValueError("local planned worktree state is invalid")
+ scopes = _normalised_list(
+ worktree["write_scope"],
+ "local planned worktree.write_scope",
+ _relative_scope,
+ maximum=MAX_WRITE_SCOPES,
+ )
+ if worktree["write_scope"] != scopes:
+ raise ValueError("local planned worktree write scope is not canonical")
+ _hash(
+ worktree["write_scope_hash"],
+ "local planned worktree.write_scope_hash",
+ )
+ _hash(worktree["identity_hash"], "local planned worktree.identity_hash")
+ if role == "execution":
+ _git_id(worktree["base_commit"], "local planned worktree.base_commit")
+ _branch(worktree["branch"])
+ return dict(worktree)
+
+
+def _validated_fast_lane_local_assignment(value: object) -> dict[str, Any]:
+ assignment = _mapping(value, "local planned assignment")
+ _exact_keys(
+ assignment,
+ _LOCAL_PLAN_ASSIGNMENT_FIELDS,
+ "local planned assignment",
+ )
+ if assignment["schema"] != "team-efficiency/local-writer-plan-v1":
+ raise ValueError("local planned assignment schema is invalid")
+ role = _text(assignment["role"], "local planned assignment.role", maximum=32)
+ if role not in _FAST_LANE_ROLES:
+ raise ValueError("local planned assignment role is invalid")
+ if (
+ assignment["execution_state"] != "plan_only"
+ or assignment["dispatch_state"] != "not_dispatched"
+ or assignment["execution_authorized"] is not False
+ or assignment["lease_state"] != "unclaimed"
+ ):
+ raise ValueError("local planned assignment execution state is invalid")
+ _validated_fast_lane_local_worktree(assignment["worktree"], role=role)
+ _validated_fast_lane_local_index_evidence(assignment["index_evidence"])
+ supplied_id = _hash(
+ assignment["plan_item_id"], "local planned assignment.plan_item_id"
+ )
+ normalized = {
+ key: item for key, item in assignment.items() if key != "plan_item_id"
+ }
+ if supplied_id != _sha256_json(normalized):
+ raise ValueError("local planned assignment identity is invalid")
+ return dict(assignment)
+
+
+def _validated_fast_lane_local_policy(value: object) -> dict[str, Any]:
+ policy = _mapping(value, "local plan workflow policy")
+ _exact_keys(policy, _LOCAL_PLAN_POLICY_FIELDS, "local plan workflow policy")
+ if dict(policy) != {
+ "schema": "team-efficiency/local-plan-consumer-policy-v1",
+ "consumer": "main_coordinator",
+ "dispatch_tool": "collaboration.spawn_agent",
+ "explicit_route_required": True,
+ "lease_claim_required_before_execution": True,
+ "compiler_side_effects": False,
+ }:
+ raise ValueError("local plan workflow policy is invalid")
+ return dict(policy)
+
+
+def _validated_fast_lane_local_plan(value: object) -> dict[str, Any]:
+ plan = _mapping(value, "fast-lane local plan")
+ _exact_keys(plan, _LOCAL_PLAN_V2_FIELDS, "fast-lane local plan")
+ if plan["schema"] != "team-efficiency/fast-lane-plan-v2":
+ raise ValueError("fast-lane local plan schema is invalid")
+ if (
+ plan["plan_only"] is not True
+ or plan["dispatch_state"] != "not_dispatched"
+ or plan["execution_authorized"] is not False
+ ):
+ raise ValueError("fast-lane local plan execution state is invalid")
+
+ activation = _mapping(plan["activation"], "fast-lane local plan activation")
+ activation_fields = (
+ _LOCAL_PLAN_ACTIVATION_FIELDS
+ if "reason" in activation
+ else _LOCAL_PLAN_INACTIVE_ACTIVATION_FIELDS
+ )
+ _exact_keys(activation, activation_fields, "fast-lane local plan activation")
+
+ index_evidence = _validated_fast_lane_local_index_evidence(plan["index_evidence"])
+ assignments = plan["assignments"]
+ if type(assignments) is not list or len(assignments) > len(FAST_LANE_SLOT_IDS):
+ raise ValueError("fast-lane local plan assignments are invalid")
+ for assignment_value in assignments:
+ assignment = _validated_fast_lane_local_assignment(assignment_value)
+ if assignment["index_evidence"] != index_evidence:
+ raise ValueError("local planned assignment index evidence is not bound")
+
+ idle_slots = plan["idle_slots"]
+ if type(idle_slots) is not list or len(idle_slots) > len(FAST_LANE_SLOT_IDS):
+ raise ValueError("fast-lane local plan idle slots are invalid")
+ for index, idle_value in enumerate(idle_slots):
+ idle = _mapping(idle_value, f"fast-lane local plan idle_slots[{index}]")
+ _exact_keys(
+ idle,
+ _LOCAL_PLAN_IDLE_SLOT_FIELDS,
+ f"fast-lane local plan idle_slots[{index}]",
+ )
+
+ _validated_fast_lane_local_policy(plan["workflow_policy"])
+ supplied_hash = _hash(plan["plan_hash"], "fast-lane local plan.plan_hash")
+ normalized = {key: item for key, item in plan.items() if key != "plan_hash"}
+ if supplied_hash != _sha256_json(normalized):
+ raise ValueError("fast-lane local plan hash is invalid")
+ return dict(plan)
+
+
+def _fast_lane_local_routing_context(
+ source_plan: Mapping[str, Any], source_plan_hash: str
+) -> dict[str, Any]:
+ """Resolve the package-owned route policy without capability claims.
+
+ These are coordinator inputs, not observations that a model or worker is
+ currently available. The collaboration boundary remains responsible for
+ rejecting an unavailable explicit route.
+ """
+
+ decisions: dict[tuple[str, str], dict[str, Any]] = {}
+ reasons: dict[tuple[str, str], str] = {}
+ for task_id, unit in sorted(_fast_lane_unit_index(source_plan).items()):
+ route_text = _text(
+ unit.get("recommended_route"),
+ f"source unit {task_id}.recommended_route",
+ maximum=64,
+ )
+ try:
+ family, effort_text = route_text.split(" ", 1)
+ model = _LOCAL_ROUTE_MODELS[family]
+ effort = effort_text.casefold()
+ floor_rank = _LOCAL_ROUTE_FLOOR_RANKS[effort]
+ except (KeyError, ValueError) as error:
+ raise _FastLaneLocalPlanError("FASTLANE_ROUTE_UNAVAILABLE") from error
+ for role in sorted(_FAST_LANE_ROLES):
+ route_input = {
+ "schema": "team-efficiency/local-route-input-v1",
+ "source_plan_hash": source_plan_hash,
+ "task_id": task_id,
+ "role": role,
+ "recommended_route": route_text,
+ }
+ route_result = {
+ "schema": "team-efficiency/local-route-result-v1",
+ "task_id": task_id,
+ "role": role,
+ "model": model,
+ "reasoning_effort": effort,
+ "source": "package_policy",
+ }
+ decisions[(task_id, role)] = {
+ "model": model,
+ "reasoning_effort": effort,
+ "routing_context_hash": _sha256_json(route_input),
+ "routing_result_hash": _sha256_json(route_result),
+ "task_fingerprint": _sha256_json(
+ {
+ "task_id": task_id,
+ "goal": unit.get("goal"),
+ "write_scope": unit.get("write_scope", []),
+ }
+ ),
+ "routing_reason_codes": ["package_policy_route"],
+ "routing_safety_floor_rank": floor_rank,
+ "routing_render_hash": _sha256_json(
+ {"model": model, "reasoning_effort": effort}
+ ),
+ "routing_input": route_input,
+ }
+ reasons[(task_id, role)] = ""
+ return {
+ "decisions": decisions,
+ "reasons": reasons,
+ "default_reason": "routing_context_missing",
+ "global_failure_reason": None,
+ }
+
+
+def _validated_fast_lane_local_material(
+ material_value: Mapping[str, Any],
+ *,
+ request: Mapping[str, Any],
+ validated: Mapping[str, Any],
+) -> tuple[dict[str, str], Path]:
+ material = _mapping(material_value, "local plan material")
+ _exact_keys(material, _LOCAL_PLAN_MATERIAL_FIELDS, "local plan material")
+ workspace_id = _hash(material["workspace_id"], "local material.workspace_id")
+ snapshot_id = _hash(material["snapshot_id"], "local material.snapshot_id")
+ root_identity_hash = _hash(
+ material["root_identity_hash"], "local material.root_identity_hash"
+ )
+ workspace_binding_hash = _hash(
+ material["workspace_binding_hash"], "local material.workspace_binding_hash"
+ )
+ snapshot_attestation_hash = _hash(
+ material["snapshot_attestation_hash"],
+ "local material.snapshot_attestation_hash",
+ )
+ head_hash = _hash(material["head_hash"], "local material.head_hash")
+ manifest_hash = _hash(material["manifest_hash"], "local material.manifest_hash")
+ parser_set_hash = _hash(
+ material["parser_set_hash"], "local material.parser_set_hash"
+ )
+ git_head = _git_id(material["git_head"], "local material.git_head").casefold()
+ workspace_root = _absolute_path(
+ material["workspace_root"], "local material.workspace_root"
+ ).resolve(strict=True)
+
+ selected_workspace_id, selected_snapshot_id = _fast_lane_local_selector(request)
+ if workspace_id != selected_workspace_id:
+ raise _FastLaneLocalPlanError("FASTLANE_WORKSPACE_MISMATCH")
+ if snapshot_id != selected_snapshot_id:
+ raise _FastLaneLocalPlanError("FASTLANE_SNAPSHOT_MISMATCH")
+
+ include_paths_value = material["include_paths"]
+ if not isinstance(include_paths_value, Sequence) or isinstance(
+ include_paths_value, (str, bytes, bytearray)
+ ):
+ raise _FastLaneLocalPlanError("FASTLANE_INDEX_BINDING_INVALID")
+ try:
+ include_paths = tuple(
+ _relative_scope(value, "local material.include_paths")
+ for value in include_paths_value
+ )
+ except (TypeError, ValueError) as error:
+ raise _FastLaneLocalPlanError("FASTLANE_INDEX_BINDING_INVALID") from error
+ if include_paths != tuple(sorted(set(include_paths))):
+ raise _FastLaneLocalPlanError("FASTLANE_INDEX_BINDING_INVALID")
+ include_paths_hash = _hash(
+ material["include_paths_hash"], "local material.include_paths_hash"
+ )
+ if include_paths_hash != _sha256_json({"include_paths": include_paths}):
+ raise _FastLaneLocalPlanError("FASTLANE_INDEX_BINDING_INVALID")
+
+ base_material = {
+ "workspace_id": workspace_id,
+ "root_identity_hash": root_identity_hash,
+ "workspace_binding_hash": workspace_binding_hash,
+ }
+ if workspace_binding_hash != _sha256_json(
+ {
+ "workspace_id": workspace_id,
+ "root_identity_hash": root_identity_hash,
+ }
+ ):
+ raise _FastLaneLocalPlanError("FASTLANE_INDEX_BINDING_INVALID")
+ if head_hash != _sha256_json({"head": git_head}):
+ raise _FastLaneLocalPlanError("FASTLANE_GIT_BINDING_INVALID")
+ if snapshot_attestation_hash != _sha256_json(
+ {
+ **base_material,
+ "snapshot_id": snapshot_id,
+ "head_hash": head_hash,
+ "manifest_hash": manifest_hash,
+ "parser_set_hash": parser_set_hash,
+ }
+ ):
+ raise _FastLaneLocalPlanError("FASTLANE_INDEX_BINDING_INVALID")
+
+ state = _mapping(validated["scheduler_state"], "scheduler state")
+ if state["integration_state"]["commit"].casefold() != git_head:
+ raise _FastLaneLocalPlanError("FASTLANE_GIT_HEAD_MISMATCH")
+ for context in validated["execution_contexts"]:
+ plan = context["bootstrap_plan"]
+ repo = _absolute_path(plan["repo"], "bootstrap plan.repo").resolve(strict=True)
+ if _fast_lane_path_identity(repo) != _fast_lane_path_identity(workspace_root):
+ raise _FastLaneLocalPlanError("FASTLANE_WORKSPACE_MISMATCH")
+ if plan["base_commit"].casefold() != git_head:
+ raise _FastLaneLocalPlanError("FASTLANE_GIT_HEAD_MISMATCH")
+
+ scopes = sorted(
+ {
+ scope
+ for unit in validated["source_plan"].get("units", [])
+ for scope in unit.get("write_scope", [])
+ }
+ )
+ if include_paths and any(
+ not any(
+ scope == include or scope.startswith(f"{include}/")
+ for include in include_paths
+ )
+ for scope in scopes
+ ):
+ raise _FastLaneLocalPlanError("INDEX_PARTIAL")
+ public_evidence = {
+ "schema": "team-efficiency/local-index-evidence-v1",
+ **base_material,
+ "snapshot_id": snapshot_id,
+ "snapshot_attestation_hash": snapshot_attestation_hash,
+ "head_hash": head_hash,
+ "manifest_hash": manifest_hash,
+ "parser_set_hash": parser_set_hash,
+ "include_paths_hash": include_paths_hash,
+ "scope_hash": _sha256_json(scopes),
+ }
+ public_evidence["evidence_hash"] = _sha256_json(public_evidence)
+ return public_evidence, workspace_root
+
+
+def _fast_lane_local_assignment_output(
+ validated: Mapping[str, Any],
+ assignment: Mapping[str, Any],
+ *,
+ index_evidence: Mapping[str, str],
+) -> dict[str, Any]:
+ task_id = _task_id(assignment["task_id"], "planned assignment.task_id")
+ role = _text(assignment["role"], "planned assignment.role", maximum=32)
+ unit = _fast_lane_unit_index(validated["source_plan"])[task_id]
+ context = _mapping(assignment.get("_context"), "planned assignment context")
+ execution_context = next(
+ (
+ item
+ for item in validated["execution_contexts"]
+ if item["task_id"] == task_id
+ ),
+ None,
+ )
+ if role == "execution" and execution_context is None:
+ raise _FastLaneLocalPlanError("FASTLANE_EXECUTION_CONTEXT_MISSING")
+ read_context = next(
+ (
+ item
+ for item in validated["read_contexts"]
+ if item["task_id"] == task_id and item["role"] == role
+ ),
+ None,
+ )
+ if role != "execution" and read_context is None:
+ raise _FastLaneLocalPlanError("FASTLANE_READ_CONTEXT_MISSING")
+ bootstrap = (
+ None if execution_context is None else execution_context["bootstrap_plan"]
+ )
+ worktree_path = (
+ bootstrap["worktree"]
+ if role == "execution" and bootstrap is not None
+ else read_context["worktree"]
+ )
+ worktree_value = {
+ "state": "planned",
+ "identity_hash": _sha256_json({"worktree": worktree_path}),
+ "base_commit": context["base_commit"],
+ "branch": context["branch"],
+ "write_scope": list(unit.get("write_scope", [])),
+ "write_scope_hash": context["write_scope_hash"],
+ }
+ worktree = _fast_lane_public_value(worktree_value)
+ if type(worktree) is not dict:
+ raise ValueError("local planned worktree is invalid")
+ item_value = {
+ "schema": "team-efficiency/local-writer-plan-v1",
+ "slot_id": assignment["slot_id"],
+ "task_id": task_id,
+ "role": role,
+ "goal": unit["goal"],
+ "output_boundary": unit["output_boundary"],
+ "execution_state": "plan_only",
+ "dispatch_state": "not_dispatched",
+ "execution_authorized": False,
+ "lease_state": "unclaimed",
+ "worktree": worktree,
+ "model": assignment["model"],
+ "reasoning_effort": assignment["reasoning_effort"],
+ "routing_context_hash": assignment["routing_context_hash"],
+ "routing_result_hash": assignment["routing_result_hash"],
+ "task_fingerprint": assignment["task_fingerprint"],
+ "routing_reason_codes": list(assignment["routing_reason_codes"]),
+ "depends_on": list(unit.get("depends_on", [])),
+ "required_evidence": list(unit.get("required_evidence", [])),
+ "index_evidence": dict(index_evidence),
+ }
+ item = _fast_lane_public_value(item_value)
+ if type(item) is not dict:
+ raise ValueError("local planned assignment is invalid")
+ item["plan_item_id"] = _sha256_json(item)
+ return _validated_fast_lane_local_assignment(item)
+
+
+def _compile_fast_lane_local_plan(
+ request: Mapping[str, Any],
+ *,
+ reasoning_effort: str,
+ enable: bool,
+ local_plan_material: Mapping[str, Any],
+) -> dict[str, Any]:
+ activation = _fast_lane_activation(reasoning_effort, enable)
+ validated = _validated_fast_lane_request(request)
+ validated = {
+ **validated,
+ "routing_context": _fast_lane_local_routing_context(
+ validated["source_plan"], validated["source_plan_hash"]
+ ),
+ }
+ if validated["scheduler_state"]["running_assignments"]:
+ raise _FastLaneLocalPlanError("FASTLANE_RUNTIME_STATE_UNSUPPORTED")
+ index_evidence, _workspace_root = _validated_fast_lane_local_material(
+ local_plan_material,
+ request=request,
+ validated=validated,
+ )
+ if activation["reason"] is None:
+ planned_assignments: list[dict[str, Any]] = []
+ idle_slots = _fast_lane_idle_slots("OPT_IN_REQUIRED")
+ status = "inactive"
+ decision_code = "EXPLICIT_OPT_IN_REQUIRED"
+ else:
+ selected, idle_slots = _fast_lane_select_actions(validated, activation)
+ planned_assignments = [
+ _fast_lane_local_assignment_output(
+ validated, assignment, index_evidence=index_evidence
+ )
+ for assignment in selected
+ ]
+ status = "planned" if planned_assignments else "blocked"
+ decision_code = (
+ "FAST_LANE_PLANNED" if planned_assignments else "NO_SAFE_LOCAL_PLAN"
+ )
+ result_value: dict[str, Any] = {
+ "schema": "team-efficiency/fast-lane-plan-v2",
+ "status": status,
+ "decision_code": decision_code,
+ "plan_only": True,
+ "dispatch_state": "not_dispatched",
+ "execution_authorized": False,
+ "activation": dict(activation),
+ "source_plan_hash": validated["source_plan_hash"],
+ "phase": validated["scheduler_state"]["phase"],
+ "subagent_capacity": len(FAST_LANE_SLOT_IDS),
+ "assignments": planned_assignments,
+ "idle_slots": list(idle_slots),
+ "index_evidence": index_evidence,
+ "workflow_policy": {
+ "schema": "team-efficiency/local-plan-consumer-policy-v1",
+ "consumer": "main_coordinator",
+ "dispatch_tool": "collaboration.spawn_agent",
+ "explicit_route_required": True,
+ "lease_claim_required_before_execution": True,
+ "compiler_side_effects": False,
+ },
+ }
+ result = _fast_lane_public_value(result_value)
+ if type(result) is not dict:
+ raise ValueError("fast-lane local plan is invalid")
+ result["plan_hash"] = _sha256_json(result)
+ result = _validated_fast_lane_local_plan(result)
+ if len(_json_bytes(result)) > MAX_MANIFEST_BYTES:
+ raise ValueError("fast-lane plan exceeds its byte budget")
+ return result
+
+
def compile_fast_lane(
request: Mapping[str, Any],
*,
diff --git a/mcp-tools/project_index/service.py b/mcp-tools/project_index/service.py
index 92dc753..d214fae 100644
--- a/mcp-tools/project_index/service.py
+++ b/mcp-tools/project_index/service.py
@@ -752,6 +752,62 @@ def host_attestation_material(
)
return material
+ def local_plan_material(
+ self,
+ workspace_id: str,
+ *,
+ snapshot_id: str,
+ ) -> dict[str, object]:
+ """Return current registry, index, and Git facts for local planning.
+
+ Unlike ``host_attestation_material``, this projection is consumed only
+ inside the MCP process. The root and raw Git head are deliberately
+ private inputs used to bind caller selectors and dry-run worktree
+ descriptors to the registered workspace; callers receive only the
+ path-free evidence projection produced by the Fast Lane compiler.
+ """
+
+ registered_id, root = self._workspace_for_reference(workspace_id)
+ material = self.host_attestation_material(
+ registered_id,
+ snapshot_id=snapshot_id,
+ )
+ snapshot = self._require_snapshot(registered_id, snapshot_id)
+ if snapshot.state is not IndexState.INDEX_READY:
+ raise IndexError(
+ snapshot.state.name,
+ "Fast Lane planning requires an INDEX_READY project index snapshot",
+ )
+ try:
+ include_paths = self._store.include_paths(snapshot.snapshot_id)
+ normalized_include_paths = self._normalize_paths(include_paths)
+ except (IndexError, StoreError, sqlite3.DatabaseError, ValueError) as exc:
+ raise IndexError(
+ "INDEX_CORRUPT", "project index include paths are corrupt"
+ ) from exc
+ if include_paths != normalized_include_paths:
+ raise IndexError(
+ "INDEX_CORRUPT", "project index include paths are not canonical"
+ )
+ git_head = _git_head(root)
+ if git_head is None:
+ raise IndexError(
+ "GIT_WORKSPACE_REQUIRED",
+ "Fast Lane planning requires a registered Git workspace",
+ )
+ if snapshot.head is None or snapshot.head.casefold() != git_head:
+ raise IndexError(
+ "INDEX_STALE",
+ "project index snapshot does not match the Git HEAD",
+ )
+ return {
+ **material,
+ "workspace_root": str(root),
+ "git_head": git_head,
+ "include_paths": include_paths,
+ "include_paths_hash": _opaque_hash({"include_paths": include_paths}),
+ }
+
def _public_query_projection(
self, workspace_id: str, receipt: QueryReceipt
) -> dict[str, object]:
diff --git a/mcp-tools/pyproject.toml b/mcp-tools/pyproject.toml
index fd9823d..e22f84b 100644
--- a/mcp-tools/pyproject.toml
+++ b/mcp-tools/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "2718lab-devkit-mcp"
-version = "1.1.3"
+version = "1.1.4"
description = "MCP runtime for the 2718lab DevKit primary plugin."
requires-python = ">=3.11"
dependencies = [
diff --git a/mcp-tools/server.py b/mcp-tools/server.py
index 1a6c546..4d04780 100644
--- a/mcp-tools/server.py
+++ b/mcp-tools/server.py
@@ -3,10 +3,7 @@
from __future__ import annotations
import atexit
-import hashlib
-import json
import os
-import secrets
import time
from collections.abc import Callable, Mapping
from pathlib import Path
@@ -362,45 +359,6 @@ def _current_index_correlation() -> str | None:
return value
-def _current_fastlane_intent_hash() -> str | None:
- """Read the Host call intent from current MCP metadata only."""
-
- try:
- meta = mcp.get_context().request_context.meta
- except (LookupError, ValueError):
- return None
- if meta is None or type(meta.model_extra) is not dict:
- return None
- value = meta.model_extra.get("2718lab/host-fastlane-intent-hash")
- if (
- type(value) is not str
- or len(value) != 64
- or any(character not in "0123456789abcdef" for character in value)
- ):
- return None
- return value
-
-
-def _current_fastlane_index_query_correlation() -> str | None:
- """Read the Host-selected Fast Lane query receipt from reserved metadata."""
-
- try:
- meta = mcp.get_context().request_context.meta
- except (LookupError, ValueError):
- return None
- if meta is None or type(meta.model_extra) is not dict:
- return None
- value = meta.model_extra.get("2718lab/host-fastlane-index-query-correlation")
- if (
- type(value) is not str
- or len(value) != 70
- or not value.startswith("index-")
- or any(character not in "0123456789abcdef" for character in value[6:])
- ):
- return None
- return value
-
-
def _sync_result_snapshot_id(value: object) -> str:
from project_index.models import IndexSyncResult
@@ -1011,346 +969,51 @@ def fastlane_compile(
reasoning_effort: Literal["low", "medium", "high", "xhigh", "max"],
enable: bool = False,
) -> dict[str, object]:
- """Compile inert Fast Lane descriptors without receiving host-private evidence.
+ """Compile a locally verified, side-effect-free Fast Lane writer plan.
- The host remains responsible for capability attestations, worktree/lease fencing,
- model dispatch, terminal receipts, and execution. This MCP boundary only
- validates and renders the deterministic local scheduling plan.
+ Caller workspace and snapshot identifiers are selectors only. A read-only
+ runtime UoW resolves them through the local registry, verifies the current
+ index and Git HEAD, and supplies private facts to the compiler. The result
+ never dispatches, creates a worktree, claims a lease, or authorizes execution.
"""
if type(request) is not dict or type(enable) is not bool:
return _failure("FASTLANE_REQUEST_INVALID")
- session = _host_session()
- intent_hash = _current_fastlane_intent_hash()
- index_query_correlation = _current_fastlane_index_query_correlation()
- from devkit_runtime.host_session import HostSession
-
- if type(session) is HostSession and session.is_available:
- if intent_hash is None or index_query_correlation is None or not enable:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- return _fastlane_authenticated_dispatch(
- request,
- reasoning_effort,
- call_intent_hash=intent_hash,
- index_query_correlation=index_query_correlation,
- )
- from devkit_fastlane import compile_fast_lane
- from devkit_runtime.tool_result import ResultContractError, envelope_success
-
- try:
- plan = compile_fast_lane(
- request,
- reasoning_effort=reasoning_effort,
- enable=enable,
- )
- return envelope_success(_fastlane_public_value(plan))
- except ResultContractError:
- return _failure("INTERNAL_ERROR")
- except (TypeError, ValueError):
- return _failure("FASTLANE_REQUEST_INVALID")
-
-
-def _fastlane_authenticated_dispatch(
- request: dict[str, object],
- reasoning_effort: str,
- *,
- call_intent_hash: str,
- index_query_correlation: str,
-) -> dict[str, object]:
- """Use no request-carried authority; the inherited bridge is the only gate."""
-
- from devkit_runtime.fastlane_host_adapter import (
- NO_SAFE_WORK,
- dispatch_fast_lane_with_host_facts,
- prepare_verified_host_facts,
+ from devkit_fastlane.scripts.team_efficiency import (
+ _compile_fast_lane_local_plan,
+ _fast_lane_local_selector,
+ _FastLaneLocalPlanError,
)
- from devkit_runtime.host_bridge import (
- FastLaneRefillRegistryRequest,
- OperationReceipt,
- )
- from devkit_runtime.host_session import HostRoute, HostSession
+ from devkit_runtime.config import RuntimeConfigError
from devkit_runtime.tool_result import ResultContractError, envelope_success
+ from project_index.models import IndexError as ProjectIndexError
try:
- if reasoning_effort == "ultra":
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- session = _host_session()
- if type(session) is not HostSession or not session.is_available:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- index_attestation = session.project_index_query_attestation(
- correlation_id=index_query_correlation
- )
- if index_attestation is None:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- index_context_hash = index_attestation.get("index_context_hash")
- if type(index_context_hash) is not str:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- project_binding = request.get("project_binding")
- work_package = request.get("work_package")
- if (
- type(project_binding) is not dict
- or type(work_package) is not dict
- or project_binding.get("workspace_id")
- != index_attestation.get("workspace_id")
- or work_package.get("input_snapshot_id")
- != index_attestation.get("snapshot_id")
- ):
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- preparation_id = f"compiler-{secrets.token_hex(16)}"
- capability_snapshot = session.resolve_capability_snapshot_v2(
- call_intent_hash=call_intent_hash,
- preparation_id=preparation_id,
- expires_at_ceiling=cast(int, index_attestation["expires_at"]),
- )
- if capability_snapshot is None:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- from devkit_fastlane.scripts.team_efficiency import (
- compile_authenticated_v5_assignment_skeletons,
- prepare_authenticated_v5_routing_from_request,
- validate_authenticated_v5_skeleton_package,
- )
-
- projected = prepare_authenticated_v5_routing_from_request(
- request,
- index_context_hash=index_context_hash,
- host_capabilities=capability_snapshot.host_capabilities,
- scheduler_facts=capability_snapshot.scheduler_facts,
- )
- routing_snapshot = session.resolve_routing_attestations(
- call_intent_hash=call_intent_hash,
- preparation_id=preparation_id,
- routing_requests=projected["all_routing_requests"],
- )
- if routing_snapshot is None:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- initial_units = projected["units"]
- remaining_units = projected["remaining_units"]
- initial_storage_budgets = {
- unit["task"]["task_id"]: unit["storage_budget"]
- for unit in initial_units
- if "storage_budget" in unit
- }
- # The compiler/profile exchange can attest only the live initial
- # skeletons. Remaining work is materialized later by the Host-owned
- # refill registry, which has no storage-profile proof channel yet.
- # Budgeted successors therefore fail closed before publication.
- if len(initial_storage_budgets) not in {0, len(initial_units)} or any(
- "storage_budget" in unit for unit in remaining_units
- ):
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- initial_task_ids = {unit["task"]["task_id"] for unit in initial_units}
- initial_requests: list[dict[str, object]] = []
- remaining_requests: list[dict[str, object]] = []
- for item in routing_snapshot.routing_requests:
- task = item.get("task")
- if type(task) is not dict:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- task_id = task.get("task_id")
- if type(task_id) is not str:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- if task_id in initial_task_ids:
- initial_requests.append(item)
- else:
- remaining_requests.append(item)
- initial_attestations = [
- item
- for item in routing_snapshot.attestations
- if item["task_id"] in initial_task_ids
- ]
- if len(initial_requests) != len(initial_units) or len(
- initial_attestations
- ) != len(initial_units):
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- compiled = compile_authenticated_v5_assignment_skeletons(
- initial_units,
- source_plan_hash=projected["source_plan_hash"],
- routing_requests=initial_requests,
- attestation_items=initial_attestations,
- )
- compiled_remaining = (
- compile_authenticated_v5_assignment_skeletons(
- remaining_units,
- source_plan_hash=projected["source_plan_hash"],
- routing_requests=remaining_requests,
- attestation_items=[
- item
- for item in routing_snapshot.attestations
- if item["task_id"] not in initial_task_ids
- ],
+ workspace_id, snapshot_id = _fast_lane_local_selector(request)
+ with _runtime_root().open_uow(read_only=True) as uow:
+ local_plan_material = (
+ uow.project_checkpoint.project_index.local_plan_material(
+ workspace_id,
+ snapshot_id=snapshot_id,
+ )
)
- if remaining_units
- else {"assignment_skeletons": [], "requested_route_pairs": []}
- )
- attestation_ref_fields = (
- "correlation_id",
- "workspace_id",
- "workspace_binding_hash",
- "root_identity_hash",
- "snapshot_id",
- "snapshot_attestation_hash",
- "query_receipt_hash",
- "index_context_hash",
- "attestation_hash",
- )
- raw_skeletons = compiled.get("assignment_skeletons")
- raw_remaining_skeletons = compiled_remaining.get("assignment_skeletons")
- if type(raw_skeletons) is not list or type(raw_remaining_skeletons) is not list:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- skeletons: list[dict[str, object]] = []
- remaining_skeletons: list[dict[str, object]] = []
- for raw_skeleton, destination in (
- (raw_skeletons, skeletons),
- (raw_remaining_skeletons, remaining_skeletons),
- ):
- for skeleton in raw_skeleton:
- if (
- type(skeleton) is not dict
- or type(skeleton.get("task_id")) is not str
- ):
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- destination.append(skeleton)
- skeleton_package_hash = validate_authenticated_v5_skeleton_package(
- projected["all_units"],
- skeletons,
- remaining_skeletons,
- source_plan_hash=projected["source_plan_hash"],
- )
- index_refs = [
- {
- "task_id": skeleton["task_id"],
- **{field: index_attestation[field] for field in attestation_ref_fields},
- }
- for skeleton in skeletons
- ]
- planner_request = {
- "schema": "2718lab-devkit/fastlane-host-planner-request-v1",
- "action": "plan_dispatch",
- "assignment_skeletons": skeletons,
- "project_index_attestation_refs": index_refs,
- }
- requested_route_pairs: set[tuple[str, str]] = set()
- for item in routing_snapshot.attestations:
- route = cast(dict[str, object], item["route"])
- model = route.get("model")
- effort = route.get("effort")
- if type(model) is not str or type(effort) is not str:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- requested_route_pairs.add((model, effort))
- requested_routes = tuple(
- HostRoute(model=model, effort=effort)
- for model, effort in sorted(requested_route_pairs)
- )
- prepared = prepare_verified_host_facts(
- session,
- preparation_id=preparation_id,
- call_intent_hash=call_intent_hash,
- routing_registry_binding_hash=(
- routing_snapshot.routing_registry_binding_hash
- ),
- request=planner_request,
- reasoning_effort=reasoning_effort,
- requested_routes=requested_routes,
- storage_budgets=initial_storage_budgets,
- )
- if prepared == NO_SAFE_WORK:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
- now = int(time.time())
- correlation_id = f"operation-{secrets.randbelow(999_999_999_999) + 1}"
-
- queue_registry = None
- if remaining_units:
- queue_registry = session.send_fast_lane_refill_registry(
- call_intent_hash=call_intent_hash,
- preparation_id=preparation_id,
- source_plan_hash=projected["source_plan_hash"],
- index_context_hash=index_context_hash,
- routing_registry_binding_hash=(
- routing_snapshot.routing_registry_binding_hash
- ),
- source_plan_task_ids=[
- unit["task"]["task_id"] for unit in projected["all_units"]
- ],
- initial_skeletons=skeletons,
- remaining_skeletons=remaining_skeletons,
- index_attestation_refs=[
- {
- "task_id": skeleton["task_id"],
- **{
- field: index_attestation[field]
- for field in attestation_ref_fields
- },
- }
- for skeleton in remaining_skeletons
- ],
- skeleton_package_hash=skeleton_package_hash,
- now=now,
- )
- if type(queue_registry) is not FastLaneRefillRegistryRequest:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
-
- def refill_callback(trigger: Mapping[str, object]) -> dict[str, object]:
- """Record the real next-boundary result for this fully dispatched plan."""
-
- request_hash = (
- "sha256:"
- + hashlib.sha256(
- json.dumps(
- request,
- ensure_ascii=False,
- sort_keys=True,
- separators=(",", ":"),
- allow_nan=False,
- ).encode("utf-8")
- ).hexdigest()
+ plan = _compile_fast_lane_local_plan(
+ request,
+ reasoning_effort=reasoning_effort,
+ enable=enable,
+ local_plan_material=local_plan_material,
)
- queued_ids = [skeleton["task_id"] for skeleton in remaining_skeletons]
- return {
- "schema": "2718lab-devkit/fastlane-refill-receipt-v1",
- "state": ("QUEUED_WAVE_PENDING" if queued_ids else "NO_QUEUED_WORK"),
- "request_hash": request_hash,
- "refill_trigger_hash": trigger["refill_trigger_hash"],
- "queue_registry_hash": (
- queue_registry.queue_registry_hash if queue_registry else None
- ),
- "queued_task_ids": queued_ids,
- }
-
- receipt = dispatch_fast_lane_with_host_facts(
- planner_request,
- reasoning_effort=reasoning_effort,
- verified_host_facts=prepared,
- correlation_id=correlation_id,
- now=now,
- refill_callback=refill_callback,
- )
- if type(receipt) is not OperationReceipt:
- return _failure("FASTLANE_HOST_DISPATCH_REJECTED")
- return envelope_success(
- {
- "state": "DISPATCH_COMMITTED",
- "task_id": receipt.task_id,
- "correlation_id": receipt.correlation_id,
- "dispatch_envelope_hash": receipt.envelope_hash,
- }
- )
+ return envelope_success(plan)
+ except _FastLaneLocalPlanError as error:
+ return _failure(error.code)
+ except ProjectIndexError as error:
+ return _failure(error.code)
+ except RuntimeConfigError as error:
+ return _runtime_failure(error)
except ResultContractError:
return _failure("INTERNAL_ERROR")
- except Exception:
- return _failure("FASTLANE_HOST_AUTHORITY_UNAVAILABLE")
-
-
-def _fastlane_public_value(value: object) -> object:
- """Remove compiler-only null sentinels before the no-null MCP envelope."""
-
- if type(value) is dict:
- return {
- key: _fastlane_public_value(item)
- for key, item in value.items()
- if item is not None
- }
- if type(value) is list:
- return [_fastlane_public_value(item) for item in value if item is not None]
- return value
+ except (TypeError, ValueError):
+ return _failure("FASTLANE_REQUEST_INVALID")
@mcp.tool(annotations=_tool_annotations("relay_start"))
diff --git a/mcp-tools/tests/test_bugkiller_metadata.py b/mcp-tools/tests/test_bugkiller_metadata.py
index 6192c4b..a7ff2bf 100644
--- a/mcp-tools/tests/test_bugkiller_metadata.py
+++ b/mcp-tools/tests/test_bugkiller_metadata.py
@@ -39,7 +39,7 @@ def test_primary_plugin_manifest_is_stable_v1_and_has_no_prompt_runtime_surface(
self,
) -> None:
codex = load_json(".codex-plugin/plugin.json")
- self.assertEqual("1.1.3", codex["version"])
+ self.assertEqual("1.1.4", codex["version"])
self.assertEqual("./.mcp.json", codex["mcpServers"])
for legacy_surface in ("skills", "agents", "commands", "hooks"):
self.assertNotIn(legacy_surface, codex)
diff --git a/mcp-tools/tests/test_fastlane_runtime.py b/mcp-tools/tests/test_fastlane_runtime.py
index 25c946e..ed642fe 100644
--- a/mcp-tools/tests/test_fastlane_runtime.py
+++ b/mcp-tools/tests/test_fastlane_runtime.py
@@ -1,13 +1,28 @@
from __future__ import annotations
+import copy
+import inspect
+import subprocess
import sys
+from contextlib import nullcontext
+from dataclasses import replace
from pathlib import Path
+from types import SimpleNamespace
+from typing import Any
+
+import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT / "mcp-tools"))
+import devkit_fastlane # noqa: E402
import server # noqa: E402
from devkit_fastlane.scripts import team_efficiency # noqa: E402
+from devkit_runtime.bootstrap import RuntimeBootstrap # noqa: E402
+from devkit_runtime.composition import RuntimeRoot # noqa: E402
+from devkit_runtime.config import RuntimeConfig # noqa: E402
+from project_index.models import IndexError as ProjectIndexError # noqa: E402
+from project_index.models import IndexState # noqa: E402
sys.path.insert(0, str(ROOT / "mcp-tools" / "devkit_fastlane" / "tests"))
@@ -23,6 +38,212 @@ def _sample_request() -> tuple[object, dict[str, object], object]:
return helper, helper.fast_lane_request(team_efficiency), tests
+def _install_local_plan_runtime(monkeypatch, helper, request) -> str:
+ """Install one read-only registry/index/Git projection for adapter tests."""
+
+ project_binding = request["project_binding"]
+ work_package = request["work_package"]
+ scheduler_state = request["scheduler_state"]
+ assert isinstance(project_binding, dict)
+ assert isinstance(work_package, dict)
+ assert isinstance(scheduler_state, dict)
+ integration_state = scheduler_state["integration_state"]
+ assert isinstance(integration_state, dict)
+ workspace_id = project_binding["workspace_id"]
+ snapshot_id = work_package["input_snapshot_id"]
+ git_head = integration_state["commit"]
+ assert isinstance(workspace_id, str)
+ assert isinstance(snapshot_id, str)
+ assert isinstance(git_head, str)
+
+ marker = team_efficiency._sha256_json
+ root_identity_hash = marker({"root": workspace_id})
+ workspace_binding_hash = marker(
+ {
+ "workspace_id": workspace_id,
+ "root_identity_hash": root_identity_hash,
+ }
+ )
+ head_hash = marker({"head": git_head})
+ manifest_hash = marker({"manifest": snapshot_id})
+ parser_set_hash = marker({"parsers": snapshot_id})
+ material = {
+ "workspace_id": workspace_id,
+ "root_identity_hash": root_identity_hash,
+ "workspace_binding_hash": workspace_binding_hash,
+ "snapshot_id": snapshot_id,
+ "snapshot_attestation_hash": marker(
+ {
+ "workspace_id": workspace_id,
+ "root_identity_hash": root_identity_hash,
+ "workspace_binding_hash": workspace_binding_hash,
+ "snapshot_id": snapshot_id,
+ "head_hash": head_hash,
+ "manifest_hash": manifest_hash,
+ "parser_set_hash": parser_set_hash,
+ }
+ ),
+ "head_hash": head_hash,
+ "manifest_hash": manifest_hash,
+ "parser_set_hash": parser_set_hash,
+ "workspace_root": str(helper.repo),
+ "git_head": git_head,
+ "include_paths": (),
+ "include_paths_hash": marker({"include_paths": ()}),
+ }
+
+ class LocalIndex:
+ def local_plan_material(
+ self, supplied_workspace_id: str, *, snapshot_id: str
+ ) -> dict[str, object]:
+ assert supplied_workspace_id == workspace_id
+ assert snapshot_id == material["snapshot_id"]
+ return dict(material)
+
+ unit_of_work = SimpleNamespace(
+ project_checkpoint=SimpleNamespace(project_index=LocalIndex())
+ )
+
+ def open_uow(*, read_only: bool):
+ assert read_only is True
+ return nullcontext(unit_of_work)
+
+ def host_session_forbidden() -> object:
+ raise AssertionError("Fast Lane must not consult an inherited Host session")
+
+ monkeypatch.setattr(
+ server, "_runtime_root", lambda: SimpleNamespace(open_uow=open_uow)
+ )
+ monkeypatch.setattr(server, "_host_session", host_session_forbidden, raising=False)
+ return snapshot_id
+
+
+def _git(repo: Path, *args: str) -> str:
+ completed = subprocess.run(
+ ["git", "-C", str(repo), *args],
+ check=True,
+ capture_output=True,
+ text=True,
+ )
+ return completed.stdout.strip()
+
+
+def _assert_no_nulls(value: object) -> None:
+ if isinstance(value, dict):
+ assert all(item is not None for item in value.values())
+ for item in value.values():
+ _assert_no_nulls(item)
+ elif isinstance(value, list):
+ assert all(item is not None for item in value)
+ for item in value:
+ _assert_no_nulls(item)
+
+
+def _request_for_persisted_snapshot(
+ helper,
+ *,
+ workspace_id: str,
+ snapshot_id: str,
+ git_head: str,
+) -> dict[str, object]:
+ authority = dict(helper.project_binding(team_efficiency))
+ authority["workspace_id"] = workspace_id
+ authority["input_snapshot_id"] = snapshot_id
+ original_project_binding = helper.project_binding
+ helper.project_binding = lambda _module, **_kwargs: dict(authority)
+ try:
+ request = helper.fast_lane_request(team_efficiency)
+ finally:
+ helper.project_binding = original_project_binding
+
+ source_plan = team_efficiency.decompose(request["work_package"])
+ units = {unit["task_id"]: unit for unit in source_plan["units"]}
+ scheduler_state = request["scheduler_state"]
+ assert isinstance(scheduler_state, dict)
+ integration_state = scheduler_state["integration_state"]
+ assert isinstance(integration_state, dict)
+ integration_state["commit"] = git_head
+ integration_state["tree"] = _git(helper.repo, "rev-parse", "HEAD^{tree}")
+ execution_contexts = request["execution_contexts"]
+ assert isinstance(execution_contexts, list)
+ for context in execution_contexts:
+ assert isinstance(context, dict)
+ task_id = context["task_id"]
+ unit = units[task_id]
+ bootstrap = context["bootstrap_plan"]
+ assert isinstance(bootstrap, dict)
+ context["bootstrap_plan"] = team_efficiency.build_bootstrap_plan(
+ task_id=task_id,
+ base_commit=git_head,
+ branch=bootstrap["branch"],
+ write_scope=unit["write_scope"],
+ repo=helper.repo,
+ project=bootstrap["project"],
+ worktree=bootstrap["worktree"],
+ temp_target=bootstrap["temp_target"],
+ )
+ context["workspace_input_snapshot_id"] = snapshot_id
+ return request
+
+
+def _install_persistent_local_plan_runtime(
+ monkeypatch,
+ helper,
+ *,
+ include_paths: list[str] | None = None,
+ partial: bool = False,
+) -> tuple[RuntimeRoot, dict[str, object], str]:
+ manifest = helper.decomposition_manifest()
+ source_plan = team_efficiency.decompose(manifest)
+ for unit in source_plan["units"]:
+ for scope in unit["write_scope"]:
+ target = helper.repo / scope
+ target.parent.mkdir(parents=True, exist_ok=True)
+ body = (
+ "def indexed_scope() -> bool:\n return True\n"
+ if target.suffix == ".py"
+ else "# Indexed scope\n"
+ )
+ target.write_text(body, encoding="utf-8")
+ if partial:
+ (helper.repo / "unsupported.js").write_text(
+ "export const unsupported = true;\n", encoding="utf-8"
+ )
+ _git(helper.repo, "init", "--quiet")
+ _git(helper.repo, "config", "user.name", "Fast Lane Test")
+ _git(helper.repo, "config", "user.email", "fastlane@example.invalid")
+ _git(helper.repo, "add", ".")
+ _git(helper.repo, "commit", "--quiet", "-m", "fixture")
+ git_head = _git(helper.repo, "rev-parse", "HEAD")
+
+ scratch = helper.temp / "runtime-scratch"
+ scratch.mkdir()
+ config = RuntimeConfig.load(
+ environ={
+ "PLUGIN_DATA": str(helper.temp / "runtime-data"),
+ "CODEX_TASK_TEMP": str(scratch),
+ }
+ )
+ RuntimeBootstrap.run(config)
+ root = RuntimeRoot(config)
+ monkeypatch.setattr(server, "_RUNTIME_ROOT", root)
+ registered = server.project_index_register(str(helper.repo))
+ assert registered["ok"] is True
+ workspace_id = registered["data"]["workspace_id"]
+ assert isinstance(workspace_id, str)
+ synced = server.project_index_sync(workspace_id, include_paths=include_paths)
+ assert synced["ok"] is True
+ snapshot_id = synced["data"]["snapshot_id"]
+ assert isinstance(snapshot_id, str)
+ request = _request_for_persisted_snapshot(
+ helper,
+ workspace_id=workspace_id,
+ snapshot_id=snapshot_id,
+ git_head=git_head,
+ )
+ return root, request, snapshot_id
+
+
def test_work_methodology_is_not_a_discoverable_skill() -> None:
"""Fast Lane contract lives in the MCP runtime, not prompt-discovered skills."""
@@ -32,6 +253,43 @@ def test_work_methodology_is_not_a_discoverable_skill() -> None:
assert (runtime / "scripts" / "team_efficiency.py").is_file()
+def test_fastlane_docs_describe_the_mcp_plan_v2_boundary() -> None:
+ contract = (ROOT / "mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md").read_text(
+ encoding="utf-8"
+ )
+ readmes = [
+ (ROOT / "README.md").read_text(encoding="utf-8"),
+ (ROOT / "README.zh-CN.md").read_text(encoding="utf-8"),
+ ]
+
+ for document in (contract, *readmes):
+ assert "team-efficiency/fast-lane-plan-v2" in document
+ assert "plan_only" in document
+ assert "include_paths" in contract
+ assert "INDEX_PARTIAL" in contract
+ assert "local_plan_material" not in contract
+
+
+def test_public_compiler_api_cannot_receive_local_authority_material() -> None:
+ assert (
+ "local_plan_material"
+ not in inspect.signature(team_efficiency.compile_fast_lane).parameters
+ )
+ assert not hasattr(devkit_fastlane, "fast_lane_local_selector")
+
+ helper, request, _ = _sample_request()
+ try:
+ with pytest.raises(TypeError):
+ devkit_fastlane.compile_fast_lane(
+ request,
+ reasoning_effort="max",
+ enable=True,
+ local_plan_material={},
+ )
+ finally:
+ helper.tearDown()
+
+
def test_fastlane_tool_rejects_host_private_inputs() -> None:
"""Host attestations stay private; public MCP receives only an inert request."""
@@ -47,26 +305,288 @@ def test_fastlane_tool_rejects_host_private_inputs() -> None:
assert result["error"]["code"] == "FASTLANE_REQUEST_INVALID"
-def test_fastlane_tool_never_spawns_or_executes() -> None:
+def test_fastlane_tool_never_spawns_or_executes(monkeypatch) -> None:
"""The MCP compiler emits descriptors; the host owns execution and refill."""
helper, request, _ = _sample_request()
+ _install_local_plan_runtime(monkeypatch, helper, request)
try:
result = server.fastlane_compile(
- request=request, reasoning_effort="ultra", enable=True
+ request=request, reasoning_effort="max", enable=False
)
finally:
helper.tearDown()
assert result["ok"] is True
data = result["data"]
- assert data["schema"] == "team-efficiency/fast-lane-plan-v1"
+ assert data["schema"] == "team-efficiency/fast-lane-plan-v2"
+ assert data["status"] == "inactive"
+ assert data["assignments"] == []
+ assert data["plan_only"] is True
+ assert data["dispatch_state"] == "not_dispatched"
+ assert data["execution_authorized"] is False
assert "host_actions" not in data
- assert data["workflow_policy"]["dispatch_protocol"] == {
- "schema": "team-efficiency/fast-lane-dispatch-protocol-v1",
- "tool": "collaboration.spawn_agent",
- "model_source": "assignment.host_dispatch.model",
- "reasoning_effort_source": "assignment.host_dispatch.reasoning_effort",
- "inherit_current_session_model": False,
- "require_explicit_route": True,
- "missing_route_action": "reject",
+ assert data["workflow_policy"]["compiler_side_effects"] is False
+
+
+def test_fastlane_tool_hashes_the_exact_normalized_inactive_plan(monkeypatch) -> None:
+ helper, request, _ = _sample_request()
+ _install_local_plan_runtime(monkeypatch, helper, request)
+ try:
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=False
+ )
+ finally:
+ helper.tearDown()
+
+ assert result["ok"] is True
+ data = result["data"]
+ _assert_no_nulls(data)
+ assert data["plan_hash"] == team_efficiency._sha256_json(
+ {key: value for key, value in data.items() if key != "plan_hash"}
+ )
+
+
+def test_fastlane_tool_hashes_the_exact_normalized_read_only_assignment(
+ monkeypatch,
+) -> None:
+ helper, _, _ = _sample_request()
+ request = helper.fast_lane_schedule_request(team_efficiency)
+ _install_local_plan_runtime(monkeypatch, helper, request)
+ try:
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ helper.tearDown()
+
+ assert result["ok"] is True, result
+ data = result["data"]
+ read_only = next(
+ assignment
+ for assignment in data["assignments"]
+ if assignment["role"] != "execution"
+ )
+ _assert_no_nulls(read_only)
+ assert read_only["plan_item_id"] == team_efficiency._sha256_json(
+ {key: value for key, value in read_only.items() if key != "plan_item_id"}
+ )
+ assert data["plan_hash"] == team_efficiency._sha256_json(
+ {key: value for key, value in data.items() if key != "plan_hash"}
+ )
+
+
+def test_fastlane_plan_v2_rejects_unknown_keys_at_each_contract_layer(
+ monkeypatch,
+) -> None:
+ helper, request, _ = _sample_request()
+ _install_local_plan_runtime(monkeypatch, helper, request)
+ try:
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ helper.tearDown()
+
+ assert result["ok"] is True
+ plan = result["data"]
+
+ def add_plan_key(value: dict[str, Any]) -> None:
+ value["unexpected"] = True
+
+ def add_assignment_key(value: dict[str, Any]) -> None:
+ value["assignments"][0]["unexpected"] = True
+
+ def add_worktree_key(value: dict[str, Any]) -> None:
+ value["assignments"][0]["worktree"]["unexpected"] = True
+
+ def add_policy_key(value: dict[str, Any]) -> None:
+ value["workflow_policy"]["unexpected"] = True
+
+ for mutate in (
+ add_plan_key,
+ add_assignment_key,
+ add_worktree_key,
+ add_policy_key,
+ ):
+ tampered = copy.deepcopy(plan)
+ mutate(tampered)
+ with pytest.raises(ValueError, match="unsupported fields"):
+ team_efficiency._validated_fast_lane_local_plan(tampered)
+
+
+def test_fastlane_tool_plans_writers_from_current_local_index_without_host(
+ monkeypatch,
+) -> None:
+ """A current local index is sufficient for a non-dispatched writer plan."""
+
+ helper, request, _ = _sample_request()
+ snapshot_id = _install_local_plan_runtime(monkeypatch, helper, request)
+ try:
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ helper.tearDown()
+
+ assert result["ok"] is True
+ data = result["data"]
+ assert data["schema"] == "team-efficiency/fast-lane-plan-v2"
+ assert data["status"] == "planned"
+ assert data["plan_only"] is True
+ assert data["dispatch_state"] == "not_dispatched"
+ assert data["execution_authorized"] is False
+ writers = [
+ assignment
+ for assignment in data["assignments"]
+ if assignment["role"] == "execution"
+ ]
+ assert writers
+ assert all(assignment["execution_state"] == "plan_only" for assignment in writers)
+ assert all(
+ assignment["dispatch_state"] == "not_dispatched" for assignment in writers
+ )
+ assert all(assignment["execution_authorized"] is False for assignment in writers)
+ assert all(assignment["lease_state"] == "unclaimed" for assignment in writers)
+ assert all(assignment["worktree"]["state"] == "planned" for assignment in writers)
+ assert all(
+ assignment["index_evidence"]["snapshot_id"] == snapshot_id
+ for assignment in writers
+ )
+ forbidden = {
+ "action",
+ "host_dispatch",
+ "assignment_token",
+ "dispatch_receipt",
+ "terminal_receipt",
}
+ assert all(forbidden.isdisjoint(assignment) for assignment in writers)
+ assert "host_status_unavailable" not in str(data)
+
+
+def test_fastlane_tool_uses_persisted_runtime_registry_index_and_git_head(
+ monkeypatch,
+) -> None:
+ helper, _, _ = _sample_request()
+ root = None
+ try:
+ root, request, snapshot_id = _install_persistent_local_plan_runtime(
+ monkeypatch, helper
+ )
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ if root is not None:
+ root.shutdown()
+ helper.tearDown()
+
+ assert result["ok"] is True
+ data = result["data"]
+ assert data["schema"] == "team-efficiency/fast-lane-plan-v2"
+ assert data["status"] == "planned"
+ assert data["index_evidence"]["snapshot_id"] == snapshot_id
+ assert data["index_evidence"]["include_paths_hash"].startswith("sha256:")
+ assert all(item["execution_state"] == "plan_only" for item in data["assignments"])
+
+
+def test_fastlane_tool_rejects_stale_persisted_snapshot(monkeypatch) -> None:
+ helper, _, _ = _sample_request()
+ root = None
+ try:
+ root, request, _ = _install_persistent_local_plan_runtime(monkeypatch, helper)
+ changed = helper.repo / "skills/work-methodology/scripts/team_efficiency.py"
+ changed.write_text(
+ "def changed_after_sync():\n return True\n", encoding="utf-8"
+ )
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ if root is not None:
+ root.shutdown()
+ helper.tearDown()
+
+ assert result["ok"] is False
+ assert result["error"]["code"] == "INDEX_STALE"
+
+
+def test_fastlane_tool_rejects_partial_persisted_snapshot(monkeypatch) -> None:
+ helper, _, _ = _sample_request()
+ root = None
+ try:
+ root, request, _ = _install_persistent_local_plan_runtime(
+ monkeypatch, helper, partial=True
+ )
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ if root is not None:
+ root.shutdown()
+ helper.tearDown()
+
+ assert result["ok"] is False
+ assert result["error"]["code"] == "INDEX_PARTIAL"
+
+
+@pytest.mark.parametrize(
+ "state",
+ [
+ IndexState.INDEX_PARTIAL,
+ IndexState.INDEX_STALE,
+ IndexState.INDEX_UNAVAILABLE,
+ IndexState.INDEX_CORRUPT,
+ IndexState.HISTORICAL_UNVERIFIED,
+ ],
+)
+def test_project_index_local_plan_material_requires_exact_ready_state(
+ monkeypatch, state: IndexState
+) -> None:
+ helper, _, _ = _sample_request()
+ root = None
+ try:
+ root, request, snapshot_id = _install_persistent_local_plan_runtime(
+ monkeypatch, helper
+ )
+ project_binding = request["project_binding"]
+ assert isinstance(project_binding, dict)
+ workspace_id = project_binding["workspace_id"]
+ assert isinstance(workspace_id, str)
+ with root.open_uow(read_only=True) as uow:
+ index = uow.project_checkpoint.project_index
+ ready = index._require_snapshot(workspace_id, snapshot_id)
+ non_ready = replace(ready, state=state)
+ monkeypatch.setattr(
+ index,
+ "_require_snapshot",
+ lambda supplied_workspace_id, supplied_snapshot_id: non_ready,
+ )
+ with pytest.raises(ProjectIndexError) as captured:
+ index.local_plan_material(workspace_id, snapshot_id=snapshot_id)
+ finally:
+ if root is not None:
+ root.shutdown()
+ helper.tearDown()
+
+ assert captured.value.code == state.name
+
+
+def test_fastlane_tool_rejects_snapshot_that_omits_a_writer_scope(monkeypatch) -> None:
+ helper, _, _ = _sample_request()
+ source_plan = team_efficiency.decompose(helper.decomposition_manifest())
+ first_scope = source_plan["units"][0]["write_scope"][0]
+ root = None
+ try:
+ root, request, _ = _install_persistent_local_plan_runtime(
+ monkeypatch, helper, include_paths=[first_scope]
+ )
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ finally:
+ if root is not None:
+ root.shutdown()
+ helper.tearDown()
+
+ assert result["ok"] is False
+ assert result["error"]["code"] == "INDEX_PARTIAL"
diff --git a/mcp-tools/tests/test_primary_artifact.py b/mcp-tools/tests/test_primary_artifact.py
index 0f59b97..8bc1a1d 100644
--- a/mcp-tools/tests/test_primary_artifact.py
+++ b/mcp-tools/tests/test_primary_artifact.py
@@ -231,14 +231,14 @@ def test_python_project_and_lock_use_pep440_stable_v1_metadata() -> None:
with project_path.open("rb") as project_file:
project = tomllib.load(project_file)
- assert project["project"]["version"] == "1.1.3"
+ assert project["project"]["version"] == "1.1.4"
assert project["project"]["dependencies"] == ["mcp[cli]>=1,<2"]
assert "devkit_atlas" in project["tool"]["pyright"]["include"]
assert "devkit_runtime" in project["tool"]["pyright"]["include"]
assert "code_atlas" not in project["tool"]["pyright"]["include"]
lock_text = lock_path.read_text(encoding="utf-8")
assert 'name = "2718lab-devkit-mcp"' in lock_text
- assert 'version = "1.1.3"' in lock_text
+ assert 'version = "1.1.4"' in lock_text
def test_two_builds_are_byte_identical_with_normalized_zip_metadata(
diff --git a/mcp-tools/uv.lock b/mcp-tools/uv.lock
index 96cd914..b33ed59 100644
--- a/mcp-tools/uv.lock
+++ b/mcp-tools/uv.lock
@@ -10,7 +10,7 @@ resolution-markers = [
[[package]]
name = "2718lab-devkit-mcp"
-version = "1.1.3"
+version = "1.1.4"
source = { virtual = "." }
dependencies = [
{ name = "mcp", extra = ["cli"] },