# 标题自动编号全局选项实施计划

> **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:** 让标题自动编号成为可关闭的全局页面选项，默认关闭，关闭时不在文档页和本地 Markdown 页面中自动渲染数字标题。

**Architecture:** 以 `PageOptions.show_heading_numbers` 作为唯一开关真源，Rust core 默认值改为关闭，`mnote-web` 的本地文件夹与文档壳读取时同步遵循该默认值；前端 page options fallback 保持与 Rust 一致。现有页面设置面板继续复用该开关，不新增第二套编号逻辑。

**Tech Stack:** Rust (`core-protocol`, `mnote-web`), TypeScript/React (`wolai-frontend`), Playwright smoke, existing Rust unit tests.

---

### Task 1: 先写失败测试，钉死默认关闭与本地显式覆盖

**Files:**
- Modify: `rust/crates/core-protocol/src/page_aggregate.rs`
- Modify: `rust/crates/mnote-web/src/routes/local_folder_source.rs`

- [ ] **Step 1: 写失败测试**

```rust
#[test]
fn page_options_default_disables_heading_numbers() {
    assert!(!PageOptions::default().show_heading_numbers);
}

#[test]
fn local_page_options_metadata_can_toggle_heading_numbers() {
    let options = page_options_from_metadata(&serde_json::json!({
        "showHeadingNumbers": false
    }));
    assert!(!options.show_heading_numbers);
}
```

- [ ] **Step 2: 运行测试确认失败**

Run: `cargo test -p core-protocol page_options_default_disables_heading_numbers -- --nocapture && cargo test -p mnote-web local_page_options_metadata_can_toggle_heading_numbers -- --nocapture`

Expected: 失败，原因是默认值和 metadata 读取还没对齐。

### Task 2: 最小实现 Rust 默认值与 metadata 读取

**Files:**
- Modify: `rust/crates/core-protocol/src/page_aggregate.rs`
- Modify: `rust/crates/mnote-web/src/routes/local_folder_source.rs`
- Modify: `rust/crates/mnote-web/src/ssr/pages/document.rs`
- Modify: `rust/crates/mnote-web/src/ssr/pages/layout.rs`
- Modify: `rust/crates/mnote-web/src/page_aggregate/builder.rs`
- Modify: `wolai-frontend/src/lib/documents/page-aggregate-builder.ts`

- [ ] **Step 1: 写最小实现**

```rust
// PageOptions::default() 里把 show_heading_numbers 改成 false。
// page_options_from_metadata() 读取 showHeadingNumbers / show_heading_numbers。
```

```ts
// 前端 page aggregate fallback 的 showHeadingNumbers 默认值改成 false。
```

- [ ] **Step 2: 运行测试确认通过**

Run: `cargo test -p core-protocol page_options_default_disables_heading_numbers -- --nocapture && cargo test -p mnote-web local_page_options_metadata_can_toggle_heading_numbers -- --nocapture`

Expected: PASS。

### Task 3: 补浏览器回归，防止文档页再次默认冒出数字标题

**Files:**
- Modify: `scripts/task163-local-folder-unified-tree-browser-smoke.js`

- [ ] **Step 1: 写一个断言**

```js
await page.goto(documentUrl(root, "local-md:README.md"), { waitUntil: "domcontentloaded", timeout: UI_TIMEOUT_MS });
const headingBefore = await page.locator("#mnote-leptos-tiptap-island-editor-root .ProseMirror h1").evaluate((node) =>
  getComputedStyle(node, "::before").content
);
assert(headingBefore === "none", "默认不应显示标题自动编号");
```

- [ ] **Step 2: 跑 smoke 验证**

Run: `MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3000 node scripts/task163-local-folder-unified-tree-browser-smoke.js`

Expected: PASS。

### Task 4: 复核与收尾

**Files:**
- Modify: `design/03-rust-web/done/3-11-rust-web-3000-existing-tree-editor-runtime-relink-checklist-v1.md` (only if需要记录新的默认值口径)

- [ ] **Step 1: 跑格式与 diff 检查**

Run: `cargo fmt --all --check && git diff --check`

- [ ] **Step 2: 确认没有回归**

Run: `cargo test -p mnote-web local_folder -- --nocapture && cargo test -p mnote-web filetree -- --nocapture`

