Skip to content

Commit 183d738

Browse files
committed
Add session handoff document for Phase 5 + Phase 6
Detailed handoff covering: current codebase state, Phase 5 (fitness-check, symbol_metrics_history, telemetry), Phase 6 (cross-compile, Containerfile, release workflow, ci init), gotchas, and execution order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMKqeuxQB5XbjKKxasQYQJ
1 parent f7b79a4 commit 183d738

1 file changed

Lines changed: 376 additions & 0 deletions

File tree

docs/session-handoff-phase-5-6.md

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
# Session Handoff — Phase 5 + Phase 6
2+
3+
> Tài liệu bàn giao cho session tiếp theo. Đọc trước khi bắt đầu code.
4+
5+
---
6+
7+
## Trạng thái hiện tại
8+
9+
**Branch**: `claude/code-intelligence-setup-6q6zn7`
10+
**PR**: #2 (draft) — đã bao gồm Phase 0.5 → Phase 4
11+
**CI**: Green (clippy, fmt, test — 94 tests pass)
12+
**Repo chỉ được sửa**: `Code-Intelligence`. **TUYỆT ĐỐI KHÔNG** thay đổi `SUPER-MCP` (chỉ dùng tham chiếu).
13+
14+
### Đã hoàn thành
15+
16+
| Phase | Nội dung | Commit |
17+
|-------|----------|--------|
18+
| 0.5 | CI pipeline, debt registry, ADR-0001 | `96c0b19` |
19+
| 1B | Analysis module ports (coverage, dead_code, codeowners, hotspot, diff_impact), C-1 regression test | `96c0b19` |
20+
| 2 | FormalResolver (stack-graphs), ConservativeResolver, EdgeConfidence, ADR-0002 | `0417e15` |
21+
| 3 | FTS5 dual-column BM25, output sanitizer (10 patterns), search module (5 SearchKind) | `a2c3969` |
22+
| 4 | 16 MCP tool handlers via rmcp `#[tool]`, clap CLI, ServerHandler, Mutex\<Connection\> | `f7b79a4` |
23+
24+
### Codebase structure
25+
26+
```
27+
crates/
28+
├── ci-core/src/
29+
│ ├── lib.rs # pub mod: db, graph, config, types, analysis, resolver, search, sanitize
30+
│ ├── db/schema.rs # SQLite schema: symbols, file_index, call_edges, import_edges, fts_exact, fts_tokens
31+
│ ├── db/queries.rs # batch_callees, batch_callers
32+
│ ├── graph/coreness.rs # K-core O(V+E)
33+
│ ├── graph/hub.rs # Hub detection (C-2 fix)
34+
│ ├── graph/path.rs # Bidirectional BFS (F1,F2,F3,F10)
35+
│ ├── graph/tokenize.rs # Identifier tokenization
36+
│ ├── resolver/formal.rs # Stack Graphs Python resolver
37+
│ ├── resolver/conservative.rs # Alias-tracking 6 languages
38+
│ ├── search.rs # FTS5 search: symbol, text, file, semantic(stub), hybrid(RRF k=20)
39+
│ ├── sanitize.rs # Credential patterns → [REDACTED:label]
40+
│ ├── config.rs # Config loading + defaults
41+
│ ├── types.rs # 11 enums (SearchKind, EdgeConfidence, TerminatedBy, etc.)
42+
│ └── analysis/ # coverage, dead_code, codeowners, hotspot, diff_impact (stubs with types)
43+
├── ci-server/src/
44+
│ ├── lib.rs # serve_stdio(), doctor(), default_db_path()
45+
│ └── tools.rs # 16 MCP tools, CodeIntelligenceServer, ServerHandler impl
46+
└── ci-cli/src/
47+
└── main.rs # clap CLI: ci serve, ci index(stub), ci doctor
48+
```
49+
50+
### Key technical details
51+
52+
- **rmcp 0.1.5**`#[tool(tool_box)]` on impl block generates tool_box + ServerHandler methods. `#[tool]` macro only supports `name`, `description`, `vis` attributes. **KHÔNG có `annotations()`** — rmcp 0.1.5 doesn't support tool annotations in macro.
53+
- **Mutex\<Connection\>** — rusqlite::Connection is NOT Sync. Server uses `Arc<Mutex<Connection>>` with `db()` helper. For `prepare()` calls, must bind guard to local variable (`let conn = self.db(); let stmt = conn.prepare(...)`) to avoid temporary dropped while borrowed.
54+
- **Tool return type** — rmcp tools return `String` (implements `IntoContents`). No `Json<T>` wrapper. Serialize via `serde_json::to_string_pretty(&output).unwrap_or_default()`.
55+
- **Parameters**`rmcp::handler::server::tool::Parameters<T>` for tool input deserialization.
56+
- **Tests** — 94 tests across ci-core (search: 11, sanitize: 11, graph: 12, db: 2, resolver: various). ci-server has 0 unit tests currently.
57+
58+
---
59+
60+
## Phase 5 — Capability Mới
61+
62+
**Ref**: `docs/migration-plan-v2.md` → "Phase 5 — Capability Mới"
63+
64+
### 5.1 — `symbol_metrics_history` table
65+
66+
Thêm bảng mới vào `ci-core/src/db/schema.rs`:
67+
68+
```sql
69+
CREATE TABLE IF NOT EXISTS symbol_metrics_history (
70+
id INTEGER PRIMARY KEY AUTOINCREMENT,
71+
qualified_name TEXT NOT NULL,
72+
snapshot_at TEXT NOT NULL, -- ISO8601 timestamp
73+
caller_count INTEGER NOT NULL DEFAULT 0,
74+
callee_count INTEGER NOT NULL DEFAULT 0,
75+
coreness INTEGER NOT NULL DEFAULT 0,
76+
is_hub INTEGER NOT NULL DEFAULT 0,
77+
churn_count INTEGER NOT NULL DEFAULT 0,
78+
complexity REAL,
79+
UNIQUE(qualified_name, snapshot_at)
80+
);
81+
CREATE INDEX IF NOT EXISTS idx_smh_symbol ON symbol_metrics_history(qualified_name);
82+
CREATE INDEX IF NOT EXISTS idx_smh_time ON symbol_metrics_history(snapshot_at);
83+
```
84+
85+
Cập nhật `init_db()` để include migration. Tham khảo pattern migration idempotent đã có (CREATE TABLE IF NOT EXISTS).
86+
87+
### 5.2 — `ci fitness-check` CLI command
88+
89+
**File**: `crates/ci-cli/src/main.rs` — thêm subcommand `FitnessCheck`
90+
91+
```rust
92+
FitnessCheck {
93+
#[arg(long, default_value = ".")]
94+
project_root: PathBuf,
95+
#[arg(long)]
96+
config: Option<PathBuf>, // thresholds.toml
97+
#[arg(long, default_value = "false")]
98+
json: bool, // JSON output for CI parsing
99+
}
100+
```
101+
102+
**Logic** (`crates/ci-core/src/fitness.rs` — file mới):
103+
1. Load thresholds từ TOML (hoặc defaults):
104+
```toml
105+
[thresholds]
106+
max_hub_count = 50
107+
max_avg_coreness = 15.0
108+
max_dead_code_pct = 10.0
109+
max_hotspot_risk = 0.75
110+
min_edge_coverage_pct = 60.0
111+
```
112+
2. Query DB cho current metrics:
113+
- Hub count: `SELECT COUNT(*) FROM symbols WHERE is_hub = 1`
114+
- Avg coreness: `SELECT AVG(coreness) FROM symbols WHERE coreness > 0`
115+
(Lưu ý: `symbols` table chưa có column `coreness` — cần thêm hoặc compute on-the-fly từ graph)
116+
- Dead code %: delegate tới `analysis::dead_code` (nếu đã port đầy đủ, hoặc stub)
117+
- Hotspot risk: max risk từ `analysis::hotspot`
118+
- Edge coverage: `SELECT COUNT(DISTINCT from_symbol) FROM call_edges` / total symbols
119+
3. Compare với thresholds
120+
4. Exit code: 0 nếu pass, 1 nếu fail
121+
5. Output: human-readable default, JSON nếu `--json`
122+
123+
**Tham khảo**: SUPER-MCP `npm run ci` pattern — fitness check chạy như CI gate trong target project.
124+
125+
### 5.3 — Structured telemetry
126+
127+
**File**: `crates/ci-server/src/telemetry.rs` (file mới)
128+
129+
Telemetry events qua `tracing`:
130+
```rust
131+
tracing::info!(
132+
tool = tool_name,
133+
duration_ms = elapsed.as_millis(),
134+
result_size = result.len(),
135+
"tool_execution_completed"
136+
);
137+
```
138+
139+
Cần wrap tool execution trong timing logic. Có 2 cách:
140+
1. **Middleware approach**: Wrap `call_tool` trong ServerHandler impl để tự động time mọi tool call.
141+
2. **Per-tool approach**: Thêm timing vào mỗi tool function.
142+
143+
Recommend option 1 — override `call_tool` trong `impl ServerHandler`:
144+
```rust
145+
async fn call_tool(&self, req: CallToolRequestParam, ctx: RequestContext<RoleServer>) -> Result<CallToolResult, McpError> {
146+
let start = std::time::Instant::now();
147+
let tool_name = req.name.clone();
148+
let result = Self::tool_box().call(ToolCallContext::new(self, req, ctx)).await;
149+
tracing::info!(tool = %tool_name, duration_ms = start.elapsed().as_millis(), "tool_call");
150+
result
151+
}
152+
```
153+
154+
**Lưu ý**: `#[tool(tool_box)]` trên `impl ServerHandler` đã generate `call_tool`. Nếu muốn override, cần KHÔNG dùng `@derive` cho `call_tool` mà viết tay. Có thể cần restructure: dùng `#[tool(tool_box)]` chỉ trên plain impl block (generates `fn tool_box()`), rồi viết `impl ServerHandler` manually với custom `call_tool` + `list_tools` delegation.
155+
156+
### 5.4 — Snapshot writer
157+
158+
**File**: `crates/ci-core/src/fitness.rs` hoặc `crates/ci-core/src/db/metrics.rs`
159+
160+
Function `snapshot_metrics(conn, timestamp)`:
161+
1. Query current symbols + coreness + caller_count
162+
2. INSERT INTO symbol_metrics_history
163+
3. Gọi từ `ci index` sau khi index xong, hoặc từ `ci fitness-check`
164+
165+
### 5.5 — Tests cần viết
166+
167+
- `fitness.rs`: threshold pass/fail logic, default thresholds, TOML parsing
168+
- `telemetry.rs`: verify tracing events emitted (dùng `tracing_test` crate hoặc custom subscriber)
169+
- `db/schema.rs`: verify `symbol_metrics_history` table created, insert/query works
170+
- Integration: `ci fitness-check` exit code 0/1
171+
172+
### 5.6 — Exit criteria
173+
174+
- [ ] `symbol_metrics_history` table exists, migration idempotent
175+
- [ ] `ci fitness-check` exit 0 khi metrics within thresholds
176+
- [ ] `ci fitness-check` exit 1 khi vượt threshold, message rõ ràng
177+
- [ ] `ci fitness-check --json` output parseable JSON
178+
- [ ] Telemetry events in stderr khi tool called
179+
- [ ] CI green (clippy, fmt, tests)
180+
181+
---
182+
183+
## Phase 6 — Distribution
184+
185+
**Ref**: `docs/migration-plan-v2.md` → "Phase 6 — Distribution"
186+
187+
### 6.1 — Cross-compile static binary
188+
189+
**File**: `.github/workflows/release.yml` (file mới)
190+
191+
```yaml
192+
name: Release
193+
on:
194+
push:
195+
tags: ['v*']
196+
197+
jobs:
198+
build:
199+
strategy:
200+
matrix:
201+
include:
202+
- target: x86_64-unknown-linux-musl
203+
os: ubuntu-latest
204+
- target: aarch64-unknown-linux-musl
205+
os: ubuntu-latest
206+
- target: aarch64-apple-darwin
207+
os: macos-latest
208+
runs-on: ${{ matrix.os }}
209+
steps:
210+
- uses: actions/checkout@v4
211+
- uses: dtolnay/rust-toolchain@stable
212+
with:
213+
targets: ${{ matrix.target }}
214+
- name: Install musl tools (Linux)
215+
if: contains(matrix.target, 'musl')
216+
run: sudo apt-get install -y musl-tools
217+
- name: Install cross (aarch64-linux)
218+
if: matrix.target == 'aarch64-unknown-linux-musl'
219+
run: cargo install cross
220+
- name: Build
221+
run: |
222+
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then
223+
cross build --release --target ${{ matrix.target }}
224+
else
225+
cargo build --release --target ${{ matrix.target }}
226+
fi
227+
- name: Upload artifact
228+
uses: actions/upload-artifact@v4
229+
with:
230+
name: ci-${{ matrix.target }}
231+
path: target/${{ matrix.target }}/release/ci
232+
233+
release:
234+
needs: build
235+
runs-on: ubuntu-latest
236+
permissions:
237+
contents: write
238+
steps:
239+
- uses: actions/download-artifact@v4
240+
- name: Create release
241+
uses: softprops/action-gh-release@v2
242+
with:
243+
files: ci-*/ci
244+
```
245+
246+
**Lưu ý quan trọng**: tree-sitter grammars cần compile native. Khi cross-compile cho musl, cần verify tree-sitter-python/etc build thành công. Nếu fail → fallback: build trên CI native runner cho mỗi platform.
247+
248+
### 6.2 — Containerfile
249+
250+
**File**: `Containerfile` (root)
251+
252+
```dockerfile
253+
FROM rust:1.85-alpine AS builder
254+
RUN apk add --no-cache musl-dev
255+
WORKDIR /build
256+
COPY Cargo.toml Cargo.lock ./
257+
COPY crates/ crates/
258+
RUN cargo build --release --target x86_64-unknown-linux-musl
259+
260+
FROM scratch
261+
COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/ci /ci
262+
ENTRYPOINT ["/ci"]
263+
CMD ["serve", "--project-root", "/project", "--db-path", "/data/index.db"]
264+
```
265+
266+
### 6.3 — compose.yaml example
267+
268+
**File**: `compose.yaml` (root)
269+
270+
```yaml
271+
services:
272+
code-intelligence:
273+
build: .
274+
read_only: true
275+
cap_drop: [ALL]
276+
security_opt: [no-new-privileges:true]
277+
pids_limit: 64
278+
mem_limit: 256m
279+
volumes:
280+
- ./:/project:ro
281+
- ci-data:/data
282+
command: ["serve", "--project-root", "/project", "--db-path", "/data/index.db"]
283+
284+
volumes:
285+
ci-data:
286+
```
287+
288+
### 6.4 — `ci init` command
289+
290+
**File**: `crates/ci-cli/src/main.rs` — thêm subcommand
291+
292+
```rust
293+
Init {
294+
#[arg(long, default_value = ".")]
295+
project_root: PathBuf,
296+
}
297+
```
298+
299+
Logic:
300+
1. Detect project root (tìm `.git/`, `Cargo.toml`, `package.json`, `pyproject.toml`)
301+
2. Tạo `.codeindex/` directory
302+
3. Tạo `.codeindex/config.json` với defaults từ `config.rs`
303+
4. Print hướng dẫn: "Run `ci index` to build the index, then `ci serve` to start MCP server"
304+
305+
### 6.5 — Tests cần viết
306+
307+
- Release workflow: test manually bằng `act` (GitHub Actions local runner) hoặc push test tag
308+
- Containerfile: `docker build .` + `docker run --rm ci doctor`
309+
- `ci init`: verify config file created, idempotent (không overwrite existing)
310+
311+
### 6.6 — Exit criteria
312+
313+
- [ ] Binary downloadable cho 3 platform (x86_64-linux-musl, aarch64-linux-musl, aarch64-apple-darwin)
314+
- [ ] `ci init` tạo config file đúng
315+
- [ ] Container image build thành công
316+
- [ ] `docker run code-intelligence doctor` pass
317+
- [ ] Release workflow green on tag push
318+
- [ ] CI green (clippy, fmt, tests)
319+
320+
---
321+
322+
## Gotchas & Lessons learned
323+
324+
1. **rmcp 0.1.5 API quirks**:
325+
- `#[tool]` macro chỉ support `name`, `description`, `vis`. KHÔNG có `annotations()`.
326+
- `#[tool(tool_box)]` trên plain impl → generates `fn tool_box()`. Trên `impl ServerHandler` → generates `list_tools()` + `call_tool()`.
327+
- Tool functions return `String` (not `Json<T>`). Serialize output manually.
328+
- `Parameters<T>` is at `rmcp::handler::server::tool::Parameters`.
329+
330+
2. **rusqlite::Connection is NOT Sync** → phải wrap trong `Mutex`. Khi dùng `prepare()`, PHẢI bind guard vào local variable:
331+
```rust
332+
let conn = self.db(); // MutexGuard lives here
333+
let mut stmt = conn.prepare(...) // borrows conn
334+
```
335+
KHÔNG ĐƯỢC: `self.db().prepare(...)` — temporary guard dropped.
336+
337+
3. **CI on this repo** uses Rust 1.96.0+ which has newer clippy lints (e.g., `useless_conversion`). Always test clippy with `-- -D warnings` locally trước khi push.
338+
339+
4. **`cargo fmt --all` và `cargo clippy --workspace`** — luôn chạy CẢ HAI và verify TỪNG CÁI riêng biệt. Đừng chain `&&` rồi chỉ check exit code cuối.
340+
341+
5. **SUPER-MCP repo** (`/home/user/SUPER-MCP`) — CHỈ ĐỌC, KHÔNG SỬA. Dùng để tham khảo patterns.
342+
343+
---
344+
345+
## Thứ tự thực hiện đề xuất
346+
347+
### Phase 5 (ước lượng ~5-7 ngày)
348+
1. `symbol_metrics_history` table + migration
349+
2. `ci-core/src/fitness.rs` — threshold logic + TOML parsing
350+
3. `ci fitness-check` CLI subcommand
351+
4. Telemetry middleware trong `ci-server`
352+
5. Tests + clippy + fmt
353+
6. Commit + push + update PR
354+
355+
### Phase 6 (ước lượng ~3-5 ngày)
356+
1. `ci init` CLI subcommand
357+
2. `.github/workflows/release.yml`
358+
3. `Containerfile` + `compose.yaml`
359+
4. Test cross-compile (ít nhất x86_64-musl)
360+
5. Tests + clippy + fmt
361+
6. Commit + push + update PR
362+
363+
---
364+
365+
## Files quan trọng cần đọc trước khi bắt đầu
366+
367+
| File | Tại sao |
368+
|------|---------|
369+
| `docs/migration-plan-v2.md` | Chi tiết Phase 5, 6 requirements |
370+
| `crates/ci-core/src/db/schema.rs` | Hiểu DB schema hiện tại, pattern migration |
371+
| `crates/ci-server/src/tools.rs` | Hiểu rmcp integration pattern, ServerHandler |
372+
| `crates/ci-server/src/lib.rs` | serve_stdio(), doctor() |
373+
| `crates/ci-cli/src/main.rs` | CLI structure, thêm subcommands ở đây |
374+
| `crates/ci-core/src/config.rs` | Config defaults |
375+
| `crates/ci-core/src/types.rs` | All type enums |
376+
| `/home/user/SUPER-MCP/` | Reference ONLY — telemetry patterns, container patterns |

0 commit comments

Comments
 (0)