docs: update CODE-HEALTH-REPORT.md after vault.rs + frontmatter.rs refactoring

vault.rs: 6.22 -> 8.81 (zero code smells remaining)
frontmatter.rs: 6.89 -> 9.68 (Yellow -> Green)
Overall project: 9.14 -> 9.33

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
lucaronin
2026-02-20 20:37:38 +01:00
parent d7821d40ce
commit f01a65538e

View File

@@ -1,224 +1,278 @@
# Code Health Report — Laputa App
**Date:** 2026-02-17
**Branch:** `experiment/shadcn-migration`
**Overall Project Score:** 8.34 / 10.0 (Yellow — approaching Green)
**Date:** 2026-02-20
**Branch:** `main`
**Overall Project Score:** 9.33 / 10.0 (Green — up from 9.14)
**Tool:** CodeScene Code Health Analysis (project ID: 76865)
**Previous Report:** 2026-02-20 on `main` — 9.14 / 10.0
---
## Summary
The Laputa App codebase scores **8.34** overall — solid but with four files in the "Yellow" zone (< 8.0) that are dragging down maintainability. One file (`vault.rs`) is in the **Red zone** at 4.8, representing the most critical technical debt.
The Laputa App codebase scores **9.33** overall — a further improvement of **+0.19** from the previous report (9.14). The codebase remains solidly in **Green**, driven by the `vault.rs` refactoring (+2.59 to 8.81) and the `frontmatter.rs` refactoring (+2.79 to 9.68, now Green). Five files remain in the Yellow zone, down from six — `frontmatter.rs` has exited Yellow into Green.
| Zone | Score Range | File Count | Description |
|------|------------|------------|-------------|
| Optimal | 10.0 | 4 | Perfect — optimized for human and AI comprehension |
| Green | 9.0 9.9 | 2 | High quality, minor issues only |
| Yellow | 4.0 8.9 | 4 | Problematic technical debt |
| Optimal | 10.0 | 8 | Perfect — optimized for human and AI comprehension |
| Green | 9.0 9.9 | 15 | High quality, minor issues only |
| Yellow | 4.0 8.9 | 5 | Problematic technical debt |
| Red | 1.0 3.9 | 0 | — |
| N/A | — | 2 | CSS files (unsupported by CodeScene) |
| N/A | — | 6 | CSS files (4) and tiny utility files (2) — unsupported by CodeScene |
---
## File-by-File Scores
## Refactoring Completed (vault.rs + frontmatter.rs)
The following refactorings were executed on vault.rs and frontmatter.rs, raising both files significantly:
### vault.rs: 6.22 → 8.81 (+2.59)
Refactored in 5 commits across multiple phases:
1. **Extracted `run_git` helper** — Consolidated duplicated git command execution into a single helper function, flattening git functions (`git_changed_files`, `git_uncommitted_new_files`).
2. **Decomposed `parse_md_file`** — Extracted `parse_frontmatter_fields`, `extract_title`, `extract_snippet`, and `extract_relationships` into focused sub-functions. Flattened deep nesting with early returns.
3. **Decomposed `scan_vault_cached`** — Extracted `process_vault_entry`, `collect_vault_entries`, `apply_git_status`, and `build_vault_response` as focused functions.
4. **Split large test assertion blocks** — Broke monolithic assertion blocks into per-field assertions for readability and maintainability.
5. **Converted internal functions to use `&Path`** instead of `&str` for vault/file paths, reducing string-heavy arguments.
All 8 original code smells (3 Bumpy Roads, 4 Deep Nestings, 2 Complex Methods, 2 Large Methods, String-Heavy Args, Large Assertion Blocks) have been resolved. The CodeScene review now reports **zero code smells**.
### frontmatter.rs: 6.89 → 9.68 (+2.79) — Yellow → Green
Refactored in 4 commits:
1. **Flattened `update_frontmatter_content`** — Used early returns and extracted `find_key_line_range` and `build_updated_content` helpers. Eliminated bumpy road (4 bumps) and deep nesting (4 levels).
2. **Simplified `FrontmatterValue::to_yaml_value`** — Extracted `needs_yaml_quoting` predicate, simplified match arms. Reduced cc from 17.
3. **Simplified `format_yaml_key`** — Extracted key-quoting rules into `key_needs_quoting` predicate. Reduced complex conditionals from 5.
4. **Extracted line-parsing helpers**`line_is_key` and related helpers for clean YAML line detection.
All original code smells (1 Bumpy Road, 1 Deep Nesting, 2 Complex Methods, 4 Complex Conditionals) have been resolved. Only one minor issue remains: **String Heavy Function Arguments** (73% of args are string types).
---
## Change Summary vs Previous Report (Feb 17)
| File | Previous | Current | Delta | Notes |
|------|----------|---------|-------|-------|
| `src/App.tsx` | 7.13 | **9.28** | **+2.15** | Yellow -> Green. Brain Method eliminated via hook extraction |
| `src/components/Inspector.tsx` | 7.49 | **9.02** | **+1.53** | Yellow -> Green. Decomposed into sub-components |
| `src-tauri/src/vault.rs` | 4.80 | **8.81** | **+4.01** | Still Yellow but near-Green. All code smells resolved |
| `src-tauri/src/frontmatter.rs` | 6.89* | **9.68** | **+2.79** | Yellow -> Green. All major smells resolved |
| `src/components/Editor.tsx` | 6.94 | **7.68** | **+0.74** | Still Yellow. DiffView/wikilinks extracted but Editor still too large |
| `src/components/Sidebar.tsx` | 9.02 | **9.14** | +0.12 | Green (stable) |
| `src/components/NoteList.tsx` | 8.11 | **8.05** | -0.06 | Yellow (stable, slight regression) |
| `src/components/QuickOpenPalette.tsx` | 9.55 | **9.55** | = | Green (unchanged) |
| `src-tauri/src/lib.rs` | 9.68 | **9.68** | = | Green (unchanged) |
| `src-tauri/src/main.rs` | 10.0 | **10.0** | = | Optimal (unchanged) |
| `src-tauri/src/git.rs` | 10.0 | **10.0** | = | Optimal (unchanged) |
| `src/components/StatusBar.tsx` | 10.0 | **9.23** | -0.77 | Regression: Optimal -> Green (new features added) |
| `src/mock-tauri.ts` | 10.0 | **9.37** | -0.63 | Regression: Optimal -> Green (new mock data added) |
*frontmatter.rs was extracted from vault.rs; "previous" is its initial score after extraction.
### New Files (not in previous report)
| File | Score | Zone | Notes |
|------|-------|------|-------|
| `src/hooks/useNoteActions.ts` | **7.81** | Yellow | Extracted from App.tsx — still needs decomposition |
| `src/components/AIChatPanel.tsx` | **8.51** | Yellow | New feature — large component |
| `src/components/DynamicPropertiesPanel.tsx` | **9.06** | Green | Extracted from Inspector.tsx |
| `src/components/DiffView.tsx` | **9.09** | Green | Extracted from Editor.tsx |
| `src/utils/frontmatter.ts` | **9.24** | Green | Extracted from Inspector.tsx |
| `src/components/CommitDialog.tsx` | **9.38** | Green | New component |
| `src/hooks/useVaultLoader.ts` | **9.41** | Green | Extracted from App.tsx |
| `src/utils/wikilinks.ts` | **9.53** | Green | Extracted from Editor.tsx |
| `src/hooks/useTheme.ts` | **9.68** | Green | New hook |
| `src/components/EditableValue.tsx` | **10.0** | Optimal | Extracted from Inspector.tsx |
| `src/components/ResizeHandle.tsx` | **10.0** | Optimal | New component |
| `src/components/CreateNoteDialog.tsx` | **10.0** | Optimal | New component |
| `src/components/Toast.tsx` | **10.0** | Optimal | New component |
| `src/utils/typeColors.ts` | **10.0** | Optimal | New utility |
| `src/main.tsx` | **10.0** | Optimal | Entry point |
---
## File-by-File Scores (All 34 Files)
| File | LoC | Score | Zone | Key Issues |
|------|-----|-------|------|------------|
| `src-tauri/src/main.rs` | 6 | **10.0** | Optimal | None |
| `src-tauri/src/git.rs` | 423 | **10.0** | Optimal | None |
| `src/mock-tauri.ts` | 707 | **10.0** | Optimal | None |
| `src/components/StatusBar.tsx` | 62 | **10.0** | Optimal | None |
| `src-tauri/src/lib.rs` | 78 | **9.68** | Green | String-heavy function arguments (93%) |
| `src/components/EditableValue.tsx` | 167 | **10.0** | Optimal | None |
| `src/components/ResizeHandle.tsx` | 74 | **10.0** | Optimal | None |
| `src/components/CreateNoteDialog.tsx` | 99 | **10.0** | Optimal | None |
| `src/components/Toast.tsx` | 28 | **10.0** | Optimal | None |
| `src/utils/typeColors.ts` | 37 | **10.0** | Optimal | None |
| `src/main.tsx` | 16 | **10.0** | Optimal | None |
| `src-tauri/src/frontmatter.rs` | 279 | **9.68** | Green | String-heavy function arguments (73%) |
| `src-tauri/src/lib.rs` | 80 | **9.68** | Green | String-heavy function arguments |
| `src/hooks/useTheme.ts` | 51 | **9.68** | Green | None significant |
| `src/components/QuickOpenPalette.tsx` | 145 | **9.55** | Green | Complex Method (cc=16) |
| `src/components/Sidebar.tsx` | 233 | **9.02** | Green | Complex Method (cc=25), Large Method (181 LoC) |
| `src/components/NoteList.tsx` | 339 | **8.11** | Yellow | Bumpy Road, Complex Method (cc=30), Large Method (166 LoC) |
| `src/components/Inspector.tsx` | 912 | **7.49** | Yellow | Bumpy Road (x2), Complex Methods (x4), Complex Conditionals |
| `src/App.tsx` | 593 | **7.13** | Yellow | Brain Method: App() at cc=56 / 381 LoC, Bumpy Road, Deep Nesting |
| `src/components/Editor.tsx` | 540 | **6.94** | Yellow | Deep Nesting, Complex Methods (cc=29), Large Method (265 LoC) |
| `src-tauri/src/vault.rs` | 815 | **4.80** | Yellow (near Red) | Bumpy Road (x2), Deep Nesting, Complex Methods (x3), Code Duplication, Large Method, String-heavy args |
| `src/App.css` | 48 | N/A | — | CSS not supported |
| `src/components/Editor.css` | 106 | N/A | — | CSS not supported |
| `src/utils/wikilinks.ts` | 68 | **9.53** | Green | None significant |
| `src/hooks/useVaultLoader.ts` | 123 | **9.41** | Green | None significant |
| `src/components/CommitDialog.tsx` | 73 | **9.38** | Green | None significant |
| `src/mock-tauri.ts` | 894 | **9.37** | Green | None significant |
| `src/App.tsx` | 176 | **9.28** | Green | Complex Method: App() cc=16 / 130 LoC |
| `src/utils/frontmatter.ts` | 72 | **9.24** | Green | None significant |
| `src/components/StatusBar.tsx` | 159 | **9.23** | Green | None significant |
| `src/components/Sidebar.tsx` | 208 | **9.14** | Green | None significant |
| `src/components/DiffView.tsx` | 45 | **9.09** | Green | None significant |
| `src/components/DynamicPropertiesPanel.tsx` | 265 | **9.06** | Green | None significant |
| `src/components/Inspector.tsx` | 312 | **9.02** | Green | None significant |
| `src-tauri/src/vault.rs` | 1111 | **8.81** | Yellow | No code smells reported — near Green threshold |
| `src/components/AIChatPanel.tsx` | 364 | **8.51** | Yellow | Complex Method: AIChatPanel() cc=15 / 285 LoC |
| `src/components/NoteList.tsx` | 434 | **8.05** | Yellow | Complex Method: NoteListInner() cc=28 / 208 LoC |
| `src/hooks/useNoteActions.ts` | 280 | **7.81** | Yellow | Bumpy Road, Deep Nesting, Complex Method: useNoteActions() cc=30 / 169 LoC |
| `src/components/Editor.tsx` | 575 | **7.68** | Yellow | **Brain Method**: Editor() cc=61 / 385 LoC, Bumpy Road |
| `src/types.ts` | 38 | N/A | — | Type definitions only |
| `src/lib/utils.ts` | 6 | N/A | — | Utility (too small) |
| `src/App.css` | — | N/A | — | CSS not supported |
| `src/index.css` | — | N/A | — | CSS not supported |
| `src/components/Editor.css` | — | N/A | — | CSS not supported |
| `src/components/EditorTheme.css` | — | N/A | — | CSS not supported |
---
## Technical Debt Hotspots
CodeScene reports **0 hotspots** from the project-level analysis (the project may need more commit history to identify change-frequency hotspots). However, based on the code health scores and file sizes, the **de facto hotspots** are:
Based on code health scores, file sizes, and change frequency:
| Priority | File | Score | LoC | Risk Factor |
|----------|------|-------|-----|-------------|
| 1 | `src-tauri/src/vault.rs` | 4.80 | 815 | Largest Rust file, near-Red health, 8 distinct code smells |
| 2 | `src/components/Editor.tsx` | 6.94 | 540 | Core editor component, deep nesting, high complexity |
| 3 | `src/App.tsx` | 7.13 | 593 | Root component, Brain Method (cc=56, 381 LoC) |
| 4 | `src/components/Inspector.tsx` | 7.49 | 912 | Largest file in codebase, 4 complex methods |
| 1 | `src/components/Editor.tsx` | 7.68 | 575 | **Brain Method** (cc=61, 385 LoC) — worst single function in codebase |
| 2 | `src/hooks/useNoteActions.ts` | 7.81 | 280 | Brain Method (cc=30, 169 LoC), deep nesting in updateMockFrontmatter |
| 3 | `src/components/NoteList.tsx` | 8.05 | 434 | Complex Method (cc=28, 208 LoC) |
| 4 | `src/components/AIChatPanel.tsx` | 8.51 | 364 | Large component (cc=15, 285 LoC) — new, address before it grows |
| 5 | `src-tauri/src/vault.rs` | 8.81 | 1111 | Near-Green, no code smells — minor improvement needed to cross 9.0 |
---
## Detailed Analysis — Files Scoring Below 8.0
## Detailed Analysis — Files Scoring Below 9.0
### 1. `src-tauri/src/vault.rs` — Score: 4.80 (CRITICAL)
### 1. `src/components/Editor.tsx` — Score: 7.68 (Now #1 Priority)
This is the **worst-scoring file** in the codebase and the highest priority for refactoring.
The core `Editor` component function remains a **Brain Method** — the single worst function in the codebase at cc=61 and 385 LoC (3.2x the 120 LoC limit).
**Code Smells Found:**
| Smell | Location | Details | Severity |
|-------|----------|---------|----------|
| Bumpy Road | `update_frontmatter_content` (L452536) | 4 bumps of nested logic | High |
| Bumpy Road | `days_from_epoch` (L253285) | 3 bumps | High |
| Deep Nesting | `update_frontmatter_content` (L452536) | 4 levels of conditionals | High |
| Complex Method | `FrontmatterValue::to_yaml_value` (L371412) | cc = 17 | Medium |
| Complex Method | `update_frontmatter_content` (L452536) | cc = 16 | Medium |
| Complex Method | `days_from_epoch` (L253285) | cc = 14 | Medium |
| Complex Conditional | `to_yaml_value` (L375377) | 8 complex expressions | Medium |
| Complex Conditional | `format_yaml_key` (L565566) | 5 complex expressions | Medium |
| Complex Conditional | `days_from_epoch` (L255) | 3 complex expressions | Medium |
| Code Duplication | `update_frontmatter` / `delete_frontmatter_property` (L416449) | Near-identical functions | Medium |
| Large Method | `parse_md_file` (L101190) | 78 LoC (limit: 70) | Medium |
| String-Heavy Args | Module-wide | 63% of args are strings | Medium |
**Business Case:** Improving to industry average (5.15) yields 27% defect reduction and 13% speed improvement.
| Bumpy Road | `Editor` (L154575) | 2 bumps | High |
| Complex Method | `Editor` (L154575) | cc = 61 (**Brain Method**) | High |
| Complex Conditional | `Editor:196` | 2 complex expressions | Medium |
| Large Method | `Editor` (L154575) | 385 LoC (limit: 120) | Medium |
---
### 2. `src/components/Editor.tsx` — Score: 6.94
### 2. `src/hooks/useNoteActions.ts` — Score: 7.81
Extracted from App.tsx. Contains the `updateMockFrontmatter` function which has deep nesting, plus the `useNoteActions` hook itself is still too large.
**Code Smells Found:**
| Smell | Location | Details | Severity |
|-------|----------|---------|----------|
| Deep Nesting | `expandWikilinksInContent` (L119146) | 4 levels of conditionals | High |
| Complex Method | `Editor` (L263540) | cc = 29 | Medium |
| Complex Method | `DiffView` (L148186) | cc = 13 | Medium |
| Complex Conditional | `DiffView:169` | 4 complex expressions | Medium |
| Complex Conditional | `expandWikilinksInContent:122` | 2 complex expressions | Medium |
| Large Method | `Editor` (L263540) | 265 LoC (limit: 120) | Medium |
| Bumpy Road | `updateMockFrontmatter` (L1466) | 2 bumps | High |
| Deep Nesting | `updateMockFrontmatter` (L1466) | 4 levels deep | High |
| Complex Method | `useNoteActions` (L93280) | cc = 30 | Medium |
| Complex Method | `updateMockFrontmatter` (L1466) | cc = 17 | Medium |
| Complex Method | `deleteMockFrontmatterProperty` (L6891) | cc = 9 | Medium |
| Large Method | `useNoteActions` (L93280) | 169 LoC (limit: 70) | Medium |
---
### 3. `src/components/NoteList.tsx` — Score: 8.05
Slightly regressed from 8.11. The `NoteListInner` component and `buildRelationshipGroups` remain complex.
**Code Smells Found:**
| Smell | Location | Details | Severity |
|-------|----------|---------|----------|
| Complex Method | `NoteListInner` (L211432) | cc = 28 | Medium |
| Complex Method | `buildRelationshipGroups` (L125188) | cc = 13 | Medium |
| Large Method | `NoteListInner` (L211432) | 208 LoC (limit: 120) | Medium |
| Overall Code Complexity | File-wide | High mean cyclomatic complexity | Medium |
**Business Case:** Improving to 9.1 yields 2740% defect reduction and 2132% speed improvement. **This is the highest-ROI refactoring target.**
---
### 3. `src/App.tsx` — Score: 7.13
### 4. `src/components/AIChatPanel.tsx` — Score: 8.51
New file (mock AI chat feature). Already showing signs of complexity that should be addressed early.
**Code Smells Found:**
| Smell | Location | Details | Severity |
|-------|----------|---------|----------|
| Bumpy Road | `updateMockFrontmatter` (L2188) | 2 bumps | High |
| Deep Nesting | `updateMockFrontmatter` (L2188) | 4 levels deep | High |
| Complex Method | `App` (L131591) | cc = 56 (**Brain Method**) | Medium |
| Complex Method | `updateMockFrontmatter` (L2188) | cc = 17 | Medium |
| Large Method | `App` (L131591) | 381 LoC (limit: 120, **3x over**) | Medium |
**Business Case:** Improving to 9.1 yields 2739% defect reduction and 2031% speed improvement.
| Complex Method | `AIChatPanel` (L62364) | cc = 15 | Medium |
| Large Method | `AIChatPanel` (L62364) | 285 LoC (limit: 120) | Medium |
---
### 4. `src/components/Inspector.tsx` — Score: 7.49
### 5. `src-tauri/src/vault.rs` — Score: 8.81
**Code Smells Found:**
| Smell | Location | Details | Severity |
|-------|----------|---------|----------|
| Bumpy Road | `parseFrontmatter` (L78150) | 2 bumps | High |
| Bumpy Road | `DynamicPropertiesPanel` (L441516) | 2 bumps | High |
| Complex Method | `parseFrontmatter` (L78150) | cc = 21 | Medium |
| Complex Method | `DynamicPropertiesPanel` (L441516) | cc = 18 | Medium |
| Complex Method | `renderEditableValue` (L527624) | cc = 16 | Medium |
| Complex Method | `Inspector` (L806912) | cc = 14 | Medium |
| Complex Conditional | `renderEditableValue:590` | 3 complex expressions | Medium |
| Complex Conditional | `parseFrontmatter:115` | 2 complex expressions | Medium |
| Overall Code Complexity | File-wide | High mean cyclomatic complexity | Medium |
**Business Case:** Improving to 9.1 yields 2636% defect reduction and 1828% speed improvement.
Dramatically improved from 6.22. The CodeScene review reports **zero code smells** after the refactoring. The file is near the Green threshold (9.0) and may only need minor adjustments to cross it.
---
## Quick Wins (Low Effort, High Impact)
These are targeted refactorings that can improve scores immediately:
### 1. Decompose `Editor` into hooks (highest ROI)
**File:** `src/components/Editor.tsx` | **Impact:** cc 61 -> ~10 per hook
- Extract `useEditorExtensions()` — all CodeMirror extension setup (themes, keybindings, decorations)
- Extract `useEditorContent()` — content loading, saving, dirty state management
- Extract `useEditorKeymap()` — custom keymap handlers
- The `Editor` component becomes a thin composition + JSX layer
### 1. Extract `App` component state into custom hooks
**File:** `src/App.tsx` | **Impact:** cc 56 → ~10 per hook
- Extract `useVaultData()` — vault loading, entry management
- Extract `useEditorState()` — selected entry, editor content, undo/redo
- Extract `useKeyboardShortcuts()` — all keyboard event handlers
- Extract `useSearch()` — search/filter state and logic
- The `App` component becomes a thin composition layer
### 2. Decompose `useNoteActions` hook
**File:** `src/hooks/useNoteActions.ts` | **Impact:** cc 30 -> ~8 per hook
- Extract `useFrontmatterSync()``updateMockFrontmatter` + `deleteMockFrontmatterProperty`
- Flatten `updateMockFrontmatter` with early returns and helper functions
- Keep `useNoteActions` as pure action dispatch (create, delete, rename)
### 2. Extract `updateMockFrontmatter` helper functions
**File:** `src/App.tsx` (L2188) | **Impact:** Eliminates deep nesting + bumpy road
- Extract date-comparison logic into a helper
- Extract frontmatter field-update logic per field type
- Flatten conditionals with early returns
### 3. Split `NoteListInner` into sub-components
**File:** `src/components/NoteList.tsx` | **Impact:** cc 28 -> ~8 per component
- Extract `NoteListItem` component for individual note rendering
- Extract `RelationshipGroup` component for grouped entries
- Extract `buildRelationshipGroups` to a utility file
### 3. Deduplicate `update_frontmatter` / `delete_frontmatter_property`
**File:** `src-tauri/src/vault.rs` (L416449) | **Impact:** Eliminates code duplication smell
- Both functions share the same file-read + frontmatter-parse + write-back pattern
- Extract shared logic into a `with_frontmatter<F>(path, f: F)` helper
### 4. Extract `AIChatPanel` hooks early
**File:** `src/components/AIChatPanel.tsx` | **Impact:** Prevent further complexity growth
- Extract `useChatMessages()` — message state, send/receive logic
- Extract `ChatMessage` component for individual message rendering
### 4. Flatten `expandWikilinksInContent`
**File:** `src/components/Editor.tsx` (L119146) | **Impact:** Eliminates deep nesting
- Use early `continue` in the loop
- Extract inner matching logic into a `resolveWikilink()` helper
### 5. Split `DynamicPropertiesPanel` into sub-components
**File:** `src/components/Inspector.tsx` | **Impact:** Reduces 4 complex methods to focused units
- Extract `EditableValue` component for `renderEditableValue`
- Extract `FrontmatterParser` utility for `parseFrontmatter`
- Extract `PropertyRow` component for individual property rendering
### 5. Push `vault.rs` past 9.0
**File:** `src-tauri/src/vault.rs` | **Impact:** 8.81 -> 9.0+
- Minor: reduce string-heavy args further with `&Path` conversions
- Minor: simplify any remaining complex expressions
---
## Larger Refactoring Plans
## Path to 9.5 Overall
### Plan A: Decompose `vault.rs` (Priority 1 — Score 4.80 → 8+)
**Current:** 9.33 (28 scored files, sum = 261.20)
**Target:** 9.5
**Goal:** Raise from near-Red (4.80) to Green (9+) in 45 steps.
To reach 9.5, all 5 Yellow files must reach at least 9.5:
| Step | Action | Target Smell |
|------|--------|--------------|
| 1 | Extract `frontmatter.rs` module — move `FrontmatterValue`, `to_yaml_value`, `update_frontmatter_content`, `format_yaml_key` | Reduces file size, isolates complexity |
| 2 | Introduce `with_frontmatter()` helper to deduplicate `update_frontmatter` / `delete_frontmatter_property` | Code Duplication |
| 3 | Refactor `update_frontmatter_content` — flatten nesting with early returns, extract `apply_field_update()` helper | Deep Nesting, Bumpy Road |
| 4 | Refactor `days_from_epoch` — use a lookup table or `chrono` crate helpers instead of manual conditionals | Bumpy Road, Complex Conditional |
| 5 | Replace string args with newtype wrappers (`VaultPath`, `FilePath`, `PropertyKey`) | String-Heavy Args |
| File | Current | Target | Points Needed |
|------|---------|--------|---------------|
| `vault.rs` | 8.81 | 9.5 | +0.69 |
| `Editor.tsx` | 7.68 | 9.5 | +1.82 |
| `useNoteActions.ts` | 7.81 | 9.5 | +1.69 |
| `NoteList.tsx` | 8.05 | 9.5 | +1.45 |
| `AIChatPanel.tsx` | 8.51 | 9.5 | +0.99 |
| **Total points needed** | | | **+6.64** |
### Plan B: Decompose `Editor.tsx` (Priority 2 — Score 6.94 → 9+)
**Projected score if all Yellow files reach 9.5:** (261.20 + 6.64) / 28 = **9.57**
**Goal:** Raise from Yellow (6.94) to Green (9+) in 34 steps.
| Step | Action | Target Smell |
|------|--------|--------------|
| 1 | Extract `useEditorExtensions()` hook — all CodeMirror extension setup | Reduces Editor cc from 29 |
| 2 | Extract `useWikilinks()` hook — wikilink expansion, resolution | Deep Nesting, Complex Conditional |
| 3 | Extract `DiffView` into its own file `DiffView.tsx` | Complex Method (cc=13) |
| 4 | Extract `useEditorContent()` hook — content loading, saving, dirty state | Further reduces Editor complexity |
### Plan C: Decompose `App.tsx` (Priority 3 — Score 7.13 → 9+)
**Goal:** Break the Brain Method pattern. The `App` function at cc=56 and 381 LoC is the single worst function in the frontend.
| Step | Action | Target Smell |
|------|--------|--------------|
| 1 | Extract `useVaultLoader()` — vault path selection, entry loading, refresh | Reduces App cc by ~15 |
| 2 | Extract `useNoteActions()` — create, delete, rename, move note | Reduces App cc by ~10 |
| 3 | Extract `useAppKeyboard()` — all keyboard shortcut handlers | Reduces App cc by ~8 |
| 4 | Extract `useFrontmatterSync()` — mock frontmatter update logic | Eliminates Bumpy Road + Deep Nesting |
| 5 | Move layout JSX into `AppLayout.tsx` presentational component | Reduces App to pure orchestration |
### Plan D: Decompose `Inspector.tsx` (Priority 4 — Score 7.49 → 9+)
**Goal:** The largest file (912 LoC) with 4 complex methods needs structural decomposition.
| Step | Action | Target Smell |
|------|--------|--------------|
| 1 | Extract `parseFrontmatter()` to `src/utils/frontmatter.ts` shared utility | Complex Method (cc=21), Bumpy Road |
| 2 | Extract `EditableValue.tsx` component from `renderEditableValue` | Complex Method (cc=16) |
| 3 | Extract `DynamicPropertiesPanel.tsx` as standalone component | Bumpy Road, Complex Method (cc=18) |
| 4 | Simplify `Inspector` to compose sub-components | Reduces cc from 14 to ~5 |
**Recommended execution order for maximum impact:**
1. `Editor.tsx` (7.68 -> 9.5) — highest user-facing impact, hook extraction is mechanical
2. `useNoteActions.ts` (7.81 -> 9.5) — extracted hook, straightforward decomposition
3. `NoteList.tsx` (8.05 -> 9.5) — component extraction
4. `AIChatPanel.tsx` (8.51 -> 9.5) — closest to target, prevent drift
5. `vault.rs` (8.81 -> 9.5) — near-Green already, minor tweaks
---
@@ -226,22 +280,11 @@ These are targeted refactorings that can improve scores immediately:
| File | Current | Target | Defect Reduction | Speed Improvement |
|------|---------|--------|------------------|-------------------|
| `Editor.tsx` | 6.94 | 9.1 | 2740% | 2132% |
| `App.tsx` | 7.13 | 9.1 | 2739% | 2031% |
| `Inspector.tsx` | 7.49 | 9.1 | 2636% | 1828% |
| `vault.rs` | 4.80 | 5.15* | 27% | 13% |
*\*vault.rs target is conservative (industry average). A full refactoring to 9+ would yield dramatically higher ROI but requires more structural work.*
---
## Recommended Execution Order
1. **`vault.rs`** — Lowest score, near-Red zone. Foundational backend code that all frontmatter operations depend on. Fix this first to prevent defect accumulation.
2. **`Editor.tsx`** — Highest ROI. Core user-facing component where bugs are most visible. Decomposition into hooks is straightforward.
3. **`App.tsx`** — Brain Method must be broken up. The cc=56 function is a maintenance trap — any new feature added here increases risk nonlinearly.
4. **`Inspector.tsx`** — Largest file but lower priority because it's more self-contained. Decompose after the above three.
5. **`NoteList.tsx`** (8.11) and **`Sidebar.tsx`** (9.02) — minor improvements, address opportunistically.
| `Editor.tsx` | 7.68 | 9.5 | 2538% | 1930% |
| `useNoteActions.ts` | 7.81 | 9.5 | 2436% | 1828% |
| `NoteList.tsx` | 8.05 | 9.5 | 2233% | 1626% |
| `AIChatPanel.tsx` | 8.51 | 9.5 | 1827% | 1321% |
| `vault.rs` | 8.81 | 9.5 | 1018% | 814% |
---
@@ -249,13 +292,54 @@ These are targeted refactorings that can improve scores immediately:
These files need no immediate attention:
- `src-tauri/src/main.rs` — 10.0 (6 LoC, clean entry point)
- `src-tauri/src/git.rs`10.0 (423 LoC, well-structured)
- `src/mock-tauri.ts` — 10.0 (707 LoC, clean mock layer)
- `src/components/StatusBar.tsx` — 10.0 (62 LoC, minimal component)
**Optimal (10.0):**
- `src-tauri/src/main.rs`6 LoC, clean entry point
- `src-tauri/src/git.rs` — 423 LoC, well-structured
- `src/components/EditableValue.tsx` — 167 LoC, clean extracted component
- `src/components/ResizeHandle.tsx` — 74 LoC, simple component
- `src/components/CreateNoteDialog.tsx` — 99 LoC, clean dialog
- `src/components/Toast.tsx` — 28 LoC, minimal component
- `src/utils/typeColors.ts` — 37 LoC, simple utility
- `src/main.tsx` — 16 LoC, entry point
**Green (9.09.9):**
- `src-tauri/src/frontmatter.rs` — 9.68 (up from 6.89! Only: string-heavy args)
- `src-tauri/src/lib.rs` — 9.68 (minor: string-heavy args)
- `src/hooks/useTheme.ts` — 9.68 (clean hook)
- `src/components/QuickOpenPalette.tsx` — 9.55 (minor: cc=16)
- `src/utils/wikilinks.ts` — 9.53 (clean utility)
- `src/hooks/useVaultLoader.ts` — 9.41 (clean hook)
- `src/components/CommitDialog.tsx` — 9.38 (clean component)
- `src/mock-tauri.ts` — 9.37 (large but clean)
- `src/App.tsx` — 9.28 (dramatically improved from 7.13)
- `src/utils/frontmatter.ts` — 9.24 (clean utility)
- `src/components/StatusBar.tsx` — 9.23 (slightly regressed from 10.0)
- `src/components/Sidebar.tsx` — 9.14 (stable)
- `src/components/DiffView.tsx` — 9.09 (clean extracted component)
- `src/components/DynamicPropertiesPanel.tsx` — 9.06 (clean extracted component)
- `src/components/Inspector.tsx` — 9.02 (dramatically improved from 7.49)
---
*Report generated by CodeScene MCP analysis. For interactive exploration, visit: https://codescene.io/projects/76865*
## What Worked Since Last Report
The following refactorings from the Feb 17 recommendations were executed:
1. **App.tsx decomposition** (Plan C) — Extracted `useNoteActions`, `useVaultLoader`, and other hooks. App dropped from cc=56/381 LoC to cc=16/130 LoC. Score: 7.13 -> 9.28.
2. **Inspector.tsx decomposition** (Plan D) — Extracted `DynamicPropertiesPanel`, `EditableValue`, and `frontmatter.ts` utility. Score: 7.49 -> 9.02.
3. **vault.rs full refactoring** (Plan A) — Extracted `run_git` helper, decomposed `parse_md_file` and `scan_vault_cached`, split large assertion blocks, converted to `&Path` args. Score: 4.80 -> 8.81. **All code smells resolved.**
4. **frontmatter.rs full refactoring** (Plan B) — Flattened `update_frontmatter_content`, simplified `to_yaml_value` and `format_yaml_key`, extracted line-parsing helpers. Score: 6.89 -> 9.68. **Yellow -> Green.**
5. **Editor.tsx partial decomposition** (Plan B, Steps 23) — Extracted `DiffView.tsx` and `wikilinks.ts`. Score: 6.94 -> 7.68.
## What Still Needs Work
1. **Editor.tsx** — DiffView and wikilinks were extracted, but the core Editor function was NOT decomposed into hooks. It's now the worst function (cc=61, 385 LoC). Hook extraction (useEditorExtensions, useEditorContent, useEditorKeymap) is the next high-impact target.
2. **useNoteActions.ts** — Inherited App.tsx's `updateMockFrontmatter` complexity. Needs decomposition into smaller hooks.
3. **NoteList.tsx** — Slight regression, needs component extraction (NoteListItem, RelationshipGroup).
4. **AIChatPanel.tsx** — New file already showing complexity. Address early before it grows.
5. **vault.rs** — Near-Green at 8.81 with zero code smells. Minor tweaks may push it past 9.0.
---
*Report generated by CodeScene MCP analysis on 2026-02-20. For interactive exploration, visit: https://codescene.io/projects/76865*
*Note: CodeScene MCP Server MCP-0.1.5 was used. Version MCP-0.2.0 is available — consider updating via `brew upgrade cs-mcp`.*