Files
claw/docs/superpowers/plans/2026-04-09-ws-branch-scene-cleanup-plan.md
木炎 81de162756 docs: add ws branch cleanup plan
Document the post-main cleanup steps for removing staged scene routing from the ws branch while preserving websocket and Zhihu flows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 11:13:43 +08:00

666 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WS Branch Scene Cleanup Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Strip `feature/claw-ws` back to websocket plus Zhihu execution only by removing staged scene-skill routing, `skill_staging`-aware loading, and array-style `skillsDir` config behavior from this branch.
**Architecture:** Treat `feature/claw-ws` as a transport-focused branch, not a business-scene branch. Keep the browser websocket/callback submit path and the existing Zhihu direct workflows, but delete the fault-details / `95598` scene registry, scene-specific prompt injection, staged scene directory expansion, and scene-only docs/tests so the branch stays small and merges cleanly after the real scene implementation lands on `main`.
**Tech Stack:** Rust 2021, existing sgClaw compat/runtime/orchestration stack, websocket browser backend, callback-host service path, existing `cargo test` suite.
---
## Preconditions
- Execute this plan **only after** `main` already contains the desired clean scene-skill implementation.
- Run it on `feature/claw-ws`, not on `main`.
- Keep websocket and Zhihu behavior intact; this plan is cleanup, not a redesign.
- Keep `docs/_tmp_sgbrowser_ws_api_doc.txt`; it remains the browser integration contract for this branch.
## Scope Guardrails
- Do **not** change the working Zhihu websocket flow in `tests/agent_runtime_test.rs`.
- Do **not** remove `src/browser/ws_backend.rs`, `src/service/server.rs`, or Zhihu routes from `src/compat/workflow_executor.rs`.
- Do **not** add a replacement scene abstraction on this branch.
- Do **not** keep partial scene plumbing “for future use”; delete it completely if it is scene-only.
- Do **not** keep array-style `skillsDir` tests or docs on this branch once the single-path cleanup is complete.
---
## File Map
### Delete
- `src/runtime/scene_registry.rs`
- staged scene registry, hard-coded `skill_staging` scene root, scene matching helpers
- `tests/scene_registry_test.rs`
- scene-registry-specific coverage that should disappear with the feature
- `docs/superpowers/specs/2026-04-06-scene-skill-runtime-routing-design.md`
- scene-routing design doc that no longer belongs on the ws-only branch
- `docs/superpowers/plans/2026-04-06-scene-skill-runtime-routing-plan.md`
- scene-routing implementation plan that no longer belongs on the ws-only branch
### Modify
- `src/runtime/mod.rs`
- stop exporting deleted scene registry APIs
- `src/runtime/engine.rs`
- remove scene-contract prompt injection and staged scene skill loading
- `src/compat/workflow_executor.rs`
- remove `FaultDetailsReport` route detection/execution while keeping Zhihu routes
- `src/compat/orchestration.rs`
- keep direct Zhihu orchestration only; remove scene-driven primary routing triggers
- `src/config/settings.rs`
- collapse `skillsDir` config handling back to single-path semantics
- `src/compat/config_adapter.rs`
- remove scene-specific skills-dir helpers and keep one resolved skills dir
- `src/compat/runtime.rs`
- stop carrying scene-expanded skills dirs through compat runtime
- `src/agent/task_runner.rs`
- update runtime logging and runtime calls to the single skills-dir contract
- `tests/compat_runtime_test.rs`
- remove fault-details / `95598` assertions and keep Zhihu/direct-route coverage
- `tests/runtime_profile_test.rs`
- remove `95598` scene-contract expectations and keep normal browser-profile coverage
- `tests/compat_config_test.rs`
- remove scene-dir / array-config coverage and add single-path cleanup coverage
- `tests/agent_runtime_test.rs`
- only extend if one extra Zhihu keep-path regression is needed after the config cleanup
### Keep As-Is Unless A Signature Change Forces A Tiny Edit
- `src/browser/ws_backend.rs`
- `src/browser/callback_backend.rs`
- `src/browser/callback_host.rs`
- `src/service/server.rs`
- `src/agent/mod.rs`
- `tests/browser_ws_backend_test.rs`
- `tests/service_ws_session_test.rs`
- `tests/task_runner_test.rs`
---
### Task 1: Lock The Cleanup Contract In Failing Tests
**Files:**
- Modify: `tests/compat_runtime_test.rs`
- Modify: `tests/runtime_profile_test.rs`
- Modify: `tests/compat_config_test.rs`
- Reuse: `tests/agent_runtime_test.rs`
- [ ] **Step 1: Add the first failing route-removal test**
In `tests/compat_runtime_test.rs`, add a focused assertion proving the ws branch no longer recognizes the fault-details scene as a direct route:
```rust
#[test]
fn ws_cleanup_no_longer_detects_fault_details_scene_route() {
use sgclaw::compat::workflow_executor::detect_route;
assert_eq!(
detect_route(
"导出故障明细",
Some("https://example.invalid/workbench"),
Some("业务台账"),
),
None,
);
}
```
- [ ] **Step 2: Run the focused route test and verify it fails**
Run:
```bash
cargo test --test compat_runtime_test ws_cleanup_no_longer_detects_fault_details_scene_route -- --nocapture
```
Expected: FAIL because `FaultDetailsReport` is still detected today.
- [ ] **Step 3: Add the second failing orchestration-gate test**
In `tests/compat_runtime_test.rs`, add one focused assertion proving scene keywords no longer open the primary direct-orchestration path:
```rust
#[test]
fn ws_cleanup_scene_keywords_do_not_trigger_primary_orchestration() {
assert!(!sgclaw::compat::orchestration::should_use_primary_orchestration(
"请处理95598抢修市指监测",
Some("https://95598.example.invalid/dispatch"),
Some("95598抢修市指监测"),
));
}
```
- [ ] **Step 4: Run the orchestration-gate test and verify it fails**
Run:
```bash
cargo test --test compat_runtime_test ws_cleanup_scene_keywords_do_not_trigger_primary_orchestration -- --nocapture
```
Expected: FAIL because the scene matcher still feeds primary orchestration today.
- [ ] **Step 5: Add the third failing runtime-instruction test**
In `tests/runtime_profile_test.rs`, add a focused negative assertion proving browser-attached turns no longer receive the `95598` scene execution contract:
```rust
#[test]
fn ws_cleanup_browser_profile_does_not_inject_95598_scene_contract() {
let engine = RuntimeEngine::new(RuntimeProfile::BrowserAttached);
let instruction = engine.build_instruction(
"请处理95598-repair-city-dispatch场景查看抢修市指派单并汇总当前队列",
Some("https://95598.example.invalid/dispatch"),
Some("95598抢修市指监测"),
true,
);
assert!(!instruction.contains("95598-repair-city-dispatch.collect_repair_orders"));
}
```
- [ ] **Step 6: Run the runtime-profile test and verify it fails**
Run:
```bash
cargo test --test runtime_profile_test ws_cleanup_browser_profile_does_not_inject_95598_scene_contract -- --nocapture
```
Expected: FAIL because `src/runtime/engine.rs` still injects the scene contract today.
- [ ] **Step 7: Add the fourth failing config-shape test**
In `tests/compat_config_test.rs`, add one focused assertion proving ws cleanup goes back to a single configured skills path and no longer accepts array-style `skillsDir` JSON:
```rust
#[test]
fn ws_cleanup_rejects_array_style_skills_dir_config() {
let root = std::env::temp_dir().join(format!("sgclaw-config-{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(&root).unwrap();
let config_path = root.join("sgclaw_config.json");
std::fs::write(
&config_path,
r#"{
"apiKey": "sk-test",
"baseUrl": "https://api.deepseek.com",
"model": "deepseek-chat",
"skillsDir": ["skill_lib", "skill_staging"]
}"#,
)
.unwrap();
assert!(sgclaw::config::SgClawSettings::load(Some(config_path.as_path())).is_err());
}
```
- [ ] **Step 8: Run the config-shape test and verify it fails**
Run:
```bash
cargo test --test compat_config_test ws_cleanup_rejects_array_style_skills_dir_config -- --nocapture
```
Expected: FAIL because the current parser still accepts string-or-array `skillsDir` input.
- [ ] **Step 9: Re-run the existing Zhihu keep-path test as a safety baseline**
Run:
```bash
cargo test --test agent_runtime_test production_submit_task_routes_zhihu_through_ws_backend_without_helper_bootstrap -- --nocapture
```
Expected: PASS, proving the behavior we want to keep is already covered before deletion starts.
---
### Task 2: Remove Scene Registry, Scene Prompt Injection, And Fault-Details Routing
**Files:**
- Delete: `src/runtime/scene_registry.rs`
- Modify: `src/runtime/mod.rs`
- Modify: `src/runtime/engine.rs`
- Modify: `src/compat/workflow_executor.rs`
- Modify: `src/compat/orchestration.rs`
- Modify: `tests/compat_runtime_test.rs`
- Modify: `tests/runtime_profile_test.rs`
- Delete: `tests/scene_registry_test.rs`
- [ ] **Step 1: Remove the runtime scene module export surface**
Update `src/runtime/mod.rs` so it no longer declares or re-exports scene registry items.
Target shape:
```rust
mod engine;
mod profile;
mod tool_policy;
pub use engine::{
is_zhihu_hotlist_task,
is_zhihu_write_task,
task_requests_zhihu_article_publish,
RuntimeEngine,
};
pub use profile::RuntimeProfile;
pub use tool_policy::ToolPolicy;
```
- [ ] **Step 2: Delete `src/runtime/scene_registry.rs`**
Remove the file entirely. Do not leave a stub module or comments about future scene support.
- [ ] **Step 3: Remove scene-aware prompt injection from `src/runtime/engine.rs`**
Delete:
- the `resolve_scene_skills_dir_path` import
- the `DispatchMode` / `match_scene_instruction` imports
- `REPAIR_CITY_DISPATCH_EXECUTION_PROMPT`
- `build_scene_execution_contract(...)`
- the `if let Some(scene_contract) = ...` block inside `RuntimeEngine::build_instruction(...)`
- staged scene directory loading inside `load_runtime_skills(...)`
The resulting instruction assembly should keep:
- browser tool contract
- Zhihu hotlist/export prompts
- Zhihu publish guard
- page context
Do **not** change Zhihu prompt text.
- [ ] **Step 4: Remove the fault-details route from `src/compat/workflow_executor.rs`**
Shrink `WorkflowRoute` back to Zhihu-only variants:
```rust
pub enum WorkflowRoute {
ZhihuHotlistExportXlsx,
ZhihuHotlistScreen,
ZhihuArticleEntry,
ZhihuArticleDraft,
ZhihuArticlePublish,
ZhihuArticleAutoPublishGenerated,
}
```
Delete:
- `FAULT_DETAILS_SCENE_ID`
- the scene check at the top of `detect_route(...)`
- `WorkflowRoute::FaultDetailsReport`
- `execute_fault_details_route(...)`
- any scene-only helpers used only by that path
Keep the Zhihu route order unchanged.
- [ ] **Step 5: Simplify `src/compat/orchestration.rs` to Zhihu-only direct routing**
After the fault-details route is gone, keep `should_use_primary_orchestration(...)` and the two execute functions focused on:
- Zhihu direct routes detected by `detect_route(...)`
- existing Zhihu export/dashboard fallback behavior
Do not add new conditions.
- [ ] **Step 6: Remove scene-only tests and replace them with cleanup assertions**
In `tests/compat_runtime_test.rs` and `tests/runtime_profile_test.rs`:
- delete `fault-details` assertions that require the old route to exist
- delete `95598` scene-contract assertions that require the old prompt injection to exist
- keep the new negative cleanup tests from Task 1
- keep the existing Zhihu assertions intact
Delete `tests/scene_registry_test.rs` completely.
- [ ] **Step 7: Run the focused cleanup tests**
Run:
```bash
cargo test --test compat_runtime_test ws_cleanup_no_longer_detects_fault_details_scene_route -- --nocapture && cargo test --test compat_runtime_test ws_cleanup_scene_keywords_do_not_trigger_primary_orchestration -- --nocapture && cargo test --test runtime_profile_test ws_cleanup_browser_profile_does_not_inject_95598_scene_contract -- --nocapture
```
Expected: PASS.
- [ ] **Step 8: Re-run the focused Zhihu runtime tests**
Run:
```bash
cargo test --test compat_runtime_test zhihu_ -- --nocapture
```
Expected: PASS, proving the Zhihu direct routes still work after the scene deletion.
- [ ] **Step 9: Commit Task 2**
```bash
git add src/runtime/mod.rs src/runtime/engine.rs src/compat/workflow_executor.rs src/compat/orchestration.rs tests/compat_runtime_test.rs tests/runtime_profile_test.rs
git rm src/runtime/scene_registry.rs tests/scene_registry_test.rs
git commit -m "refactor: remove scene routing from ws branch"
```
---
### Task 3: Collapse `skillsDir` Back To Single-Path Semantics
**Files:**
- Modify: `src/config/settings.rs`
- Modify: `src/compat/config_adapter.rs`
- Modify: `src/compat/runtime.rs`
- Modify: `src/agent/task_runner.rs`
- Modify if needed: `tests/agent_runtime_test.rs`
- Modify: `tests/compat_config_test.rs`
- [ ] **Step 1: Change config parsing to a single configured skills path**
In `src/config/settings.rs`, replace the string-or-array parser with a single optional string field.
Target shape:
```rust
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeepSeekSettings {
pub api_key: String,
pub base_url: String,
pub model: String,
pub skills_dir: Option<PathBuf>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SgClawSettings {
// ...
pub skills_dir: Option<PathBuf>,
// ...
}
```
And in `RawSgClawSettings`:
```rust
#[serde(rename = "skillsDir", alias = "skills_dir", default)]
skills_dir: Option<String>,
```
Delete `deserialize_skills_dirs(...)` entirely.
- [ ] **Step 2: Keep relative-path resolution, but only for one path**
Replace `resolve_configured_skills_dirs(...) -> Vec<PathBuf>` with a single-path helper such as:
```rust
fn resolve_configured_skills_dir(raw: Option<String>, config_dir: &Path) -> Option<PathBuf> {
raw.map(|value| value.trim().to_string())
.filter(|value| !value.is_empty())
.map(PathBuf::from)
.map(|path| if path.is_absolute() { path } else { config_dir.join(path) })
}
```
- [ ] **Step 3: Collapse compat config adapter back to one resolved skills dir**
In `src/compat/config_adapter.rs`:
- keep `zeroclaw_default_skills_dir(...)`
- change `resolve_skills_dir(...)` and `resolve_skills_dir_from_sgclaw_settings(...)` to return a single `PathBuf`
- delete `resolve_scene_skills_dir_from_sgclaw_settings(...)`
- delete `resolve_scene_skills_dir_path(...)`
- delete any helper branches that append `skill_staging/skills`
Recommended shape:
```rust
pub fn resolve_skills_dir_from_sgclaw_settings(
workspace_root: &Path,
settings: &SgClawSettings,
) -> PathBuf {
settings
.skills_dir
.as_ref()
.map(|dir| normalize_configured_skills_dir(dir))
.unwrap_or_else(|| zeroclaw_default_skills_dir(workspace_root))
}
```
- [ ] **Step 4: Update runtime callers to the single-path contract**
In `src/compat/runtime.rs` and `src/agent/task_runner.rs`:
- stop passing vectors of skills dirs around
- update logging from `skills dirs resolved to [...]` to a single-path message such as `skills dir resolved to ...`
- keep the rest of the runtime behavior unchanged
In `src/runtime/engine.rs`, if the method still needs a collection internally, convert the one path at the call site instead of preserving public multi-root plumbing.
- [ ] **Step 5: Replace config tests with single-path cleanup coverage**
In `tests/compat_config_test.rs`:
- keep single-string `skillsDir` resolution tests
- remove `resolve_scene_skills_dir_path_*` coverage
- remove array-acceptance expectations
- keep the new rejecting-array test from Task 1
Add one focused positive test like:
```rust
#[test]
fn ws_cleanup_resolves_single_configured_skills_dir() {
let root = std::env::temp_dir().join(format!("sgclaw-skills-{}", uuid::Uuid::new_v4()));
std::fs::create_dir_all(root.join("skill_lib/skills")).unwrap();
let settings = DeepSeekSettings {
api_key: "key".to_string(),
base_url: "https://api.deepseek.com".to_string(),
model: "deepseek-chat".to_string(),
skills_dir: Some(root.join("skill_lib")),
};
assert_eq!(
resolve_skills_dir(&root, &settings),
root.join("skill_lib/skills"),
);
}
```
- [ ] **Step 6: Run the focused config tests**
Run:
```bash
cargo test --test compat_config_test ws_cleanup_ -- --nocapture
```
Expected: PASS.
- [ ] **Step 7: Re-run the Zhihu websocket keep-path test**
Run:
```bash
cargo test --test agent_runtime_test production_submit_task_routes_zhihu_through_ws_backend_without_helper_bootstrap -- --nocapture
```
Expected: PASS.
- [ ] **Step 8: Commit Task 3**
```bash
git add src/config/settings.rs src/compat/config_adapter.rs src/compat/runtime.rs src/agent/task_runner.rs tests/compat_config_test.rs tests/agent_runtime_test.rs
git commit -m "refactor: restore single skills dir on ws branch"
```
---
### Task 4: Remove Scene-Only Docs And Residual Test References
**Files:**
- Delete: `docs/superpowers/specs/2026-04-06-scene-skill-runtime-routing-design.md`
- Delete: `docs/superpowers/plans/2026-04-06-scene-skill-runtime-routing-plan.md`
- Modify: `tests/compat_runtime_test.rs`
- Modify: `tests/runtime_profile_test.rs`
- Modify: `tests/compat_config_test.rs`
- [ ] **Step 1: Delete the two scene-only planning documents**
Remove exactly these files:
- `docs/superpowers/specs/2026-04-06-scene-skill-runtime-routing-design.md`
- `docs/superpowers/plans/2026-04-06-scene-skill-runtime-routing-plan.md`
Keep the websocket/browser docs and Zhihu docs.
- [ ] **Step 2: Sweep remaining tests for scene-only names**
Remove or rewrite any remaining test blocks that still require:
- `fault-details-report`
- `95598-repair-city-dispatch`
- `resolve_scene_skills_dir_path`
- `resolve_scene_skills_dir_from_sgclaw_settings`
- `scene_registry`
Do not delete Zhihu-related assertions during this sweep.
- [ ] **Step 3: Run a focused grep-style audit from the shell**
Run:
```bash
git grep -n "fault-details-report\|95598-repair-city-dispatch\|resolve_scene_skills_dir_path\|resolve_scene_skills_dir_from_sgclaw_settings\|scene_registry" -- src tests docs
```
Expected: no matches in `src/` or `tests/`; doc matches should be gone after the deletions.
- [ ] **Step 4: Commit Task 4**
```bash
git add tests/compat_runtime_test.rs tests/runtime_profile_test.rs tests/compat_config_test.rs
git rm docs/superpowers/specs/2026-04-06-scene-skill-runtime-routing-design.md docs/superpowers/plans/2026-04-06-scene-skill-runtime-routing-plan.md
git commit -m "docs: remove ws-only scene planning artifacts"
```
---
### Task 5: Verify The Branch Is Back To WS Plus Zhihu Only
**Files:**
- Verify only unless a failing test proves one tiny follow-up fix is needed
- [ ] **Step 1: Run the retained Zhihu websocket regression**
Run:
```bash
cargo test --test agent_runtime_test production_submit_task_routes_zhihu_through_ws_backend_without_helper_bootstrap -- --nocapture
```
Expected: PASS.
- [ ] **Step 2: Run websocket/backend focused coverage**
Run:
```bash
cargo test --test browser_ws_backend_test -- --nocapture && cargo test --test service_ws_session_test -- --nocapture
```
Expected: PASS.
- [ ] **Step 3: Run direct-route/runtime Zhihu coverage**
Run:
```bash
cargo test --test compat_runtime_test zhihu_ -- --nocapture && cargo test --test task_runner_test -- --nocapture
```
Expected: PASS.
- [ ] **Step 4: Run config/runtime verification after the single-dir cleanup**
Run:
```bash
cargo test --test compat_config_test -- --nocapture && cargo test --test runtime_profile_test -- --nocapture
```
Expected: PASS.
- [ ] **Step 5: Build the affected binaries**
Run:
```bash
cargo build --bin sgclaw --bin sg_claw --bin sg_claw_client
```
Expected: PASS.
- [ ] **Step 6: Audit the remaining branch diff against `main`**
Run:
```bash
git diff --stat main...HEAD
```
Expected: the remaining meaningful differences are websocket/browser transport work and Zhihu-related behavior, not scene-routing or staged-scene config churn.
- [ ] **Step 7: Commit the final verification pass**
```bash
git add src/config/settings.rs src/compat/config_adapter.rs src/compat/runtime.rs src/compat/workflow_executor.rs src/compat/orchestration.rs src/runtime/mod.rs src/runtime/engine.rs tests/compat_config_test.rs tests/runtime_profile_test.rs tests/compat_runtime_test.rs tests/agent_runtime_test.rs tests/task_runner_test.rs
git commit -m "test: verify ws branch cleanup preserves zhihu websocket flow"
```
---
## Verification Checklist
### Cleanup regressions
```bash
cargo test --test compat_runtime_test ws_cleanup_ -- --nocapture
cargo test --test runtime_profile_test ws_cleanup_ -- --nocapture
cargo test --test compat_config_test ws_cleanup_ -- --nocapture
```
Expected: scene detection, scene prompt injection, and array-style `skillsDir` behavior are gone.
### Retained Zhihu websocket behavior
```bash
cargo test --test agent_runtime_test production_submit_task_routes_zhihu_through_ws_backend_without_helper_bootstrap -- --nocapture
cargo test --test browser_ws_backend_test -- --nocapture
cargo test --test service_ws_session_test -- --nocapture
cargo test --test compat_runtime_test zhihu_ -- --nocapture
```
Expected: websocket submit path and Zhihu direct workflows still pass.
### Runtime/config verification
```bash
cargo test --test compat_config_test -- --nocapture
cargo test --test runtime_profile_test -- --nocapture
cargo test --test task_runner_test -- --nocapture
```
Expected: runtime/config plumbing is stable after the single-dir cleanup.
### Build verification
```bash
cargo build --bin sgclaw --bin sg_claw --bin sg_claw_client
```
Expected: the branch still compiles cleanly.
---
## Notes For The Engineer
- The current scene support touches three different seams: runtime prompt injection, direct route detection/execution, and multi-root `skillsDir` plumbing. Remove all three; deleting only one leaves conflict-prone leftovers.
- If collapsing `skillsDir` to `Option<PathBuf>` creates more churn than expected, keep the internal representation temporarily as a one-element collection, but the public config contract and tests on this branch must still go back to a single configured path.
- Do not delete browser websocket or callback-host code just because it is adjacent to the scene work; this plan is about stripping scene behavior, not reworking transport.
- If `git diff --stat main...HEAD` still shows scene-specific files after Task 5, stop and remove them before merging `main` back into this branch.