Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "2718lab-devkit",
"version": "1.1.1",
"version": "1.1.2",
"description": "Local MCP server for developer workflow coordination, indexing, and evidence handling.",
"author": {
"name": "2718lab",
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ body:
id: version
attributes:
label: DevKit version
placeholder: "v1.1.1"
placeholder: "v1.1.2"
validations:
required: true

Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ only after the CI and artifact checks pass.

## [Unreleased]

## [1.1.2] - 2026-08-27

### Fixed

- Treat a newly opened project without an index as normal cold start: initialize
it with one bounded `project_index_register -> project_index_sync` sequence
before considering degraded mode, including when README, configuration, or
source files already exist.
- Preserve the host-attested initial entry count through bootstrap and require
the synchronized manifest and entry count to match exactly before indexed
recompilation; registration, synchronization, identity, or attestation
failures remain fail-closed.

## [1.1.1] - 2026-08-25

### Fixed
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[简体中文](README.zh-CN.md)

# 2718lab DevKit — Codex + MCP v1.1.1
# 2718lab DevKit — Codex + MCP v1.1.2

[![version](https://img.shields.io/badge/version-v1.1.1-blue)](./.codex-plugin/plugin.json)
[![version](https://img.shields.io/badge/version-v1.1.2-blue)](./.codex-plugin/plugin.json)
[![license](https://img.shields.io/badge/license-AGPL--3.0-blue)](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.1 package.
of reference manuals. This repository carries the versioned v1.1.2 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.
Expand Down Expand Up @@ -168,7 +168,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 <artifact-output-dir>/2718lab-devkit-marketplace-v1.1.1.zip
python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output <artifact-output-dir>/2718lab-devkit-marketplace-v1.1.2.zip

## Install and run locally

Expand Down Expand Up @@ -202,7 +202,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 <artifact-output-dir>/2718lab-devkit-v1.1.1.zip
python .codex-plugin/build_main_artifact.py --plugin-root . --output <artifact-output-dir>/2718lab-devkit-v1.1.2.zip

The artifact contains the manifest, .mcp.json, LICENSE, the locked Python
project, and the runtime files selected by
Expand Down Expand Up @@ -360,7 +360,7 @@ freeze a transient regression count.

## Version

This repository represents the versioned v1.1.1 package. Release notes are
This repository represents the versioned v1.1.2 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,
Expand Down
12 changes: 6 additions & 6 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[English](README.md)

# 2718lab DevKit —— Codex + MCP v1.1.1
# 2718lab DevKit —— Codex + MCP v1.1.2

[![版本](https://img.shields.io/badge/version-v1.1.1-blue)](./.codex-plugin/plugin.json)
[![版本](https://img.shields.io/badge/version-v1.1.2-blue)](./.codex-plugin/plugin.json)
[![许可证](https://img.shields.io/badge/license-AGPL--3.0-blue)](LICENSE)

2718lab DevKit 是一个 Codex-first 工程工具包:它包含一个本地、仅 stdio
传输的 MCP 运行时,用于有边界的项目索引、Atlas 证据、Relay 生命周期协调和
确定性的 Fast Lane 规划;同时还包含一组精简的 Skill 说明书。本仓库承载版本化的
v1.1.1 包;已提交的 manifest 和 allowlist 定义可执行运行时范围,说明书导航、
v1.1.2 包;已提交的 manifest 和 allowlist 定义可执行运行时范围,说明书导航、
安装、构建和验证章节共同给出支持的工作流。

当前版本保留刻意 fail-closed 的 Fast Lane 预览。公共编译器和 CLI 固定返回
Expand Down Expand Up @@ -148,7 +148,7 @@ Fast Lane 不含额度协调器合同;公共编译器和 CLI 不读取、协

维护者使用专用的 marketplace allowlist 构建该快照:

python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output <artifact-output-dir>/2718lab-devkit-marketplace-v1.1.1.zip
python .codex-plugin/build_main_artifact.py --plugin-root . --allowlist .codex-plugin/marketplace-artifact-allowlist.json --output <artifact-output-dir>/2718lab-devkit-marketplace-v1.1.2.zip

## 本地安装与运行

Expand Down Expand Up @@ -179,7 +179,7 @@ RELAY_CAPABILITY_BROKER_UNAVAILABLE。服务器不会暴露原始 handle,也

allowlist builder 会在插件源码树之外生成确定性的 ZIP。请选择源码树之外的输出目录:

python .codex-plugin/build_main_artifact.py --plugin-root . --output <artifact-output-dir>/2718lab-devkit-v1.1.1.zip
python .codex-plugin/build_main_artifact.py --plugin-root . --output <artifact-output-dir>/2718lab-devkit-v1.1.2.zip

产物包含 manifest、.mcp.json、LICENSE、锁定的 Python 项目,以及
.codex-plugin/main-artifact-allowlist.json 选中的运行时文件。它的可执行运行时
Expand Down Expand Up @@ -312,7 +312,7 @@ CI 和全新产物检查才是当前测试计数的唯一来源。它们验证

## 版本

本仓库代表版本化的 v1.1.1 包。发布说明见
本仓库代表版本化的 v1.1.2 包。发布说明见
[CHANGELOG.md](CHANGELOG.md);构建和安装请以已提交的 manifest、产物 allowlist
和锁定依赖为准。维护者从 current `main` 手动 dispatch Release;它通过全部 gates
后才创建注释 tag 并发布匹配的 GitHub Release。单独 push tag 不会触发发布。
Expand Down
5 changes: 3 additions & 2 deletions mcp-tools/devkit_fastlane/FASTLANE_CONTRACT.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@ plan 可自报的根字段。
本地 Windows 的 `C:/` 和 `G:/` 以外的本机盘符都禁止作为 `TEMP`、`TMP`、`TMPDIR`
或临时根;可信 hosted Windows CI 仅可使用宿主提供的 `RUNNER_TEMP`,并在其下派生
任务临时与缓存路径。该宿主例外不放宽本地规则,也不是外部宿主 embedding 证据。
这仍是当前 bootstrap/read-context 边界。空项目只能生成 bootstrap-only index:不得据此创建可执行
assignment,直到可信宿主提供有界项目索引上下文。旧 schema 输入返回
这仍是当前 bootstrap/read-context 边界。尚未建立索引的新项目(无论目录是否已包含
源码、README 或配置)只能生成 bootstrap-only index:不得据此创建可执行 assignment,
直到可信宿主完成一次 `register -> sync` 并提供与初始 manifest 精确绑定的有界项目索引上下文。旧 schema 输入返回
`FASTLANE_SCHEMA_UPGRADE_REQUIRED`,不得降级猜测或启动工作。

### 6. 验证与交付
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,11 @@ apply behavior; neither is implemented or accepted as an input here.

An older bootstrap or routing schema is rejected as
`FASTLANE_SCHEMA_UPGRADE_REQUIRED`; it is never normalized into an executable
plan. An empty project may produce bootstrap-only index diagnostics, but cannot
produce an assignment until trusted host index context is available.
plan. An unindexed new project, including one that already contains source,
README, or configuration files, may produce bootstrap-only index diagnostics,
but cannot produce an assignment until the trusted host completes one
`register -> sync` and supplies index context bound to the attested initial
manifest.

The `RuntimeRoot` host-private V2/V3 bootstrap path is covered with injected
test doubles only. That coverage does not prove an external host embedding or
Expand Down
12 changes: 6 additions & 6 deletions mcp-tools/devkit_fastlane/scripts/team_efficiency.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
MAX_WRITE_SCOPES = 32
MAX_STATUS_TASKS = 64
MAX_MANIFEST_UNITS = 16
MAX_BOOTSTRAP_ENTRY_COUNT = 2**63 - 1
MAX_LIST_ITEMS = 32
MAX_GRAPH_NODES = 64
MAX_GRAPH_EDGES = 128
Expand Down Expand Up @@ -997,7 +998,9 @@ def _validated_project_binding(value: object) -> dict[str, Any]:
raise ValueError("project binding attestation schema is unknown")
if (
type(attestation_source["initial_entry_count"]) is not int
or not 0 <= attestation_source["initial_entry_count"] <= MAX_MANIFEST_UNITS
or not 0
<= attestation_source["initial_entry_count"]
<= MAX_BOOTSTRAP_ENTRY_COUNT
):
raise ValueError("project binding initial entry count is invalid")
if (
Expand Down Expand Up @@ -1155,10 +1158,7 @@ def _project_execution_block_details(
return "BOOTSTRAP_ATTESTATION_MISMATCH", None
if binding["mode"] == "new_empty_bootstrap":
attestation = binding["attestation"]
if (
attestation["state"] != "new_empty"
or attestation["initial_entry_count"] != 0
):
if attestation["state"] != "new_empty":
return "BOOTSTRAP_PROJECT_NOT_EMPTY", None
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
issued = _bootstrap_attestation_timestamp(
attestation["issued_at"], "project binding attestation.issued_at"
Expand Down Expand Up @@ -8613,7 +8613,7 @@ def _fast_lane_bootstrap_index_ready_plan(
*,
source_identity: Mapping[str, Any],
) -> dict[str, Any]:
"""Emit only the read-only descriptor for an attested empty project."""
"""Emit the read-only descriptor for an attested unindexed new project."""

binding = _mapping(source_identity["binding"], "new-empty bootstrap binding")
attestation = _mapping(binding["attestation"], "new-empty bootstrap attestation")
Expand Down
45 changes: 40 additions & 5 deletions mcp-tools/devkit_fastlane/tests/test_team_efficiency.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ def new_empty_project_binding(
issued_at: int,
expires_at: int,
initial_entry_count: int = 0,
state: str = "new_empty",
snapshot_id: str | None = None,
) -> dict[str, object]:
package = request["work_package"]
Expand All @@ -737,7 +738,7 @@ def new_empty_project_binding(
helper,
authority=authority,
mode="new_empty_bootstrap",
state="new_empty",
state=state,
initial_entry_count=initial_entry_count,
issued_at=issued_at,
expires_at=expires_at,
Expand Down Expand Up @@ -2255,6 +2256,30 @@ def test_task2_shaped_new_empty_project_emits_descriptor_only_plan(
self.assertNotIn(forbidden, serialized)
self.assertNotIn(str(self.repo).casefold(), serialized)

def test_unindexed_project_with_more_than_manifest_units_can_bootstrap(
self,
) -> None:
helper = load_efficiency()
request = self.fast_lane_schedule_request(helper)
now = int(datetime.now(UTC).timestamp())
request["project_binding"] = self.new_empty_project_binding(
helper,
request,
issued_at=now - 10,
expires_at=now + 110,
initial_entry_count=helper.MAX_MANIFEST_UNITS + 1,
)

result = helper.compile_fast_lane(
request,
reasoning_effort="ultra",
enable=True,
)

self.assertEqual("BOOTSTRAP_INDEX_READY", result["decision_code"])
self.assertEqual("bootstrap", result["status"])
self.assertEqual(1, len(result["bootstrap_queue"]))

def test_unattested_or_invalid_new_empty_project_stays_fenced(self) -> None:
helper = load_efficiency()
now = int(datetime.now(UTC).timestamp())
Expand All @@ -2280,13 +2305,22 @@ def bootstrap_request() -> dict[str, object]:
issued_at=now - 130,
expires_at=now - 10,
)
nonempty = bootstrap_request()
nonempty["project_binding"] = self.new_empty_project_binding(
invalid_state = bootstrap_request()
invalid_state["project_binding"] = self.new_empty_project_binding(
helper,
nonempty,
invalid_state,
issued_at=issued_at,
expires_at=expires_at,
initial_entry_count=1,
state="indexed",
)
negative_count = bootstrap_request()
negative_count["project_binding"] = self.new_empty_project_binding(
helper,
negative_count,
issued_at=issued_at,
expires_at=expires_at,
initial_entry_count=-1,
)
mismatch = bootstrap_request()
mismatch["project_binding"] = self.new_empty_project_binding(
Expand All @@ -2307,7 +2341,8 @@ def bootstrap_request() -> dict[str, object]:
cases = {
"missing": (missing, "BOOTSTRAP_ATTESTATION_REQUIRED"),
"stale": (stale, "BOOTSTRAP_ATTESTATION_STALE"),
"nonempty": (nonempty, "BOOTSTRAP_PROJECT_NOT_EMPTY"),
"invalid_state": (invalid_state, "BOOTSTRAP_PROJECT_NOT_EMPTY"),
"negative_count": (negative_count, "BOOTSTRAP_ATTESTATION_UNKNOWN"),
"mismatch": (mismatch, "BOOTSTRAP_ATTESTATION_MISMATCH"),
"unknown": (unknown, "BOOTSTRAP_ATTESTATION_UNKNOWN"),
}
Expand Down
5 changes: 3 additions & 2 deletions mcp-tools/devkit_relay/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
_MAX_RETRY_ATTEMPTS = 3
_MAX_WRITERS_PER_SCHEDULER = 3
_MAX_PARALLEL_WRITERS = 9
_MAX_BOOTSTRAP_ENTRY_COUNT = 2**63 - 1


class RelayPlanError(ValueError):
Expand Down Expand Up @@ -1135,7 +1136,7 @@ def _new_empty_project_binding(
)
or attestation["state"] != "new_empty"
or type(attestation["initial_entry_count"]) is not int
or attestation["initial_entry_count"] != 0
or not 0 <= attestation["initial_entry_count"] <= _MAX_BOOTSTRAP_ENTRY_COUNT
or type(attestation["capability_epoch"]) is not int
or attestation["capability_epoch"] < 1
or not _finite_timestamp(attestation["issued_at"])
Expand Down Expand Up @@ -1166,7 +1167,7 @@ def _bootstrap_registry_binding(
"project_id": attestation["project_id"],
"bootstrap_root_identity": attestation["bootstrap_root_identity"],
"initial_manifest_hash": attestation["initial_manifest_hash"],
"initial_entry_count": 0,
"initial_entry_count": attestation["initial_entry_count"],
"capability_epoch": attestation["capability_epoch"],
"capability_hash": attestation["capability_hash"],
"attested_input_snapshot_id": attestation["attested_input_snapshot_id"],
Expand Down
3 changes: 2 additions & 1 deletion mcp-tools/devkit_relay/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
_DIGEST = re.compile(r"sha256:[0-9a-f]{64}\Z")
_WORKSPACE_ID = re.compile(r"sha256:[0-9a-f]{64}\Z")
_SCOPE_PATH = re.compile(r"^[A-Za-z]:")
_MAX_BOOTSTRAP_ENTRY_COUNT = 2**63 - 1


class RelayError(RuntimeError):
Expand Down Expand Up @@ -1066,7 +1067,7 @@ def _validated_bootstrap_recompile_binding(
)
or attestation["state"] != "new_empty"
or type(attestation["initial_entry_count"]) is not int
or attestation["initial_entry_count"] != 0
or not 0 <= attestation["initial_entry_count"] <= _MAX_BOOTSTRAP_ENTRY_COUNT
or type(attestation["capability_epoch"]) is not int
or attestation["capability_epoch"] < 1
or not self._finite_timestamp(attestation["issued_at"])
Expand Down
11 changes: 7 additions & 4 deletions mcp-tools/devkit_runtime/relay_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"2718lab-devkit/project-registry-bootstrap-binding-v1"
)
_BOOTSTRAP_RECEIPT_SCHEMA = "2718lab-devkit/project-index-bootstrap-receipt-v1"
_MAX_BOOTSTRAP_ENTRY_COUNT = 2**63 - 1
_PROJECT_BINDING_KEYS = frozenset(
{
"schema",
Expand Down Expand Up @@ -280,7 +281,7 @@ def resolve_new_empty_bootstrap(
if (
attestation["state"] != "new_empty"
or type(attestation["initial_entry_count"]) is not int
or attestation["initial_entry_count"] != 0
or not 0 <= attestation["initial_entry_count"] <= _MAX_BOOTSTRAP_ENTRY_COUNT
):
raise RelayRuntimeError("BOOTSTRAP_PROJECT_NOT_EMPTY")
now = _trusted_time(self._clock)
Expand Down Expand Up @@ -315,7 +316,7 @@ def resolve_new_empty_bootstrap(
"project_id": attestation["project_id"],
"bootstrap_root_identity": attestation["bootstrap_root_identity"],
"initial_manifest_hash": attestation["initial_manifest_hash"],
"initial_entry_count": 0,
"initial_entry_count": attestation["initial_entry_count"],
"capability_epoch": attestation["capability_epoch"],
"capability_hash": attestation["capability_hash"],
"attested_input_snapshot_id": attestation["attested_input_snapshot_id"],
Expand Down Expand Up @@ -406,7 +407,8 @@ def execute(self, registry_binding: Mapping[str, object]) -> dict[str, object]:
or synchronized["attested_input_snapshot_id"]
!= binding["attested_input_snapshot_id"]
or synchronized["initial_manifest_hash"] != binding["initial_manifest_hash"]
or synchronized["initial_entry_count"] != 0
or type(synchronized["initial_entry_count"]) is not int
or synchronized["initial_entry_count"] != binding["initial_entry_count"]
or not _is_hash(synchronized["index_snapshot_id"])
or synchronized["index_identity"] != expected_index_identity
):
Expand Down Expand Up @@ -489,7 +491,8 @@ def _validated_bootstrap_registry_binding(
binding["schema"] != _BOOTSTRAP_REGISTRY_BINDING_SCHEMA
or binding["mode"] != "new_empty_bootstrap"
or binding["bootstrap_only"] is not True
or binding["initial_entry_count"] != 0
or type(binding["initial_entry_count"]) is not int
or not 0 <= binding["initial_entry_count"] <= _MAX_BOOTSTRAP_ENTRY_COUNT
or not _is_hash(binding["binding_hash"])
or binding["binding_hash"]
!= _canonical_hash(_without_hash(binding, "binding_hash"))
Expand Down
2 changes: 1 addition & 1 deletion mcp-tools/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "2718lab-devkit-mcp"
version = "1.1.1"
version = "1.1.2"
description = "MCP runtime for the 2718lab DevKit primary plugin."
requires-python = ">=3.11"
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion mcp-tools/tests/test_bugkiller_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,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.1", codex["version"])
self.assertEqual("1.1.2", codex["version"])
self.assertEqual("./.mcp.json", codex["mcpServers"])
for legacy_surface in ("skills", "agents", "commands", "hooks"):
self.assertNotIn(legacy_surface, codex)
Expand Down
4 changes: 2 additions & 2 deletions mcp-tools/tests/test_primary_artifact.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,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.1"
assert project["project"]["version"] == "1.1.2"
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.1"' in lock_text
assert 'version = "1.1.2"' in lock_text


def test_two_builds_are_byte_identical_with_normalized_zip_metadata(
Expand Down
Loading