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
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ archive_ready: false
| 1. 蓝图 delta 校验 | ✅ 完成 | 5 项审计全通过 |
| 2. 当前消费者扫描 | ✅ 完成 | 4 类清单 + consumer 判定 |
| 3. 删除就绪结论 | ✅ 完成 | kernel 边界锁定, 退场量级 ~38K LOC |
| 4. 审计后删除 | ✅ 主线完成 | 4.1-4.5/4.6/4.7-4.10a/4.10c/4.10d/4.13-A/4.13-B ✅; 4.10b/4.11/4.12/4.13 Phase B 待后续 |
| 4. 审计后删除 | ✅ 主线完成 | 4.1-4.5/4.6/4.7-4.10a/4.10b/4.10c/4.10d/4.13-A/4.13-B ✅; 4.11/4.12/4.13 Phase B 待后续 |
| 5. 文档更新 | ⚠️ 部分完成 | 5.1/5.2/5.3 ✅; 5.4/5.5/5.6/5.7 待后续 |
| 6. contract 面清理 + engine 重构 | ✅ 完成 | 6.1-6.6 全部收完, −6,400+ LOC |

Expand Down Expand Up @@ -183,7 +183,7 @@ archive_ready: false
> - run_runtime() 兼容 wrapper 仍在 engine.py,尚未删除
> - _kernel_turn 仍包含 11 个 non-kernel route handler 的分发逻辑
> - 以上均属 Package A 范围
- [ ] 4.10b **Step 3 Package A: _kernel_turn → engine 依赖切断 + 合同面审计 + 批量删除** — re-scoped / partial close (2026-05-23)
- [x] 4.10b **Step 3 Package A: _kernel_turn → engine 依赖切断 + 合同面审计 + 批量删除** — re-scoped / partial close (2026-05-23); **plan_scaffold 单职责重构 + runtime/plan/ 包化** ✅ 完成 (2026-05-25)
> 判断边界: 按"当前宿主可见 contract 还在不在"删,不按模块名猜测。行为还需要但文件不需要时,优先内联到 retained 模块;不新造模块/层次/public surface。
>
> **A1: _kernel_turn → engine 依赖切断(仅切实现耦合,不删功能面)** ✅ 完成
Expand Down Expand Up @@ -211,7 +211,7 @@ archive_ready: false
> | `plan_registry.py` | 953 | **retain as independent governance layer** ✅ 6.5 裁定 | _planning.py + archive_lifecycle + output; YAML 写入已迁出到 _yaml.py |
> | `skill_registry.py` | — | **deleted** ✅ 6.4 | discovery 退场 |
> | `skill_resolver.py` | — | **deleted** ✅ 6.4 | resolve_route_candidate_skills 退场,candidate_skill_ids 改为静态 tuple |
> | `plan_scaffold.py` | 466 | **retain as single-purpose module** ✅ 维护者确认 | 6.6b 后 runtime 消费者仅 _planning.py; tests 消费者仍多。暂不内联,后续只做主链单职责瘦身 |
> | `plan_scaffold.py` | 466→~200 | **refactored → runtime/plan/ package** ✅ 4.10b 完成 (2026-05-25) | 拆为 scaffold/lookup/intent/identity 4 个单职责模块 + registry.py 迁入; create_plan_scaffold() registry side-effect 上提到 _planning.py; 626 tests green |
> | `skill_runner.py` | — | **deleted** ✅ 4.10b A3 | 悬空路径 |
>
> 5 个模块 (archive_lifecycle / kb / clarification / decision / context_recovery) 经维护者确认为 retain as module。
Expand All @@ -222,7 +222,7 @@ archive_ready: false
> **A3: 立即删除面** ✅ 收口
> - 已完成: runtime skill execution sidecar (-187 LOC) ✅ 2141ed6
> - 否决: 38 项大内联方案(~1,655 LOC 搬进 _kernel_turn.py 是换文件名不收缩)
> - 剩余: plan_scaffold.py (464 LOC) 保留独立模块;后续若继续瘦身,仅做职责收窄审计与测试收口,不再以“内联/删文件”为目标
> - 剩余: plan_scaffold.py 已完成单职责重构 ✅ (2026-05-25):拆为 runtime/plan/{scaffold,lookup,intent,identity,registry}.py; create_plan_scaffold() 不再含 registry write
> - engine.py: 6.6 完成后已瘦身至 343 LOC(conflict/cancel + activation + archive + run_runtime wrapper);planning 主块已迁出到 _planning.py
> - S3.1 大 co-delete 表不再作为执行清单;已降级为旧假设
- [x] 4.10c Step 3 Package C: models.py bridge 退场 ✅ 完成 (2026-05-23)
Expand Down
45 changes: 45 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,51 @@ Format: Summary → Changed → Plan Packages. File-level details live in `git l

## [Unreleased]

## [2026-05-26.092824] - 2026-05-26

### Summary

- Changes across: Docs, Runtime, Skills, Tests.

### Changed

- **Docs**: Refined public documentation (2 files)
- **Runtime**: Updated runtime internals (12 files)
- **Skills**: Synced prompt-layer skills (4 files)
- **Tests**: Updated automated coverage (6 files)

## [2026-05-26.092444] - 2026-05-26

### Summary

- Changes across: Runtime.

### Changed

- **Runtime**: Updated runtime internals (1 files)

## [2026-05-26.092057] - 2026-05-26

### Summary

- Changes across: Runtime, Tests.

### Changed

- **Runtime**: Updated runtime internals (15 files)
- **Tests**: Updated automated coverage (5 files)

## [2026-05-25.194723] - 2026-05-25

### Summary

- Changes across: Runtime, Tests.

### Changed

- **Runtime**: Updated runtime internals (5 files)
- **Tests**: Updated automated coverage (5 files)

## [2026-05-24.205420] - 2026-05-24

### Summary
Expand Down
2 changes: 1 addition & 1 deletion Claude/Skills/CN/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- bootstrap: lang=zh-CN; encoding=UTF-8 -->
<!-- SOPIFY_VERSION: 2026-05-24.205420 -->
<!-- SOPIFY_VERSION: 2026-05-26.092824 -->
<!-- ARCHITECTURE: Adaptive Workflow + Layered Rules -->

# Sopify - 自适应 AI 编程助手
Expand Down
2 changes: 1 addition & 1 deletion Claude/Skills/EN/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- bootstrap: lang=en-US; encoding=UTF-8 -->
<!-- SOPIFY_VERSION: 2026-05-24.205420 -->
<!-- SOPIFY_VERSION: 2026-05-26.092824 -->
<!-- ARCHITECTURE: Adaptive Workflow + Layered Rules -->

# Sopify - Adaptive AI Programming Assistant
Expand Down
2 changes: 1 addition & 1 deletion Codex/Skills/CN/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- bootstrap: lang=zh-CN; encoding=UTF-8 -->
<!-- SOPIFY_VERSION: 2026-05-24.205420 -->
<!-- SOPIFY_VERSION: 2026-05-26.092824 -->
<!-- ARCHITECTURE: Adaptive Workflow + Layered Rules -->

# Sopify - 自适应 AI 编程助手
Expand Down
2 changes: 1 addition & 1 deletion Codex/Skills/EN/AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!-- bootstrap: lang=en-US; encoding=UTF-8 -->
<!-- SOPIFY_VERSION: 2026-05-24.205420 -->
<!-- SOPIFY_VERSION: 2026-05-26.092824 -->
<!-- ARCHITECTURE: Adaptive Workflow + Layered Rules -->

# Sopify - Adaptive AI Programming Assistant
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE)
[![Docs](https://img.shields.io/badge/docs-CC%20BY%204.0-green.svg)](./LICENSE-docs)
[![Version](https://img.shields.io/badge/version-2026--05--24.205420-orange.svg)](#version-history)
[![Version](https://img.shields.io/badge/version-2026--05--26.092824-orange.svg)](#version-history)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING.md)

English · [简体中文](./README.zh-CN.md) · [Quick Start](#quick-start) · [Contributors](./CONTRIBUTORS.md)
Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

[![许可证](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](./LICENSE)
[![文档](https://img.shields.io/badge/docs-CC%20BY%204.0-green.svg)](./LICENSE-docs)
[![版本](https://img.shields.io/badge/version-2026--05--24.205420-orange.svg)](#版本历史)
[![版本](https://img.shields.io/badge/version-2026--05--26.092824-orange.svg)](#版本历史)
[![欢迎PR](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](./CONTRIBUTING_CN.md)

[English](./README.md) · 简体中文 · [快速开始](#快速开始) · [贡献者](./CONTRIBUTORS.md)
Expand Down
20 changes: 14 additions & 6 deletions runtime/_planning.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
from sopify_contracts.artifacts import KbArtifact, PlanArtifact
from sopify_contracts.core import ExecutionGate, RouteDecision, RunState, RuntimeConfig
from sopify_contracts.decision import ClarificationState, DecisionState
from .plan_registry import (
from .plan.registry import (
PlanRegistryError,
encode_priority_note_event,
priority_note_for_plan,
upsert_plan_entry,
)
from .plan_scaffold import (
create_plan_scaffold,
find_plan_by_request_reference,
request_explicitly_wants_new_plan,
)
from .plan.scaffold import create_plan_scaffold
from .plan.lookup import find_plan_by_request_reference
from .plan.intent import request_explicitly_wants_new_plan
from canonical_writer import StateStore, iso_now
from .state import (
make_run_id,
Expand Down Expand Up @@ -917,6 +917,14 @@ def _advance_planning_route(
level=level,
decision_state=confirmed_decision,
)
try:
upsert_plan_entry(
config=config,
artifact=created,
request_text=decision.request_text,
)
except PlanRegistryError:
pass
state_store.set_current_plan(created)
kb_artifact = _merge_kb_artifacts(kb_artifact, ensure_blueprint_index(config), config=config)
notes.extend(
Expand Down
2 changes: 1 addition & 1 deletion runtime/archive_lifecycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from .knowledge_sync import KNOWLEDGE_SYNC_KEYS, knowledge_sync_targets, parse_knowledge_sync
from sopify_contracts.artifacts import KbArtifact, PlanArtifact
from sopify_contracts.core import RuntimeConfig
from .plan_registry import PlanRegistryError, remove_plan_entry
from .plan.registry import PlanRegistryError, remove_plan_entry
from canonical_writer import StateStore, iso_now

ARCHIVE_STATUS_COMPLETED = "completed"
Expand Down
2 changes: 1 addition & 1 deletion runtime/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from sopify_contracts.core import RouteDecision, RunState, RuntimeConfig, SkillMeta
from sopify_contracts.decision import ClarificationState, DecisionState
from sopify_contracts.handoff import RuntimeHandoff, RuntimeResult, SkillActivation
from .plan_registry import (
from .plan.registry import (
PlanRegistryError,
get_plan_entry,
registry_relative_path,
Expand Down
2 changes: 1 addition & 1 deletion runtime/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .decision import CURRENT_DECISION_RELATIVE_PATH
from .handoff import CURRENT_HANDOFF_RELATIVE_PATH
from sopify_contracts.handoff import RuntimeResult
from .plan_registry import extract_priority_note_event
from .plan.registry import extract_priority_note_event

_PHASE_LABELS = {
"zh-CN": {
Expand Down
9 changes: 9 additions & 0 deletions runtime/plan/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Plan subsystem for Sopify runtime.

Submodules:
- scaffold: plan package creation and rendering
- lookup: plan discovery and loading from disk
- intent: new-plan intent detection (text heuristics)
- identity: shared naming helpers (derive_topic_key)
- registry: plan governance and priority tracking
"""
21 changes: 21 additions & 0 deletions runtime/plan/identity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Plan identity helpers shared by scaffold creation and plan lookup."""

from __future__ import annotations

from hashlib import sha1
import re


def derive_topic_key(request_text: str) -> str:
cleaned = " ".join(request_text.split())
if not cleaned:
return "task"
normalized = _slugify(cleaned)[:48].rstrip("-")
if normalized:
return normalized
return f"task-{sha1(cleaned.encode('utf-8')).hexdigest()[:6]}"


def _slugify(value: str) -> str:
ascii_slug = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
return ascii_slug or "task"
66 changes: 66 additions & 0 deletions runtime/plan/intent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
"""Plan intent detection for Sopify runtime.

Determines whether a user request explicitly asks for a new plan,
distinguishing genuine "create new plan" phrases from negated forms.
"""

from __future__ import annotations

import re
from typing import Sequence

_EXPLICIT_NEW_PLAN_PATTERNS = (
re.compile(r"\bnew\s+plan\b", re.IGNORECASE),
re.compile(r"\bcreate\s+(?:a\s+)?new\s+plan\b", re.IGNORECASE),
re.compile(r"新建(?:一个)?\s*plan", re.IGNORECASE),
re.compile(r"新\s*plan", re.IGNORECASE),
re.compile(r"新的\s*plan", re.IGNORECASE),
re.compile(r"另起(?:一个)?\s*plan", re.IGNORECASE),
re.compile(r"新增(?:一个)?\s*plan", re.IGNORECASE),
)
_NEGATED_NEW_PLAN_PATTERNS = (
re.compile(
r"(?:不要|别|不用|无需|禁止)\s*(?:再|另外|额外|单独)?\s*(?:新建(?:一个)?(?:新的)?\s*plan|新\s*plan|新的\s*plan)",
re.IGNORECASE,
),
re.compile(r"(?:do\s+not|don't|dont|no\s+need\s+to)\s+(?:create\s+(?:a\s+)?new\s+plan|new\s+plan)", re.IGNORECASE),
)


def request_explicitly_wants_new_plan(request_text: str) -> bool:
normalized = " ".join(request_text.split())
matches = _collect_new_plan_intent_matches(normalized)
effective_matches = _drop_positive_matches_covered_by_negated(matches)
if not effective_matches:
return False
last_match = max(effective_matches, key=lambda item: (item[0], item[1]))
return last_match[2] == "positive"


def _collect_new_plan_intent_matches(text: str) -> list[tuple[int, int, str]]:
seen: set[tuple[int, int, str]] = set()
ordered: list[tuple[int, int, str]] = []
for polarity, patterns in (
("negated", _NEGATED_NEW_PLAN_PATTERNS),
("positive", _EXPLICIT_NEW_PLAN_PATTERNS),
):
for pattern in patterns:
for match in pattern.finditer(text):
span = (match.start(), match.end(), polarity)
if span in seen:
continue
seen.add(span)
ordered.append(span)
return ordered


def _drop_positive_matches_covered_by_negated(
matches: Sequence[tuple[int, int, str]],
) -> list[tuple[int, int, str]]:
negated_spans = [(start, end) for start, end, polarity in matches if polarity == "negated"]
effective: list[tuple[int, int, str]] = []
for start, end, polarity in matches:
if polarity == "positive" and any(neg_start <= start and end <= neg_end for neg_start, neg_end in negated_spans):
continue
effective.append((start, end, polarity))
return effective
Loading
Loading