diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json
index 60c8949..37b27bd 100644
--- a/.codex-plugin/plugin.json
+++ b/.codex-plugin/plugin.json
@@ -1,6 +1,6 @@
{
"name": "2718lab-devkit",
- "version": "1.1.4",
+ "version": "1.1.5",
"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 a94ae82..9e1de5c 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.4"
+ placeholder: "v1.1.5"
validations:
required: true
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ccf7473..1213f69 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,34 @@ only after the CI and artifact checks pass.
## [Unreleased]
+## [1.1.5] - 2026-09-05
+
+### Added
+
+- Added the model-neutral `fast-lane-request-v2` / `work-package-v3` /
+ `fast-lane-plan-v3` path. New assignments describe complexity, capability,
+ effort, and cost requirements while the coordinator chooses from the model
+ IDs and efforts exposed by the current Codex dispatch tool.
+- Added public request preparation plus model-selection record helpers. A
+ selection record binds the exact model ID, effort, reason,
+ `requirement_hash`, and `plan_item_id` without claiming dispatch or model
+ availability.
+
+### Fixed
+
+- Future bounded model IDs, including an explicitly requested `gpt-6-astra`,
+ no longer require a DevKit model-name whitelist. Explicit model/effort intent
+ is hash-bound and cannot be silently replaced by a fallback route.
+- Reject mixed request/work-package versions in both directions; request-v1 is
+ paired with work-package-v2 and request-v2 with work-package-v3.
+
+### Security
+
+- Model-neutral plans remain `plan_only`, `not_dispatched`, and unauthorized;
+ the actual dispatch tool is the only availability gate and worker `ultra`
+ remains forbidden. Legacy v3/v4/v5 routing policy assets and legacy
+ request-v1/plan-v2 replay behavior are unchanged.
+
## [1.1.4] - 2026-09-04
### Added
diff --git a/README.md b/README.md
index 66888db..06e451d 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,27 @@
[简体中文](README.zh-CN.md)
-# 2718lab DevKit — Codex + MCP v1.1.4
+# 2718lab DevKit — Codex + MCP v1.1.5
-[](./.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.4 package.
+of reference manuals. This repository carries the versioned v1.1.5 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 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.
+`team-efficiency/fast-lane-plan-v1` preview. For new work, prepare
+`fast-lane-request-v2` with `prepare_model_neutral_fast_lane_request`; MCP
+`fastlane_compile` then resolves the workspace/snapshot selectors through its
+local RuntimeRoot and returns a verified `team-efficiency/fast-lane-plan-v3`.
+Its assignments describe requirements and leave model selection to the
+coordinator using current Codex tool metadata. Every descriptor remains
+`plan_only`: it never dispatches, claims a lease, creates a worktree, or
+authorizes execution. Request-v1/plan-v2 stays available for exact legacy replay.
The prior v1.1.3 storage-governance integration references compatible Host source only
on Ayleovelle's user-fork
@@ -61,12 +64,14 @@ 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 planning compiler. The MCP tool can emit bounded
- `team-efficiency/fast-lane-plan-v2` assignments only after its private
+- Fast Lane is a pure planning compiler. New model-neutral requests emit bounded
+ `team-efficiency/fast-lane-plan-v3` 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.
+ write-scope coverage. Assignments contain no default model name; the
+ coordinator records an exact model/effort choice before the dispatch tool
+ validates availability. 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
@@ -84,8 +89,9 @@ and continue to fail closed.
## Overall workflow
The repository workflow defaults to Fast Lane. `workflow-design` prepares a
-bounded input. MCP `fastlane_compile` verifies the persisted local project
-snapshot and returns a plan-v2 descriptor; `team_efficiency.py` retains the
+bounded model-neutral request-v2 input. MCP `fastlane_compile` verifies the
+persisted local project snapshot and returns a plan-v3 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.
@@ -98,7 +104,7 @@ flowchart TD
end
subgraph FAST["Fast Lane"]
F["fast-lane request"] --> G["MCP fastlane_compile
private RuntimeRoot verification"]
- G --> X["plan-v2
plan_only, not dispatched"]
+ G --> X["plan-v3 requirements
unselected, plan_only"]
F --> H["public Python / CLI"] --> I["plan-v1
NO_SAFE_WORK"]
end
B -->|MCP tools| C
@@ -179,7 +185,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.4.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output /2718lab-devkit-marketplace-v1.1.5.zip
## Install and run locally
@@ -226,7 +232,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.4.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.5.zip
The artifact contains the manifest, .mcp.json, LICENSE, the locked Python
project, and the runtime files selected by
@@ -337,18 +343,25 @@ 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 MCP `fastlane_compile`
-entry returns `team-efficiency/fast-lane-plan-v2` only after a read-only
+entry returns `team-efficiency/fast-lane-plan-v3` for a model-neutral request
+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`; the MCP output never dispatches a worker.
-- `team-efficiency/fast-lane-plan-v2` fixes `plan_only=true`,
+- `team-efficiency/fast-lane-plan-v3` fixes `plan_only=true`,
`dispatch_state="not_dispatched"`, and `execution_authorized=false`.
- Assignments use `team-efficiency/local-writer-plan-v1`; path-free
+ Assignments use `team-efficiency/local-writer-plan-v2`, with bounded
+ `route_requirements` and coordinator-owned `selection.state="unselected"`;
+ path-free
`index_evidence` includes snapshot/binding hashes, `include_paths_hash`, and
the compiled `scope_hash`.
+- `record_model_selection` binds `plan_item_id`, `requirement_hash`, the exact
+ model ID and effort, and the coordinator's reason. It is a `selection_only`,
+ `not_dispatched` record; the dispatch tool remains the availability gate.
+ An explicit request intent cannot be replaced by a fallback model.
- `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
@@ -395,7 +408,7 @@ freeze a transient regression count.
## Version
-This repository represents the versioned v1.1.4 package. Release notes are
+This repository represents the versioned v1.1.5 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 be8c255..71f475c 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -1,21 +1,23 @@
[English](README.md)
-# 2718lab DevKit —— Codex + MCP v1.1.4
+# 2718lab DevKit —— Codex + MCP v1.1.5
-[](./.codex-plugin/plugin.json)
+[](./.codex-plugin/plugin.json)
[](LICENSE)
2718lab DevKit 是一个 Codex-first 工程工具包:它包含一个本地、仅 stdio
传输的 MCP 运行时,用于有边界的项目索引、Atlas 证据、Relay 生命周期协调和
确定性的 Fast Lane 规划;同时还包含一组精简的 Skill 说明书。本仓库承载版本化的
-v1.1.4 包;已提交的 manifest 和 allowlist 定义可执行运行时范围,说明书导航、
+v1.1.5 包;已提交的 manifest 和 allowlist 定义可执行运行时范围,说明书导航、
安装、构建和验证章节共同给出支持的工作流。
公共 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 或授权执行。
+`team-efficiency/fast-lane-plan-v1` 预览。新任务先用
+`prepare_model_neutral_fast_lane_request` 准备 `fast-lane-request-v2`;MCP
+`fastlane_compile` 再通过本地 RuntimeRoot 解析 workspace/snapshot selector,并返回
+已验证的 `team-efficiency/fast-lane-plan-v3`。assignment 只描述需求,由协调器根据
+本次 Codex 工具 metadata 选择模型。描述符仍固定为 `plan_only`:不会派发、领取
+lease、创建 worktree 或授权执行。request-v1/plan-v2 仅保留精确历史重放。
此前 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)
@@ -47,11 +49,12 @@ stock Codex Host 没有经过证明的 protected broker,继续 fail-closed。
静态 prompt agent 或模型运行器。
- 可选的 Codex Skill bundle 是 DevKit 的说明书表面,提供简短的模块化手册;
它不构成第二个运行时,也不是可执行的 prompt/agent 表面。
-- Fast Lane 是纯规划编译器。只有 server 私有 RuntimeRoot 验证已注册的
+- Fast Lane 是纯规划编译器。新 model-neutral request 只有在 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 诊断面。
+ 产出有界的 `team-efficiency/fast-lane-plan-v3` assignments。assignment 不带
+ 默认模型名;协调器先记录 exact model/effort,再由 dispatch tool 校验可用性。
+ 所有结果仍为 `plan_only`,不执行 agent、Git 命令、lease 或 worktree 动作。
+ 公共 Python 编译器/CLI 继续作为无 authority 的 plan-v1 诊断面。
## 核心模块速览
@@ -68,8 +71,9 @@ stock Codex Host 没有经过证明的 protected broker,继续 fail-closed。
## 整体工作流
-仓库级默认工作流是 Fast Lane。`workflow-design` 准备有界输入;MCP
-`fastlane_compile` 验证持久化本地项目 snapshot 后返回 plan-v2 描述符,
+仓库级默认工作流是 Fast Lane。`workflow-design` 准备有界的 model-neutral
+request-v2 输入;MCP `fastlane_compile` 验证持久化本地项目 snapshot 后返回
+plan-v3 描述符,
`team_efficiency.py` 则保留被阻断的 plan-v1 诊断路径。两条路径都不会启动 agent,
也不会创建或执行跨会话工作树。协调器必须另行验证 route availability、领取 lease
并派发所选工作。
@@ -82,7 +86,7 @@ flowchart TD
end
subgraph FAST["Fast Lane"]
F["fast-lane request"] --> G["MCP fastlane_compile
私有 RuntimeRoot 验证"]
- G --> X["plan-v2
plan_only,未派发"]
+ G --> X["plan-v3 requirements
未选择,plan_only"]
F --> H["公共 Python / CLI"] --> I["plan-v1
NO_SAFE_WORK"]
end
B -->|MCP 工具| C
@@ -157,7 +161,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.4.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output /2718lab-devkit-marketplace-v1.1.5.zip
## 本地安装与运行
@@ -197,7 +201,7 @@ RELAY_CAPABILITY_BROKER_UNAVAILABLE。服务器不会暴露原始 handle,也
allowlist builder 会在插件源码树之外生成确定性的 ZIP。请选择源码树之外的输出目录:
- python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.4.zip
+ python .codex-plugin/build_main_artifact.py --plugin-root . --output /2718lab-devkit-v1.1.5.zip
产物包含 manifest、.mcp.json、LICENSE、锁定的 Python 项目,以及
.codex-plugin/main-artifact-allowlist.json 选中的运行时文件。它的可执行运行时
@@ -293,16 +297,21 @@ Fast Lane 编译器位于
mcp-tools/devkit_fastlane/scripts/fastlane_routing.py 和
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`、
+model-neutral request 返回 `team-efficiency/fast-lane-plan-v3`。snapshot 必须
+current、处于 `INDEX_READY`、
绑定仓库 Git HEAD,且持久化 `include_paths` 完整覆盖每个 writer `write_scope`。
- `reasoning_effort` 必填且只接受 `low`、`medium`、`high`、`xhigh` 或
`max`;MCP 输出永不派发 worker。
-- `team-efficiency/fast-lane-plan-v2` 固定 `plan_only=true`、
+- `team-efficiency/fast-lane-plan-v3` 固定 `plan_only=true`、
`dispatch_state="not_dispatched"`、`execution_authorized=false`。
- assignment 使用 `team-efficiency/local-writer-plan-v1`;无路径的
+ assignment 使用 `team-efficiency/local-writer-plan-v2`,包含有界
+ `route_requirements` 与协调器负责的 `selection.state="unselected"`;无路径的
`index_evidence` 包含 snapshot/binding hashes、`include_paths_hash` 与已编译
`scope_hash`。
+- `record_model_selection` 绑定 `plan_item_id`、`requirement_hash`、exact model ID、
+ effort 与协调器选择理由。该记录仍为 `selection_only/not_dispatched`,可用性只由
+ dispatch tool 校验;显式请求的模型不得被 fallback 替换。
- filesystem 或 Git 漂移返回 `INDEX_STALE`;snapshot 本身 partial,或其 include
roots 遗漏任一 writer scope,均返回 `INDEX_PARTIAL`。
- caller ID 只是 selector,不是 authority material。公共 MCP request 与公共
@@ -342,7 +351,7 @@ CI 和全新产物检查才是当前测试计数的唯一来源。它们验证
## 版本
-本仓库代表版本化的 v1.1.4 包。发布说明见
+本仓库代表版本化的 v1.1.5 包。发布说明见
[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 59a374b..6855942 100644
--- a/mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md
+++ b/mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md
@@ -100,7 +100,8 @@ does not weaken host capability, lease, worktree, review, or safety gates.
状态的 Fast Lane 编译调用,遇到 v1 必须返回 `NO_SAFE_WORK` 和
`LEGACY_PROJECT_UNBOUND`,零 assignment、零队列、零外部派发。
-未来外部 Desktop bridge 如要消费的载荷必须是 `team-efficiency/work-package-v2` exact-key envelope,包含原始 canonical v1
+legacy request-v1 bridge 消费 `team-efficiency/work-package-v2` exact-key envelope;
+新 request-v2 使用下述同边界的 work-package-v3。两者都包含原始 canonical v1
`package`、其 `package_payload_hash`、`project_fence`(仅 `project_id`、
`binding_digest`、`binding_version`)、`workspace_id` 与 `input_snapshot_id`。V2 的
source-plan hash 必须包含该整个 binding,因此相同 task/workflow 在不同项目、workspace 或输入
@@ -132,7 +133,7 @@ server-private 编译在创建任何 planned assignment 前必须同时证明:
Git 漂移返回 `INDEX_STALE`;binding、root、snapshot 或 HEAD 错配必须 fail closed,不能产生
部分计划。
-成功响应 schema 为 `team-efficiency/fast-lane-plan-v2`。顶层固定
+legacy request-v1 的成功响应 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` 使用
@@ -141,6 +142,46 @@ hash、`include_paths_hash`、所有 writer scopes 的 `scope_hash` 与最终 `e
registry root、raw Git HEAD 或 include path 文本。`workflow_policy` 只说明协调器后续必须显式
验证 route、领取 lease 并调用 dispatch tool;它不是执行许可,编译器也不调用该工具。
+#### Model-neutral 新任务入口(V3)
+
+新任务默认使用 `team-efficiency/fast-lane-request-v2`,并与
+`team-efficiency/work-package-v3` exact-key 配对;request-v1 只能与
+work-package-v2 配对。两个方向的版本混配都返回 invalid。work-package-v3 保留原
+project authority、payload hash 与全部 local registry/index/Git 安全边界,但它生成
+`decomposition-plan-v2`:unit 不再公开带品牌的 `recommended_route`,而是携带
+`model-route-requirements-v1`。
+
+现有 request-v1 可显式转换为新入口(命令只生成 JSON,不授予 authority):
+
+```text
+cd mcp-tools
+uv run --locked python -c "import json,sys; from devkit_fastlane import prepare_model_neutral_fast_lane_request as prepare; request=json.load(open(sys.argv[1], encoding='utf-8')); print(json.dumps(prepare(request), ensure_ascii=False, sort_keys=True))" request-v1.json
+```
+
+MCP `fastlane_compile` 对该请求返回 `team-efficiency/fast-lane-plan-v3`,assignment
+schema 为 `team-efficiency/local-writer-plan-v2`。每个 assignment 包含
+`route_requirements`(complexity、capability tags、effort/cost preference、worker
+ultra 禁令、可选 exact explicit intent)以及
+`selection={state:"unselected", owner:"coordinator",
+catalog_source:"codex_tool_metadata", availability_gate:"dispatch_tool"}`。
+`unselected` 是正常 planned 状态,不因没有 Host 或持久 catalog 而 blocked;协调器只根据
+本次 Codex dispatch tool 暴露的 metadata 做判断。DevKit 不实现 model rank、品牌白名单、
+catalog 服务或 availability authority。
+
+协调器选定路线后调用公开 `record_model_selection`。生成的
+`model-selection-record-v1` 绑定 assignment 的 `plan_item_id`、`requirement_hash`、exact
+`model_id`、`reasoning_effort` 与选择理由,且固定
+`execution_state="selection_only"`、`dispatch_state="not_dispatched"`、
+`execution_authorized=false`。任何 bounded model ID 均可记录;effort 必须是 dispatch tool
+支持的标准值且 worker 禁止 `ultra`。如果 request 已指定 exact model/effort,记录必须完全
+相同,否则拒绝,不能 silent fallback。记录本身不证明模型可用,真实 dispatch tool 仍是唯一
+availability gate。
+
+request-v2 的完整 canonical request hash 进入 plan-v3,explicit intent 又进入
+`requirement_hash` 与 `plan_item_id`,从而选择记录可被精确重放。旧
+request-v1/work-package-v2、plan-v2、`fastlane_routing.py` v3/v4/v5 policy/hash 与旧 receipt
+validator 继续按原字节和语义重放,不用新规则解释历史记录。
+
同一限制覆盖 `bootstrap --apply` 及 import-callable `apply_bootstrap_plan`:当前公开入口在构建
caller-supplied bootstrap plan 或调用 worktree mutation 前,无条件以
`NO_SAFE_WORK/PROJECT_AUTHORITY_UNAVAILABLE` 失败关闭,因而不能到达
@@ -165,10 +206,10 @@ probe 或 coordinator gate。
python scripts/team_efficiency.py fast-lane --input --host-status --reasoning-effort ultra
```
-`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。
+`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`;新 request-v2 在 `enable=true` 时返回上述 plan-v3,legacy request-v1 仍返回 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 contract;它们不由当前 MCP `fastlane_compile` 调用,也不能把 plan-v2/plan-v3 变成 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/__init__.py b/mcp-tools/devkit_fastlane/__init__.py
index 5458cd0..aeee314 100644
--- a/mcp-tools/devkit_fastlane/__init__.py
+++ b/mcp-tools/devkit_fastlane/__init__.py
@@ -6,7 +6,7 @@
MCP server does not import subprocess or host execution helpers.
"""
-from collections.abc import Mapping
+from collections.abc import Mapping, Sequence
from typing import Any
@@ -29,4 +29,52 @@ def compile_fast_lane(
)
-__all__ = ["compile_fast_lane"]
+def record_model_selection(
+ assignment: Mapping[str, Any],
+ *,
+ model_id: str,
+ reasoning_effort: str,
+ selection_reason: str,
+) -> dict[str, Any]:
+ """Record an exact coordinator choice without claiming dispatch."""
+
+ from .scripts.team_efficiency import record_model_selection as _record
+
+ return _record(
+ assignment,
+ model_id=model_id,
+ reasoning_effort=reasoning_effort,
+ selection_reason=selection_reason,
+ )
+
+
+def prepare_model_neutral_fast_lane_request(
+ request: Mapping[str, Any],
+ *,
+ route_intents: Sequence[Mapping[str, Any]] | None = None,
+) -> dict[str, Any]:
+ """Prepare the default model-neutral Fast Lane request schema."""
+
+ from .scripts.team_efficiency import (
+ prepare_model_neutral_fast_lane_request as _prepare,
+ )
+
+ return _prepare(request, route_intents=route_intents)
+
+
+def validate_model_selection_record(
+ record: Mapping[str, Any], *, assignment: Mapping[str, Any]
+) -> dict[str, Any]:
+ """Validate a selection record against its planned assignment."""
+
+ from .scripts.team_efficiency import validate_model_selection_record as _validate
+
+ return _validate(record, assignment=assignment)
+
+
+__all__ = [
+ "compile_fast_lane",
+ "prepare_model_neutral_fast_lane_request",
+ "record_model_selection",
+ "validate_model_selection_record",
+]
diff --git a/mcp-tools/devkit_fastlane/scripts/team_efficiency.py b/mcp-tools/devkit_fastlane/scripts/team_efficiency.py
index 591f33c..e73d7a8 100644
--- a/mcp-tools/devkit_fastlane/scripts/team_efficiency.py
+++ b/mcp-tools/devkit_fastlane/scripts/team_efficiency.py
@@ -157,6 +157,7 @@
"scheduler_state",
}
)
+_FAST_LANE_REQUEST_V2_FIELDS = _FAST_LANE_REQUEST_FIELDS | frozenset({"route_intents"})
_FAST_LANE_REQUEST_HOST_PRIVATE_FIELDS = frozenset(
{
"host_status",
@@ -189,6 +190,9 @@
)
_PROJECT_FENCE_SCHEMA = "team-efficiency/project-fence-v1"
_WORK_PACKAGE_V2_SCHEMA = "team-efficiency/work-package-v2"
+_WORK_PACKAGE_V3_SCHEMA = "team-efficiency/work-package-v3"
+_FAST_LANE_REQUEST_V2_SCHEMA = "team-efficiency/fast-lane-request-v2"
+_ROUTE_INTENT_FIELDS = frozenset({"task_id", "role", "model_id", "reasoning_effort"})
_PROJECT_BINDING_SCHEMA = "2718lab-devkit/project-binding-v1"
_BOOTSTRAP_ATTESTATION_SCHEMA = "2718lab-devkit/new-project-bootstrap-attestation-v1"
_PROJECT_BINDING_FIELDS = frozenset(
@@ -755,6 +759,7 @@
"plan_hash",
}
)
+_LOCAL_PLAN_V3_FIELDS = _LOCAL_PLAN_V2_FIELDS | frozenset({"request_hash"})
_LOCAL_PLAN_ASSIGNMENT_FIELDS = frozenset(
{
"schema",
@@ -780,6 +785,27 @@
"plan_item_id",
}
)
+_LOCAL_PLAN_ASSIGNMENT_V2_FIELDS = frozenset(
+ {
+ "schema",
+ "slot_id",
+ "task_id",
+ "role",
+ "goal",
+ "output_boundary",
+ "execution_state",
+ "dispatch_state",
+ "execution_authorized",
+ "lease_state",
+ "worktree",
+ "route_requirements",
+ "selection",
+ "depends_on",
+ "required_evidence",
+ "index_evidence",
+ "plan_item_id",
+ }
+)
_LOCAL_PLAN_WORKTREE_FIELDS = frozenset(
{
"state",
@@ -803,6 +829,49 @@
"compiler_side_effects",
}
)
+_LOCAL_PLAN_POLICY_V2_FIELDS = _LOCAL_PLAN_POLICY_FIELDS | frozenset(
+ {"selection_owner", "catalog_source", "availability_gate", "selection_record"}
+)
+_ROUTE_REQUIREMENT_FIELDS = frozenset(
+ {
+ "schema",
+ "complexity",
+ "capability_tags",
+ "effort_preference",
+ "cost_preference",
+ "worker_ultra_forbidden",
+ "explicit_intent",
+ "requirement_hash",
+ }
+)
+_MODEL_SELECTION_FIELDS = frozenset(
+ {
+ "schema",
+ "state",
+ "owner",
+ "catalog_source",
+ "availability_gate",
+ "record_schema",
+ }
+)
+_MODEL_SELECTION_RECORD_FIELDS = frozenset(
+ {
+ "schema",
+ "plan_item_id",
+ "requirement_hash",
+ "model_id",
+ "reasoning_effort",
+ "selection_reason",
+ "availability_gate",
+ "execution_state",
+ "dispatch_state",
+ "execution_authorized",
+ "selection_record_hash",
+ }
+)
+_MODEL_NEUTRAL_WORKER_EFFORTS = frozenset(
+ {"none", "minimal", "low", "medium", "high", "xhigh", "max"}
+)
_LOCAL_PLAN_INDEX_EVIDENCE_FIELDS = frozenset(
{
"schema",
@@ -1103,6 +1172,17 @@ def _validated_work_package_v2(value: object) -> dict[str, Any]:
}
+def _validated_work_package_v3(value: object) -> dict[str, Any]:
+ """Validate the model-neutral envelope without changing V2 replay bytes."""
+
+ source = _mapping(value, "work-package v3 envelope")
+ _exact_keys(source, _WORK_PACKAGE_V2_FIELDS, "work-package v3 envelope")
+ if source["schema"] != _WORK_PACKAGE_V3_SCHEMA:
+ raise ValueError("work-package v3 schema is invalid")
+ legacy_shape = {**dict(source), "schema": _WORK_PACKAGE_V2_SCHEMA}
+ return _validated_work_package_v2(legacy_shape)
+
+
def _validated_project_binding(value: object) -> dict[str, Any]:
"""Validate Task 2's exact opaque project-binding-v1 wrapper locally."""
@@ -1244,8 +1324,17 @@ def _project_execution_block_details(
return "BOOTSTRAP_ATTESTATION_REQUIRED", None
try:
- _exact_keys(raw_request, _FAST_LANE_REQUEST_FIELDS, "fast-lane request")
- if raw_request["schema"] != "team-efficiency/fast-lane-request-v1":
+ request_schema = raw_request.get("schema")
+ request_fields = (
+ _FAST_LANE_REQUEST_V2_FIELDS
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA
+ else _FAST_LANE_REQUEST_FIELDS
+ )
+ _exact_keys(raw_request, request_fields, "fast-lane request")
+ if request_schema not in {
+ "team-efficiency/fast-lane-request-v1",
+ _FAST_LANE_REQUEST_V2_SCHEMA,
+ }:
return "PROJECT_BINDING_INVALID", None
if len(_json_bytes(raw_request)) > MAX_MANIFEST_INPUT_BYTES:
return "PROJECT_BINDING_INVALID", None
@@ -1257,14 +1346,26 @@ def _project_execution_block_details(
return "PROJECT_BINDING_INVALID", None
if package.get("schema") == "team-efficiency/work-package-v1":
return "LEGACY_PROJECT_UNBOUND", None
- if package.get("schema") == _WORK_PACKAGE_V2_SCHEMA:
+ package_schema = package.get("schema")
+ if package_schema in {_WORK_PACKAGE_V2_SCHEMA, _WORK_PACKAGE_V3_SCHEMA}:
+ expected_package_schema = (
+ _WORK_PACKAGE_V3_SCHEMA
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA
+ else _WORK_PACKAGE_V2_SCHEMA
+ )
+ if package_schema != expected_package_schema:
+ return "PROJECT_BINDING_INVALID", None
try:
- v2 = _validated_work_package_v2(package)
+ envelope = (
+ _validated_work_package_v3(package)
+ if package_schema == _WORK_PACKAGE_V3_SCHEMA
+ else _validated_work_package_v2(package)
+ )
# Validate the canonical V1 payload before classifying the V2
# envelope as merely missing external authority. This is a pure
# diagnostic parse: it cannot reach scheduler, host, or index,
# worktree, or dispatch logic.
- _decompose_v1(v2["package"])
+ _decompose_v1(envelope["package"])
except (TypeError, ValueError):
return "PROJECT_BINDING_INVALID", None
try:
@@ -1274,11 +1375,11 @@ def _project_execution_block_details(
except (TypeError, ValueError):
return "BOOTSTRAP_ATTESTATION_UNKNOWN", None
if (
- binding["workspace_id"] != v2["project_authority"]["workspace_id"]
+ binding["workspace_id"] != envelope["project_authority"]["workspace_id"]
or binding["project_id"]
- != f"sha256:{v2['project_authority']['project_id']}"
+ != f"sha256:{envelope['project_authority']['project_id']}"
or binding["attestation"]["attested_input_snapshot_id"]
- != v2["project_authority"]["input_snapshot_id"]
+ != envelope["project_authority"]["input_snapshot_id"]
):
return "BOOTSTRAP_ATTESTATION_MISMATCH", None
if binding["mode"] == "new_empty_bootstrap":
@@ -1310,8 +1411,8 @@ def _project_execution_block_details(
"PROJECT_AUTHORITY_UNAVAILABLE",
{
"schema": "team-efficiency/project-fence-blocked-v2",
- "package_payload_hash": v2["package_payload_hash"],
- "project_authority": v2["project_authority"],
+ "package_payload_hash": envelope["package_payload_hash"],
+ "project_authority": envelope["project_authority"],
},
)
return "PROJECT_BINDING_INVALID", None
@@ -3895,6 +3996,18 @@ def _fast_lane_assignment(
epoch = int(state.get("slot_epochs", {}).get(slot_id, 0)) + 1
task_id = str(unit["task_id"])
context = _fast_lane_build_dispatch_context(validated, unit, role)
+ if "route_requirements" in route:
+ return {
+ "slot_id": slot_id,
+ "action": "start",
+ "task_id": task_id,
+ "role": role,
+ "assignment_epoch": epoch,
+ "context_hash": context["context_hash"],
+ "route_requirements": dict(route["route_requirements"]),
+ "selection": dict(route["selection"]),
+ "_context": context,
+ }
receipt = {
"schema": "team-efficiency/fast-lane-dispatch-receipt-v1",
"source_plan_hash": validated["source_plan_hash"],
@@ -4471,7 +4584,9 @@ def _registration_plan(
"workflow_id": _host_binding("workflow_id"),
"task_id": unit["task_id"],
"title": unit["goal"],
- "owner_role": unit["recommended_route"],
+ "owner_role": unit.get(
+ "recommended_route", "coordinator_model_selection"
+ ),
"card": card,
"dependencies": list(unit["depends_on"]),
"write_scope": list(unit["write_scope"]),
@@ -4649,6 +4764,124 @@ def _scheduled_plan(
}
+def _route_requirements(
+ complexity: str,
+ *,
+ role: str = "execution",
+ explicit_intent: Mapping[str, Any] | None = None,
+) -> dict[str, Any]:
+ """Describe task needs without naming a model or claiming availability."""
+
+ if complexity not in {"routine", "moderate", "complex", "exceptional"}:
+ raise ValueError("route requirement complexity is invalid")
+ capability_tags = {
+ "routine": {"bounded_task_execution"},
+ "moderate": {"multi_step_task_execution"},
+ "complex": {"complex_task_execution", "cross_module_reasoning"},
+ "exceptional": {"highest_available_capability", "deep_reasoning"},
+ }[complexity]
+ if role == "design_probe":
+ capability_tags.update({"architecture_design", "highest_available_capability"})
+ complexity = "exceptional"
+ elif role == "review":
+ capability_tags.add("independent_review")
+ elif role == "verification":
+ capability_tags.add("verification")
+ elif role == "prewarm":
+ capability_tags.add("read_only_prewarm")
+ effort_preference = {
+ "routine": "medium",
+ "moderate": "high",
+ "complex": "max",
+ "exceptional": "max",
+ }[complexity]
+ cost_preference = {
+ "routine": "cost_efficient",
+ "moderate": "balanced",
+ "complex": "capability_first",
+ "exceptional": "capability_first",
+ }[complexity]
+ intent = (
+ {"state": "unspecified"}
+ if explicit_intent is None
+ else {
+ "state": "required",
+ "model_id": explicit_intent["model_id"],
+ "reasoning_effort": explicit_intent["reasoning_effort"],
+ }
+ )
+ requirement: dict[str, Any] = {
+ "schema": "team-efficiency/model-route-requirements-v1",
+ "complexity": complexity,
+ "capability_tags": sorted(capability_tags),
+ "effort_preference": effort_preference,
+ "cost_preference": cost_preference,
+ "worker_ultra_forbidden": True,
+ "explicit_intent": intent,
+ }
+ requirement["requirement_hash"] = _sha256_json(requirement)
+ return requirement
+
+
+def _model_neutral_source_plan(
+ legacy_plan: Mapping[str, Any], package: Mapping[str, Any]
+) -> dict[str, Any]:
+ """Project a new source-plan schema while leaving legacy replay untouched."""
+
+ if legacy_plan.get("status") != "planned":
+ result = dict(legacy_plan)
+ result["schema"] = "team-efficiency/decomposition-plan-v2"
+ if result.get("reason") == "Semantic decomposition requires Sol-owned design.":
+ result["reason"] = (
+ "Semantic decomposition requires coordinator-owned design."
+ )
+ return result
+ artifact_complexities = {
+ str(item.get("task_id")): str(item.get("complexity"))
+ for item in package.get("artifacts", [])
+ if isinstance(item, Mapping)
+ }
+ legacy_units = {
+ str(item["task_id"]): item
+ for item in legacy_plan.get("units", [])
+ if isinstance(item, Mapping)
+ }
+ units: list[dict[str, Any]] = []
+ for task_id, old in sorted(legacy_units.items()):
+ complexity = artifact_complexities.get(task_id)
+ if complexity not in {"routine", "moderate", "complex", "exceptional"}:
+ complexity = (
+ "moderate" if old.get("unit_kind") == "verification" else "routine"
+ )
+ unit = {
+ key: json.loads(_canonical_json(value))
+ for key, value in old.items()
+ if key != "recommended_route"
+ }
+ unit["route_requirements"] = _route_requirements(complexity)
+ units.append(unit)
+ unit_by_id = {unit["task_id"]: unit for unit in units}
+ waves = [
+ [unit_by_id[str(item["task_id"])] for item in wave]
+ for wave in legacy_plan.get("waves", [])
+ ]
+ return {
+ **{
+ key: json.loads(_canonical_json(value))
+ for key, value in legacy_plan.items()
+ if key not in {"schema", "units", "waves", "registration_plan"}
+ },
+ "schema": "team-efficiency/decomposition-plan-v2",
+ "units": units,
+ "waves": waves,
+ "registration_plan": _registration_plan(
+ units,
+ waves,
+ strict_index=legacy_plan.get("source_kind") in _ATLAS_SOURCE_KINDS,
+ ),
+ }
+
+
def _decompose_v1(manifest: Mapping[str, Any]) -> dict[str, Any]:
"""Compile manual boundaries or verified Code Atlas evidence into safe waves."""
@@ -4785,6 +5018,14 @@ def decompose(manifest: Mapping[str, Any]) -> dict[str, Any]:
"""
source = _mapping(manifest, "work-package manifest")
+ if source.get("schema") == _WORK_PACKAGE_V3_SCHEMA:
+ v3 = _validated_work_package_v3(source)
+ plan = _model_neutral_source_plan(_decompose_v1(v3["package"]), v3["package"])
+ return {
+ **plan,
+ "project_authority": v3["project_authority"],
+ "package_payload_hash": v3["package_payload_hash"],
+ }
if source.get("schema") != _WORK_PACKAGE_V2_SCHEMA:
return _decompose_v1(source)
v2 = _validated_work_package_v2(source)
@@ -4809,6 +5050,13 @@ def _fast_lane_effort(value: object) -> str:
return effort
+def _model_neutral_worker_effort(value: object) -> str:
+ effort = _text(value, "reasoning_effort", maximum=16)
+ if effort not in _MODEL_NEUTRAL_WORKER_EFFORTS:
+ raise ValueError("worker reasoning_effort is unavailable")
+ return effort
+
+
def _one_fast_lane_effort(values: object) -> str:
if (
not isinstance(values, Sequence)
@@ -6759,6 +7007,9 @@ def _fast_lane_source_with_remediation(
source_plan: Mapping[str, Any], remediation: Mapping[str, Any]
) -> dict[str, Any]:
unit = _fast_lane_remediation_unit(remediation)
+ if source_plan.get("schema") == "team-efficiency/decomposition-plan-v2":
+ unit = {key: value for key, value in unit.items() if key != "recommended_route"}
+ unit["route_requirements"] = _route_requirements("complex")
return {
**source_plan,
"units": [*source_plan["units"], unit],
@@ -7503,6 +7754,32 @@ def _validated_fast_lane_scheduler_state(
return normalized, remediation
+def _validated_route_intents(
+ value: object, *, task_ids: frozenset[str]
+) -> dict[tuple[str, str], dict[str, str]]:
+ if not isinstance(value, Sequence) or isinstance(value, (str, bytes, bytearray)):
+ raise ValueError("route_intents must be a list")
+ if len(value) > MAX_FAST_LANE_ROUTING_ENTRIES:
+ raise ValueError("route_intents exceeds its bound")
+ intents: dict[tuple[str, str], dict[str, str]] = {}
+ for index, raw in enumerate(value):
+ item = _mapping(raw, f"route_intents[{index}]")
+ _exact_keys(item, _ROUTE_INTENT_FIELDS, f"route_intents[{index}]")
+ task_id = _task_id(item["task_id"], f"route_intents[{index}].task_id")
+ role = _text(item["role"], f"route_intents[{index}].role", maximum=32)
+ if task_id not in task_ids or role not in _FAST_LANE_ROLES:
+ raise ValueError("route intent target is invalid")
+ model_id = _text(
+ item["model_id"], f"route_intents[{index}].model_id", maximum=128
+ )
+ effort = _model_neutral_worker_effort(item["reasoning_effort"])
+ key = (task_id, role)
+ if key in intents:
+ raise ValueError("route intent target is duplicated")
+ intents[key] = {"model_id": model_id, "reasoning_effort": effort}
+ return intents
+
+
def _validated_fast_lane_request(
request: Mapping[str, Any],
*,
@@ -7516,12 +7793,36 @@ def _validated_fast_lane_request(
"""
candidate = _mapping(request, "fast-lane request")
- _exact_keys(candidate, _FAST_LANE_REQUEST_FIELDS, "fast-lane request")
- if candidate["schema"] != "team-efficiency/fast-lane-request-v1":
+ request_schema = candidate.get("schema")
+ request_fields = (
+ _FAST_LANE_REQUEST_V2_FIELDS
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA
+ else _FAST_LANE_REQUEST_FIELDS
+ )
+ _exact_keys(candidate, request_fields, "fast-lane request")
+ if request_schema not in {
+ "team-efficiency/fast-lane-request-v1",
+ _FAST_LANE_REQUEST_V2_SCHEMA,
+ }:
raise ValueError("fast-lane request schema is invalid")
if len(_json_bytes(candidate)) > MAX_MANIFEST_INPUT_BYTES:
raise ValueError("fast-lane request exceeds its byte budget")
+ request_hash = _sha256_json(candidate)
+ package = _mapping(candidate["work_package"], "fast-lane work package")
+ expected_package_schema = (
+ _WORK_PACKAGE_V3_SCHEMA
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA
+ else _WORK_PACKAGE_V2_SCHEMA
+ )
+ if package.get("schema") != expected_package_schema:
+ raise ValueError("fast-lane request/work-package versions are incompatible")
source_plan = decompose(candidate["work_package"])
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA:
+ if source_plan.get("schema") != "team-efficiency/decomposition-plan-v2":
+ raise ValueError("fast-lane request v2 requires work-package v3")
+ route_intents_value = candidate["route_intents"]
+ else:
+ route_intents_value = ()
source_plan_hash = _sha256_json(source_plan)
target_gates = _validated_fast_lane_target_gates(
candidate["target_gates"], source_plan
@@ -7534,6 +7835,14 @@ def _validated_fast_lane_request(
integration_state=integration_state,
)
if remediation is not None and remediation.get("_automation_stopped"):
+ route_intents = (
+ _validated_route_intents(
+ route_intents_value,
+ task_ids=frozenset(_fast_lane_unit_index(source_plan)),
+ )
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA
+ else {}
+ )
routing_context = _fast_lane_routing_context(
host_routing_context,
source_plan=source_plan,
@@ -7586,6 +7895,8 @@ def _validated_fast_lane_request(
"scheduler_state": scheduler_state,
"routing_context": routing_context,
"automation_stopped": True,
+ "route_intents": route_intents,
+ "request_hash": request_hash,
}
effective_source_plan = source_plan
@@ -7601,6 +7912,14 @@ def _validated_fast_lane_request(
"gates": remediation["target_gates"],
},
]
+ route_intents = (
+ _validated_route_intents(
+ route_intents_value,
+ task_ids=frozenset(_fast_lane_unit_index(effective_source_plan)),
+ )
+ if request_schema == _FAST_LANE_REQUEST_V2_SCHEMA
+ else {}
+ )
routing_context = _fast_lane_routing_context(
host_routing_context,
source_plan=effective_source_plan,
@@ -7632,9 +7951,43 @@ def _validated_fast_lane_request(
"scheduler_state": scheduler_state,
"routing_context": routing_context,
"automation_stopped": False,
+ "route_intents": route_intents,
+ "request_hash": request_hash,
}
+def prepare_model_neutral_fast_lane_request(
+ request: Mapping[str, Any],
+ *,
+ route_intents: Sequence[Mapping[str, Any]] | None = None,
+) -> dict[str, Any]:
+ """Create the default request-v2 envelope from an explicit legacy request."""
+
+ source = _mapping(request, "fast-lane request")
+ request_schema = source.get("schema")
+ if request_schema == "team-efficiency/fast-lane-request-v1":
+ _exact_keys(source, _FAST_LANE_REQUEST_FIELDS, "fast-lane request")
+ package = _mapping(source["work_package"], "fast-lane work package")
+ if package.get("schema") != _WORK_PACKAGE_V2_SCHEMA:
+ raise ValueError("model-neutral request requires work-package v2")
+ prepared = json.loads(_canonical_json(source))
+ prepared["schema"] = _FAST_LANE_REQUEST_V2_SCHEMA
+ prepared["work_package"]["schema"] = _WORK_PACKAGE_V3_SCHEMA
+ prepared["route_intents"] = (
+ []
+ if route_intents is None
+ else json.loads(_canonical_json(list(route_intents)))
+ )
+ elif request_schema == _FAST_LANE_REQUEST_V2_SCHEMA:
+ prepared = json.loads(_canonical_json(source))
+ if route_intents is not None:
+ prepared["route_intents"] = json.loads(_canonical_json(list(route_intents)))
+ else:
+ raise ValueError("model-neutral request source schema is invalid")
+ _validated_fast_lane_request(prepared)
+ return prepared
+
+
def _fast_lane_phase(value: object) -> str:
scheduler_state = _mapping(value, "scheduler_state")
phase = _text(scheduler_state.get("phase"), "scheduler_state.phase", maximum=32)
@@ -9650,8 +10003,111 @@ def _validated_fast_lane_local_worktree(value: object, *, role: str) -> dict[str
return dict(worktree)
+def _validated_route_requirements(value: object) -> dict[str, Any]:
+ requirement = _mapping(value, "route requirements")
+ _exact_keys(requirement, _ROUTE_REQUIREMENT_FIELDS, "route requirements")
+ if requirement["schema"] != "team-efficiency/model-route-requirements-v1":
+ raise ValueError("route requirements schema is invalid")
+ if requirement["complexity"] not in {
+ "routine",
+ "moderate",
+ "complex",
+ "exceptional",
+ }:
+ raise ValueError("route requirements complexity is invalid")
+ _normalised_list(
+ requirement["capability_tags"],
+ "route requirements.capability_tags",
+ _label,
+ maximum=8,
+ required=True,
+ )
+ if requirement["effort_preference"] not in {
+ "low",
+ "medium",
+ "high",
+ "xhigh",
+ "max",
+ }:
+ raise ValueError("route requirements effort preference is invalid")
+ if requirement["cost_preference"] not in {
+ "cost_efficient",
+ "balanced",
+ "capability_first",
+ }:
+ raise ValueError("route requirements cost preference is invalid")
+ if requirement["worker_ultra_forbidden"] is not True:
+ raise ValueError("route requirements must forbid worker ultra")
+ intent = _mapping(requirement["explicit_intent"], "explicit route intent")
+ if intent.get("state") == "unspecified":
+ _exact_keys(intent, frozenset({"state"}), "explicit route intent")
+ elif intent.get("state") == "required":
+ _exact_keys(
+ intent,
+ frozenset({"state", "model_id", "reasoning_effort"}),
+ "explicit route intent",
+ )
+ _text(intent["model_id"], "explicit route intent.model_id", maximum=128)
+ _model_neutral_worker_effort(intent["reasoning_effort"])
+ else:
+ raise ValueError("explicit route intent state is invalid")
+ supplied_hash = _hash(
+ requirement["requirement_hash"], "route requirements.requirement_hash"
+ )
+ normalized = {
+ key: item for key, item in requirement.items() if key != "requirement_hash"
+ }
+ if supplied_hash != _sha256_json(normalized):
+ raise ValueError("route requirements hash is invalid")
+ return dict(requirement)
+
+
+def _validated_model_selection(value: object) -> dict[str, Any]:
+ selection = _mapping(value, "model selection")
+ _exact_keys(selection, _MODEL_SELECTION_FIELDS, "model selection")
+ if dict(selection) != {
+ "schema": "team-efficiency/model-selection-v1",
+ "state": "unselected",
+ "owner": "coordinator",
+ "catalog_source": "codex_tool_metadata",
+ "availability_gate": "dispatch_tool",
+ "record_schema": "team-efficiency/model-selection-record-v1",
+ }:
+ raise ValueError("model selection is invalid")
+ return dict(selection)
+
+
def _validated_fast_lane_local_assignment(value: object) -> dict[str, Any]:
assignment = _mapping(value, "local planned assignment")
+ if assignment.get("schema") == "team-efficiency/local-writer-plan-v2":
+ _exact_keys(
+ assignment,
+ _LOCAL_PLAN_ASSIGNMENT_V2_FIELDS,
+ "local planned assignment",
+ )
+ 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"])
+ _validated_route_requirements(assignment["route_requirements"])
+ _validated_model_selection(assignment["selection"])
+ 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)
_exact_keys(
assignment,
_LOCAL_PLAN_ASSIGNMENT_FIELDS,
@@ -9682,8 +10138,110 @@ def _validated_fast_lane_local_assignment(value: object) -> dict[str, Any]:
return dict(assignment)
+def _validated_model_selection_record(
+ value: object, *, assignment: Mapping[str, Any]
+) -> dict[str, Any]:
+ record = _mapping(value, "model selection record")
+ _exact_keys(record, _MODEL_SELECTION_RECORD_FIELDS, "model selection record")
+ if record["schema"] != "team-efficiency/model-selection-record-v1":
+ raise ValueError("model selection record schema is invalid")
+ planned = _validated_fast_lane_local_assignment(assignment)
+ if planned["schema"] != "team-efficiency/local-writer-plan-v2":
+ raise ValueError("model selection requires a model-neutral assignment")
+ plan_item_id = _hash(record["plan_item_id"], "model selection.plan_item_id")
+ requirement_hash = _hash(
+ record["requirement_hash"], "model selection.requirement_hash"
+ )
+ if (
+ plan_item_id != planned["plan_item_id"]
+ or requirement_hash != planned["route_requirements"]["requirement_hash"]
+ ):
+ raise ValueError("model selection record is not bound to its assignment")
+ model_id = _text(record["model_id"], "model selection.model_id", maximum=128)
+ reasoning_effort = _model_neutral_worker_effort(record["reasoning_effort"])
+ _text(record["selection_reason"], "model selection.selection_reason", maximum=512)
+ if (
+ record["availability_gate"] != "dispatch_tool"
+ or record["execution_state"] != "selection_only"
+ or record["dispatch_state"] != "not_dispatched"
+ or record["execution_authorized"] is not False
+ ):
+ raise ValueError("model selection record claims execution authority")
+ intent = _mapping(
+ planned["route_requirements"]["explicit_intent"], "explicit route intent"
+ )
+ if intent["state"] == "required" and (
+ model_id != intent["model_id"] or reasoning_effort != intent["reasoning_effort"]
+ ):
+ raise ValueError("explicit route intent cannot be replaced")
+ supplied_hash = _hash(
+ record["selection_record_hash"], "model selection.selection_record_hash"
+ )
+ normalized = {
+ key: item for key, item in record.items() if key != "selection_record_hash"
+ }
+ if supplied_hash != _sha256_json(normalized):
+ raise ValueError("model selection record hash is invalid")
+ return dict(record)
+
+
+def record_model_selection(
+ assignment: Mapping[str, Any],
+ *,
+ model_id: str,
+ reasoning_effort: str,
+ selection_reason: str,
+) -> dict[str, Any]:
+ """Bind a coordinator choice without claiming dispatch or availability."""
+
+ planned = _validated_fast_lane_local_assignment(assignment)
+ if planned["schema"] != "team-efficiency/local-writer-plan-v2":
+ raise ValueError("model selection requires a model-neutral assignment")
+ selected_model = _text(model_id, "model selection.model_id", maximum=128)
+ selected_effort = _model_neutral_worker_effort(reasoning_effort)
+ reason = _text(selection_reason, "model selection.selection_reason", maximum=512)
+ record: dict[str, Any] = {
+ "schema": "team-efficiency/model-selection-record-v1",
+ "plan_item_id": planned["plan_item_id"],
+ "requirement_hash": planned["route_requirements"]["requirement_hash"],
+ "model_id": selected_model,
+ "reasoning_effort": selected_effort,
+ "selection_reason": reason,
+ "availability_gate": "dispatch_tool",
+ "execution_state": "selection_only",
+ "dispatch_state": "not_dispatched",
+ "execution_authorized": False,
+ }
+ record["selection_record_hash"] = _sha256_json(record)
+ return _validated_model_selection_record(record, assignment=planned)
+
+
+def validate_model_selection_record(
+ record: Mapping[str, Any], *, assignment: Mapping[str, Any]
+) -> dict[str, Any]:
+ """Validate the exact model choice against its model-neutral assignment."""
+
+ return _validated_model_selection_record(record, assignment=assignment)
+
+
def _validated_fast_lane_local_policy(value: object) -> dict[str, Any]:
policy = _mapping(value, "local plan workflow policy")
+ if policy.get("schema") == "team-efficiency/local-plan-consumer-policy-v2":
+ _exact_keys(policy, _LOCAL_PLAN_POLICY_V2_FIELDS, "local plan workflow policy")
+ if dict(policy) != {
+ "schema": "team-efficiency/local-plan-consumer-policy-v2",
+ "consumer": "main_coordinator",
+ "dispatch_tool": "collaboration.spawn_agent",
+ "explicit_route_required": True,
+ "lease_claim_required_before_execution": True,
+ "compiler_side_effects": False,
+ "selection_owner": "coordinator",
+ "catalog_source": "codex_tool_metadata",
+ "availability_gate": "dispatch_tool",
+ "selection_record": "team-efficiency/model-selection-record-v1",
+ }:
+ raise ValueError("local plan workflow policy is invalid")
+ return dict(policy)
_exact_keys(policy, _LOCAL_PLAN_POLICY_FIELDS, "local plan workflow policy")
if dict(policy) != {
"schema": "team-efficiency/local-plan-consumer-policy-v1",
@@ -9699,8 +10257,17 @@ def _validated_fast_lane_local_policy(value: object) -> dict[str, Any]:
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":
+ plan_schema = plan.get("schema")
+ expected_fields = (
+ _LOCAL_PLAN_V3_FIELDS
+ if plan_schema == "team-efficiency/fast-lane-plan-v3"
+ else _LOCAL_PLAN_V2_FIELDS
+ )
+ _exact_keys(plan, expected_fields, "fast-lane local plan")
+ if plan_schema not in {
+ "team-efficiency/fast-lane-plan-v2",
+ "team-efficiency/fast-lane-plan-v3",
+ }:
raise ValueError("fast-lane local plan schema is invalid")
if (
plan["plan_only"] is not True
@@ -9723,6 +10290,13 @@ def _validated_fast_lane_local_plan(value: object) -> dict[str, Any]:
raise ValueError("fast-lane local plan assignments are invalid")
for assignment_value in assignments:
assignment = _validated_fast_lane_local_assignment(assignment_value)
+ expected_assignment_schema = (
+ "team-efficiency/local-writer-plan-v2"
+ if plan_schema == "team-efficiency/fast-lane-plan-v3"
+ else "team-efficiency/local-writer-plan-v1"
+ )
+ if assignment["schema"] != expected_assignment_schema:
+ raise ValueError("local planned assignment version is invalid")
if assignment["index_evidence"] != index_evidence:
raise ValueError("local planned assignment index evidence is not bound")
@@ -9814,6 +10388,41 @@ def _fast_lane_local_routing_context(
}
+def _fast_lane_model_neutral_routing_context(
+ source_plan: Mapping[str, Any],
+ route_intents: Mapping[tuple[str, str], Mapping[str, str]],
+) -> dict[str, Any]:
+ """Return selectable requirements; catalog choice remains coordinator-owned."""
+
+ decisions: dict[tuple[str, str], dict[str, Any]] = {}
+ for task_id, unit in sorted(_fast_lane_unit_index(source_plan).items()):
+ base = _mapping(unit.get("route_requirements"), "source route requirements")
+ complexity = _text(
+ base.get("complexity"), "source route requirements.complexity", maximum=32
+ )
+ for role in sorted(_FAST_LANE_ROLES):
+ intent = route_intents.get((task_id, role))
+ decisions[(task_id, role)] = {
+ "route_requirements": _route_requirements(
+ complexity, role=role, explicit_intent=intent
+ ),
+ "selection": {
+ "schema": "team-efficiency/model-selection-v1",
+ "state": "unselected",
+ "owner": "coordinator",
+ "catalog_source": "codex_tool_metadata",
+ "availability_gate": "dispatch_tool",
+ "record_schema": "team-efficiency/model-selection-record-v1",
+ },
+ }
+ return {
+ "decisions": decisions,
+ "reasons": {},
+ "default_reason": "coordinator_model_selection",
+ "global_failure_reason": None,
+ }
+
+
def _validated_fast_lane_local_material(
material_value: Mapping[str, Any],
*,
@@ -9985,6 +10594,30 @@ def _fast_lane_local_assignment_output(
worktree = _fast_lane_public_value(worktree_value)
if type(worktree) is not dict:
raise ValueError("local planned worktree is invalid")
+ if "route_requirements" in assignment:
+ item_value = {
+ "schema": "team-efficiency/local-writer-plan-v2",
+ "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,
+ "route_requirements": dict(assignment["route_requirements"]),
+ "selection": dict(assignment["selection"]),
+ "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)
item_value = {
"schema": "team-efficiency/local-writer-plan-v1",
"slot_id": assignment["slot_id"],
@@ -10021,13 +10654,21 @@ def _compile_fast_lane_local_plan(
enable: bool,
local_plan_material: Mapping[str, Any],
) -> dict[str, Any]:
+ model_neutral = request.get("schema") == _FAST_LANE_REQUEST_V2_SCHEMA
activation = _fast_lane_activation(reasoning_effort, enable)
validated = _validated_fast_lane_request(request)
+ routing_context = (
+ _fast_lane_model_neutral_routing_context(
+ validated["source_plan"], validated["route_intents"]
+ )
+ if model_neutral
+ else _fast_lane_local_routing_context(
+ validated["source_plan"], validated["source_plan_hash"]
+ )
+ )
validated = {
**validated,
- "routing_context": _fast_lane_local_routing_context(
- validated["source_plan"], validated["source_plan_hash"]
- ),
+ "routing_context": routing_context,
}
if validated["scheduler_state"]["running_assignments"]:
raise _FastLaneLocalPlanError("FASTLANE_RUNTIME_STATE_UNSUPPORTED")
@@ -10054,7 +10695,11 @@ def _compile_fast_lane_local_plan(
"FAST_LANE_PLANNED" if planned_assignments else "NO_SAFE_LOCAL_PLAN"
)
result_value: dict[str, Any] = {
- "schema": "team-efficiency/fast-lane-plan-v2",
+ "schema": (
+ "team-efficiency/fast-lane-plan-v3"
+ if model_neutral
+ else "team-efficiency/fast-lane-plan-v2"
+ ),
"status": status,
"decision_code": decision_code,
"plan_only": True,
@@ -10067,15 +10712,32 @@ def _compile_fast_lane_local_plan(
"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,
- },
+ "workflow_policy": (
+ {
+ "schema": "team-efficiency/local-plan-consumer-policy-v2",
+ "consumer": "main_coordinator",
+ "dispatch_tool": "collaboration.spawn_agent",
+ "explicit_route_required": True,
+ "lease_claim_required_before_execution": True,
+ "compiler_side_effects": False,
+ "selection_owner": "coordinator",
+ "catalog_source": "codex_tool_metadata",
+ "availability_gate": "dispatch_tool",
+ "selection_record": "team-efficiency/model-selection-record-v1",
+ }
+ if model_neutral
+ else {
+ "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,
+ }
+ ),
}
+ if model_neutral:
+ result_value["request_hash"] = validated["request_hash"]
result = _fast_lane_public_value(result_value)
if type(result) is not dict:
raise ValueError("fast-lane local plan is invalid")
diff --git a/mcp-tools/pyproject.toml b/mcp-tools/pyproject.toml
index e22f84b..c1c0c8f 100644
--- a/mcp-tools/pyproject.toml
+++ b/mcp-tools/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "2718lab-devkit-mcp"
-version = "1.1.4"
+version = "1.1.5"
description = "MCP runtime for the 2718lab DevKit primary plugin."
requires-python = ">=3.11"
dependencies = [
diff --git a/mcp-tools/tests/test_bugkiller_metadata.py b/mcp-tools/tests/test_bugkiller_metadata.py
index a7ff2bf..4967c10 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.4", codex["version"])
+ self.assertEqual("1.1.5", 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 ed642fe..77e11f1 100644
--- a/mcp-tools/tests/test_fastlane_runtime.py
+++ b/mcp-tools/tests/test_fastlane_runtime.py
@@ -253,7 +253,7 @@ 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:
+def test_fastlane_docs_describe_the_mcp_plan_v3_and_legacy_v2_boundaries() -> None:
contract = (ROOT / "mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md").read_text(
encoding="utf-8"
)
@@ -263,8 +263,9 @@ def test_fastlane_docs_describe_the_mcp_plan_v2_boundary() -> None:
]
for document in (contract, *readmes):
- assert "team-efficiency/fast-lane-plan-v2" in document
+ assert "team-efficiency/fast-lane-plan-v3" in document
assert "plan_only" in document
+ assert "team-efficiency/fast-lane-plan-v2" in contract
assert "include_paths" in contract
assert "INDEX_PARTIAL" in contract
assert "local_plan_material" not in contract
@@ -305,6 +306,79 @@ def test_fastlane_tool_rejects_host_private_inputs() -> None:
assert result["error"]["code"] == "FASTLANE_REQUEST_INVALID"
+@pytest.mark.parametrize(
+ ("request_schema", "package_schema", "include_route_intents"),
+ [
+ (
+ "team-efficiency/fast-lane-request-v1",
+ "team-efficiency/work-package-v3",
+ False,
+ ),
+ (
+ "team-efficiency/fast-lane-request-v2",
+ "team-efficiency/work-package-v2",
+ True,
+ ),
+ ],
+)
+def test_fastlane_rejects_mixed_request_and_work_package_versions(
+ request_schema: str, package_schema: str, include_route_intents: bool
+) -> None:
+ helper, request, _ = _sample_request()
+ try:
+ request["schema"] = request_schema
+ request["work_package"]["schema"] = package_schema
+ if include_route_intents:
+ request["route_intents"] = []
+ result = server.fastlane_compile(
+ request=request, reasoning_effort="max", enable=True
+ )
+ with pytest.raises(ValueError, match="versions are incompatible"):
+ team_efficiency._validated_fast_lane_request(request)
+ finally:
+ helper.tearDown()
+ assert result["ok"] is False
+ assert result["error"]["code"] == "PROJECT_BINDING_INVALID"
+
+
+def test_model_neutral_route_intent_can_target_appended_remediation(
+ monkeypatch,
+) -> None:
+ helper, request, _ = _sample_request()
+ try:
+ prepared = devkit_fastlane.prepare_model_neutral_fast_lane_request(request)
+ remediation = helper.fast_lane_remediation_request(team_efficiency, prepared)
+ prepared["remediation_request"] = remediation
+ prepared["route_intents"] = [
+ {
+ "task_id": remediation["task_id"],
+ "role": "execution",
+ "model_id": "gpt-99-future",
+ "reasoning_effort": "max",
+ }
+ ]
+ monkeypatch.setattr(
+ team_efficiency,
+ "_validated_fast_lane_contexts",
+ lambda *args, **kwargs: ([], []),
+ )
+ monkeypatch.setattr(
+ team_efficiency,
+ "_validated_fast_lane_scheduler_state",
+ lambda *args, **kwargs: ({}, remediation),
+ )
+ validated = team_efficiency._validated_fast_lane_request(prepared)
+ finally:
+ helper.tearDown()
+ assert remediation["task_id"] in {
+ item["task_id"] for item in validated["source_plan"]["units"]
+ }
+ assert validated["route_intents"][(remediation["task_id"], "execution")] == {
+ "model_id": "gpt-99-future",
+ "reasoning_effort": "max",
+ }
+
+
def test_fastlane_tool_never_spawns_or_executes(monkeypatch) -> None:
"""The MCP compiler emits descriptors; the host owns execution and refill."""
@@ -489,6 +563,93 @@ def test_fastlane_tool_uses_persisted_runtime_registry_index_and_git_head(
assert all(item["execution_state"] == "plan_only" for item in data["assignments"])
+def test_model_neutral_plan_preserves_future_intent_and_legacy_source_hash(
+ monkeypatch,
+) -> None:
+ helper, _, _ = _sample_request()
+ legacy_hash = team_efficiency._sha256_json(
+ team_efficiency.decompose(helper.decomposition_manifest())
+ )
+ root = None
+ try:
+ root, request, snapshot_id = _install_persistent_local_plan_runtime(
+ monkeypatch, helper
+ )
+ prepared = devkit_fastlane.prepare_model_neutral_fast_lane_request(
+ request,
+ route_intents=[
+ {
+ "task_id": "ATLAS-12B-A",
+ "role": "execution",
+ "model_id": "gpt-99-future",
+ "reasoning_effort": "max",
+ }
+ ],
+ )
+ result = server.fastlane_compile(
+ request=prepared, reasoning_effort="max", enable=True
+ )
+ finally:
+ if root is not None:
+ root.shutdown()
+ helper.tearDown()
+
+ assert legacy_hash == (
+ "sha256:f736b99d55bc562252d1fd6a98fb0f2d12813b0b50ba518f88d4f12c298a7775"
+ )
+ assert result["ok"] is True
+ data = result["data"]
+ assert data["schema"] == "team-efficiency/fast-lane-plan-v3"
+ assert data["status"] == "planned"
+ assert data["request_hash"] == team_efficiency._sha256_json(prepared)
+ assert data["index_evidence"]["snapshot_id"] == snapshot_id
+ assert all(
+ {"model", "reasoning_effort", "recommended_route"}.isdisjoint(assignment)
+ for assignment in data["assignments"]
+ )
+ assignment = next(
+ item for item in data["assignments"] if item["task_id"] == "ATLAS-12B-A"
+ )
+ assert assignment["selection"] == {
+ "schema": "team-efficiency/model-selection-v1",
+ "state": "unselected",
+ "owner": "coordinator",
+ "catalog_source": "codex_tool_metadata",
+ "availability_gate": "dispatch_tool",
+ "record_schema": "team-efficiency/model-selection-record-v1",
+ }
+ assert assignment["route_requirements"]["explicit_intent"] == {
+ "state": "required",
+ "model_id": "gpt-99-future",
+ "reasoning_effort": "max",
+ }
+ record = devkit_fastlane.record_model_selection(
+ assignment,
+ model_id="gpt-99-future",
+ reasoning_effort="max",
+ selection_reason="The current Codex tool metadata lists the requested route.",
+ )
+ assert record["execution_state"] == "selection_only"
+ assert record["dispatch_state"] == "not_dispatched"
+ assert record["execution_authorized"] is False
+ assert record["plan_item_id"] == assignment["plan_item_id"]
+ assert (
+ record["requirement_hash"]
+ == assignment["route_requirements"]["requirement_hash"]
+ )
+ assert (
+ devkit_fastlane.validate_model_selection_record(record, assignment=assignment)
+ == record
+ )
+ with pytest.raises(ValueError, match="explicit route intent cannot be replaced"):
+ devkit_fastlane.record_model_selection(
+ assignment,
+ model_id="gpt-5.6-sol",
+ reasoning_effort="max",
+ selection_reason="Attempted fallback must be rejected.",
+ )
+
+
def test_fastlane_tool_rejects_stale_persisted_snapshot(monkeypatch) -> None:
helper, _, _ = _sample_request()
root = None
diff --git a/mcp-tools/tests/test_primary_artifact.py b/mcp-tools/tests/test_primary_artifact.py
index 8bc1a1d..2f618af 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.4"
+ assert project["project"]["version"] == "1.1.5"
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.4"' in lock_text
+ assert 'version = "1.1.5"' 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 b33ed59..4a26f6f 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.4"
+version = "1.1.5"
source = { virtual = "." }
dependencies = [
{ name = "mcp", extra = ["cli"] },
diff --git a/skills/fast-lane-routing/SKILL.md b/skills/fast-lane-routing/SKILL.md
index d60cc0e..9c5a86c 100644
--- a/skills/fast-lane-routing/SKILL.md
+++ b/skills/fast-lane-routing/SKILL.md
@@ -5,8 +5,29 @@ description: Reference manual for reading a compiled 2718lab Fast Lane plan, exp
# Fast Lane Routing Manual
-Read a plan as a bounded host contract: model, effort, route, worktree, lease,
-context, and predecessor bindings are exact values, not defaults to infer.
+For new work, prepare `fast-lane-request-v2` with
+`prepare_model_neutral_fast_lane_request`; it pairs only with
+`work-package-v3`. Read its plan-v3 assignments as requirements, not a model
+registry:
+
+- Use `route_requirements` to judge complexity, capability, effort, and cost.
+- Choose from the model IDs and supported efforts listed by the current
+ `collaboration.spawn_agent` tool metadata. Routine work should stay
+ cost-conscious; design, research, and exceptional cross-module work should
+ use the strongest suitable current model at its highest worker-safe effort.
+- `selection.state="unselected"` is a normal planned state. Call
+ `record_model_selection` with the exact chosen model ID, effort, and reason,
+ then pass that exact route to the dispatch tool. The record does not claim
+ availability or dispatch.
+- An `explicit_intent` with `state="required"` is non-substitutable. If the
+ current tool rejects it, report the route unavailable; never silently fall
+ back to another model.
+- Model IDs are bounded strings, not a product whitelist. Do not add a model
+ name to DevKit routing tables merely because Codex introduces it.
+
+Legacy request-v1/plan-v2 records remain exact replay contracts: their model,
+effort, route, worktree, lease, context, and predecessor bindings are not
+defaults to reinterpret.
- A missing, altered, or unattested route is \`NO_SAFE_WORK\`.
- A missing first index snapshot in a newly opened project is a cold-start