Skip to content

Implement to support with claude desktop - #4

Merged
hungpham10 merged 1 commit into
mainfrom
feature/fix-issue-cannot-working-with-claude-desktop
Aug 10, 2026
Merged

hungpham10 merged 1 commit into
mainfrom
feature/fix-issue-cannot-working-with-claude-desktop

Conversation

@hungpham10

@hungpham10 hungpham10 commented Aug 10, 2026 •

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added session-based MCP workspace management with initialization, indexing, reinitialization, and deinitialization tools.
    • Added MCP serving over standard input/output with clearer tool discovery and client-visible errors.
    • Simplified the CLI to focus on init, deinit, and serve --mcp.
    • Added optional indexing during workspace initialization and explicit full reindexing.
  • Documentation

    • Updated setup, lifecycle, available tools, architecture, and re-indexing guidance.
    • Documented the recommended MCP session workflow.

@hungpham10
hungpham10 merged commit 40c4ac9 into main Aug 10, 2026
5 of 9 checks passed
@coderabbitai

coderabbitai Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99cb9a90-7c0a-4c16-851c-27e6468f983b

📥 Commits

Reviewing files that changed from the base of the PR and between a029afd and 5095bf9.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • README.md
  • crates/codegraph-mcp/Cargo.toml
  • crates/codegraph-mcp/src/http.rs
  • crates/codegraph-mcp/src/lib.rs
  • crates/codegraph-mcp/src/protocol.rs
  • crates/codegraph-mcp/src/server-instructions.md
  • crates/codegraph-mcp/src/session.rs
  • crates/codegraph-mcp/src/stdio.rs
  • crates/codegraph-mcp/src/tools.rs
  • crates/codegraph/Cargo.toml
  • crates/codegraph/src/main.rs

Walkthrough

The MCP crate now uses rmcp transports and session-bound workspace operations. The CLI supports asynchronous init, deinit, and serve --mcp commands. Documentation describes the new lifecycle and expanded tool set.

Changes

MCP session and CLI lifecycle

Layer / File(s) Summary
rmcp transports and tool contracts
crates/codegraph-mcp/Cargo.toml, crates/codegraph-mcp/src/http.rs, crates/codegraph-mcp/src/stdio.rs, crates/codegraph-mcp/src/tools.rs
The crate adds rmcp-based tool definitions and stdio serving. It adds a feature-gated HTTP transport stub.
Workspace session lifecycle
crates/codegraph-mcp/src/session.rs, crates/codegraph-mcp/src/tools.rs, crates/codegraph-mcp/src/server-instructions.md
Sessions now bind, initialize, deinitialize, validate, reload, and reindex workspaces. Initialization can return extraction statistics.
Session-aware server dispatch
crates/codegraph-mcp/src/lib.rs
CodegraphServer replaces the fixed-root server. Tool calls use session state and rmcp responses.
Reduced CLI and usage documentation
crates/codegraph/src/main.rs, crates/codegraph/Cargo.toml, README.md
The CLI removes legacy commands and supports asynchronous lifecycle commands and MCP serving. README instructions reflect the new workflow and 30 tools.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MCPClient
  participant serve_stdio
  participant CodegraphServer
  participant Session
  MCPClient->>serve_stdio: Send MCP tool request
  serve_stdio->>CodegraphServer: Forward rmcp call
  CodegraphServer->>Session: Apply session operation
  Session-->>CodegraphServer: Return state or tool data
  CodegraphServer-->>serve_stdio: Return rmcp result
  serve_stdio-->>MCPClient: Send MCP response
Loading

Possibly related PRs

Suggested reviewers: cleboost, hungpham7-tiki

Poem

I bound a workspace, said the rabbit with glee,
Then indexed its symbols beneath the MCP tree.
rmcp carried each call,
Sessions guarded them all,
And the CLI grew small as can be.

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/fix-issue-cannot-working-with-claude-desktop

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codspeed

codspeed Bot commented Aug 10, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing feature/fix-issue-cannot-working-with-claude-desktop (5095bf9) with main (a029afd)

Open in CodSpeed

hungpham10 added a commit that referenced this pull request Oct 8, 2026
hungpham10 added a commit that referenced this pull request Oct 25, 2026
…eaning magic features (#51)

* Implement dynamic dispatch flag + fan-out

* Enrich Go semantics: method-set matching, function values, imports, concurrency markers

- Method-set matching cho implicit interface: receiver_fn hook lưu receiver
  base type vào Symbol.type_name (`func (f *File) Write` → "File"); khai báo
  method trong interface body là node `method_elem` (không phải
  method_declaration) — giờ được extract với scope đúng vào interface symbol.
  build_go_method_sets tính structural typing: T implements I ⟺ method
  names(I) ⊆ method names(T); w.Write() fan-out chỉ tới các type thỏa thay vì
  naive CHA (fallback giữ nguyên khi method-set chưa đủ dữ liệu).
- Function value tracking: go_fn_ptr_assign bắt `handler := process` /
  `handler = process` → PointerAssign fan-out (dùng chung machinery C).
- Package/import: FileDeps { package, imports } mới trong ParseResult;
  go_file_deps đọc package_clause + import_spec (alias→path);
  alias_qualified_name resolve `orders.Get` qua import alias cho in-repo
  packages (match segment cuối path).
- Concurrency markers: MARKER_GO/MARKER_DEFER (Marker::Go/Defer) vào chain cho
  `go f()`/`defer f()`; select_statement wired vào switch machinery
  (communication_case); EffectType::Panic cho panic/log.Fatal/os.Exit.

Tests: 5 extractor (receiver type, interface method scope, fn value, file
deps, markers) + 2 e2e graph (method-set precision, import alias). Clippy
sạch, fmt xong.

* Go method-set: match signature, không chỉ tên + gom LangSpec thành nhóm

- Symbol.sig_key: signature key chuẩn hóa `(param_types)(result_types)` (bỏ
  tên param) qua sig_key_fn hook; go_signature_key dùng chung cho
  method_declaration/method_elem/function_declaration. build_go_method_sets
  thỏa interface ⟺ (name, sig_key) khớp — `Wrong.Read(string) string` không
  còn bị coi là implement `Reader.Read([]byte) (int, error)`. Thiếu key nào →
  fallback name-only (lenient); interface 0 method → skip.
- LangSpec refactor: gom 3 nhóm base / hooks (HookSpec — các Option<fn>,
  HookSpec::none()) / markers (MarkerSpec — control-flow kinds + field names,
  MarkerSpec::dflt()); LangSpec::dflt() const + FRU hợp lệ trong static.
  14 language spec chỉ khai field KHÁC default — thêm hook mới không còn phải
  sửa 14 file.

* Rust semantic enrichment: field/param typing, use indexing, cross-file impl linking, sig_key

- decls += field_declaration/parameter/let_declaration: struct field, tham số
  và local giờ là symbol có type_name (từ field `type`) — tie-break
  field_declared_type resolve `db.query()` theo type của `db`. Parameter lấy
  tên từ field `pattern` TRƯỚC name_type_fallback (tránh lấy nhầm tên kiểu).
- rust_file_deps: extract `use` (alias = `as` alias hoặc segment cuối);
  import_alias_candidates hỗ trợ `Type::method` — `use crate::storage::Database`
  + `Database::new()` resolve về method của class Database (Alias).
- link_impls_globally: impl linking chuyển lên global ingest — `impl Worker`
  khác file với `struct Worker` vẫn nối (type_ref → def, re-parent methods).
- rust_signature_key: `(params)(return)` cho method/fn (self → "self") —
  nguyên liệu trait matching theo signature.

* Python semantic enrichment + persist dynamic indexes qua reopen

Python (theo review gaps):
- param_container_kinds: `parameters` container → Parameter symbols (identifier
  / typed_parameter / default_parameter, type từ type hint) — field/param
  typing cho tie-break resolution.
- field_from_self_attr: `self.attr = Database()` → Field symbol scope vào
  class, type từ callee text — instance-attr typing.
- py_file_deps: import/import-as/from-import → FileDeps (alias→path), ăn vào
  import_alias_candidates sẵn có.
- py_superclasses: `class File(Writer)` → impl_trait "Writer" — inheritance
  fan-out qua machinery impl_index (giống C++ base class).

Persistence (fix: dynamic indexes chỉ ở RAM, MCP restart là mất):
- Storage trait + sqlite (sg_file_deps/sg_fn_ptr_assigns) + in_memory:
  persist ĐẦU VÀO thô FileDeps + FnPtrAssigns theo file path.
- rebuild() khi open: rebuild file_imports/fn_ptr_index từ blob +
  link_impls_globally/impl_index/go_impls từ sg_symbols — resolution quality
  giữ nguyên sau restart. E2e: dynamic_indexes_survive_reopen.

* Rust config review fixes: trait-declared methods + macro invocations

Review bằng fixture "thật" (trait + impl + macro + closure + async) phát hiện:
- function_signature_item (method KHAI BÁO trong trait) không được extract —
  không có symbol scope vào Interface nên fan-out Rust không bao giờ fire trên
  code thật (các test trước dùng synthetic symbols). Thêm vào decls → trigger
  Interface như Go method_elem.
- macro_invocation không phải call (println!/vec! mất hoàn toàn) — thêm
  CallRule với rust_macro_call_name (`println!`).
- E2E extraction thật: trait Repo{ping} + 2 impl → r.ping() fan-out cả hai
  (HierarchyFanOut) — chứng minh path thật chạy, không chỉ synthetic.
- Cập nhật chain expectation test cũ: cg_t!/cg_d! giờ là call thật.

Còn lại (defer): closure/callable tracking (cb()), generic instantiation,
associated type semantics, UFCS.

* Persist file_deps/fn_ptr_assigns cho MỌI storage backend

Trước đó chỉ sqlite + in_memory implement — lmdb/postgres/mysql/redis rơi về
no-op default = mất dynamic indexes khi reopen trên các backend đó.

- lmdb: 2 named DBI (sg_file_deps/sg_fn_ptr_assigns) + set/all (cursor iter)
  + clear_entities.
- postgres/mysql: bảng sg_file_deps/sg_fn_ptr_assigns (repo_id, path) PK,
  CREATE TABLE IF NOT EXISTS idempotent khi mở repo (không cần migration tay);
  mysql dùng ON DUPLICATE KEY UPDATE; clear_entities thêm 2 bảng.
- redis: 2 hash keys (filedeps/fnptpassigns) + DEL trong clear_entities.
- cached.rs: forward 4 methods xuống inner storage (trước đây rơi về default
  no-op → bypass backend thật!).
- Test roundtrip in_memory (set/all/clear); build + test --all-features.

* callers()/impact xuyên dyn-trait: fan-out fire theo receiver_text + dyn_callers index

Review qua MCP index thật (codegraph-rs tự index chính nó) phát hiện:
- `callers(set_file_deps)` trả rỗng dù ingest_with_progress gọi nó qua
  `dyn Storage` — call qua trait object bị resolve Single vì is_method_dispatch
  check `call_name.contains('.')` nhưng extractor đã rút call_name còn bare,
  trong khi receiver_text vẫn giữ receiver.
- Fix 1: is_method_dispatch = receiver_text.is_some() || call_name.contains('.')
  → fan-out fire cho dyn-trait call.
- Fix 2: dyn_callers (callee → callers) build từ call_meta khi ingest, scan
  call records khi rebuild; callers_resumable merge vào pending (dedup qua
  visited) → callers()/impact() thấy caller xuyên dyn-trait/interface/fn-ptr.
- E2E: callers() của từng impl method thấy dyn caller (trước đây rỗng).

Note vận hành: MCP server đang chạy bị MDB_BAD_RSLOT sau re-index in-process —
reader locktable stale, cần restart MCP server (issue riêng, chưa xử lý).

* Java + JavaScript/TypeScript semantic enrichment

Review setup vs machinery Go/Rust/Python đã có — lấp các gap:

Java (typing đã tốt nhất: field/param/local + annotations + implements):
- java_supers: gộp extends (superclass) + implements vào impl_trait —
  inheritance fan-out qua machinery C++-base (superclass đứng trước).
- java_signature_key: (params)(return) — tên param bỏ.
- java_file_deps: import (bỏ static/wildcard) → FileDeps; strip keyword
  "extends" khỏi superclass text.

JavaScript/TypeScript:
- param_container_kinds formal_parameters: js identifier/rest_pattern, ts
  required/optional_parameter (name từ field pattern, type từ type_annotation
  — strip ':' + '?'). Trước đây params KHÔNG được extract.
- js_file_deps (share TS): import default/named-as/namespace → FileDeps.
  Bug kèm theo: class_type_name cũ không bao giờ match JS thuần (class_heritage
  không có extends_clause — chỉ TS có); js_extends xử lý cả 2 grammar.
- js_extends → impl_trait: inheritance fan-out cho class extends.
- js_fn_value_assign: `handler = process` / `const h = process` (identifier
  thuần) → PointerAssign machinery.

Tests: 3 fixture mới (java supers/sig/imports; js params/imports/extends/
fn-value; ts typed params + interface method scope). 20/21 suite (Redis env).

* PHP/Ruby/Lua/Scala semantic enrichment — hoàn thiện fan-out toàn ngôn ngữ

PHP (typing đã tốt: params/property/variable):
- php_supers: base_clause (extends) + class_interface_clause (implements) —
  LÀ NODE KIND không phải field name (child_by_field_name trả None!) —
  inheritance fan-out.
- php_signature_key + php_use_deps (namespace_use_declaration, bỏ
  function/const/wildcard).

Ruby (mỏng nhất — params chưa từng extract):
- param_container_kinds method_parameters: identifier/optional_parameter/
  keyword_parameter/splat_parameter.
- ruby_superclass → impl_trait (bỏ dynamic superclass `< Struct.new(..)`).
- ruby_require_deps: require/require_relative → FileDeps.

Lua:
- param_container_kinds "parameters" (kind thật, không phải parameter_list).
- lua_require_deps: `local mod = require('mod')` ghép variable_list với
  expression_list theo vị trí.
- lua_fn_value_assign: `handler = process` → PointerAssign.

Scala:
- scala_supers: field "extend" (extends_clause là node kind, field tên
  "extend") — extends B with T → "B,T".
- scala_signature_key + scala_file_deps (import_declaration, selector
  `.{a, b => c}`); token keyword "import" có cùng kind — guard child_count.

Bài học chung: field name vs node kind khác nhau từng grammar — luôn dump AST
trước khi wire hook.

* Swift/C# semantic enrichment — đủ 14/14 ngôn ngữ

Swift (trước đây gần trống — không hooks):
- decls += protocol_function_declaration: method KHAI BÁO trong protocol
  scope vào Interface → fan-out (đúng bug Rust từng mắc).
- swift_supers: inheritance_specifier (`class FileRepo: BaseRepo, Repo`) →
  impl_trait — protocol conformance đi cùng cơ chế fan-out.
- swift_signature_key: Swift dùng TRÙNG tên field "name" cho tên param VÀ
  type (lấy field "name" cuối); match cả protocol_function_declaration;
  return = user_type sau token "->".
- swift_import_deps: import_declaration → FileDeps.

C# (typing/annotations sẵn tốt):
- csharp_bases: base_list (node kind, unnamed child) → impl_trait
  (base class + interfaces, strip generic).
- csharp_signature_key: return field là "returns" (không phải "type").
- csharp_using_deps: `using App.Repos` + alias form `using Db = App.Data`.

Tests: 2 fixture mới (swift protocol/supers/sig/imports; csharp bases/sig/
using). 25/25 dynamic_dispatch, 20/21 workspace (Redis env-only).

* FunctionValue + member assignment + MARKER_AWAIT (priority 1/3/6)

A. FunctionValue cho 4 ngôn ngữ còn thiếu:
- Python: `handler = process` (identifier=identifier) + `self.handler = process`
  (member, var = "self.handler").
- Ruby: CHỈ `handler = method(:process)` — plain `x = process` là LỜI GỌI
  trong Ruby, không track.
- Java: `Runnable r = this::run` — method_reference, target = identifier cuối
  (không phụ thuộc field name grammar).
- C#: `Action handler = Process` — value là identifier UNNAMED (không có
  field "value") — lấy identifier con cuối khác name.

B. Member fn assignment `obj.handler = fn`:
- Mở guard fn_ptr_index (bỏ `!contains('.')`) — lookup theo call_name bare
  lẫn dotted.
- js/ts: member_expression left → key full dotted text (`Foo.prototype.run`).
- lua: text chứa '.' → full text; bracket `handlers["read"]` skip.
- python: self.attr.

C. MARKER_AWAIT (Marker::Await = 27): MarkerSpec.await_kinds — python "await",
js/ts/csharp/swift "await_expression" (dump AST xác nhận); walk_chain push
AWAIT trước call như GO/DEFER → edge mang ngữ cảnh async boundary.

E2E: member_fn_assignment_resolves_dotted_call — `obj.handler = process` +
`obj.handler()` → PointerAssign (trước đây guard chặn). 25/25 dynamic_dispatch
(2 test mới), 20/21 workspace (Redis env-only).

* C/C++ enrichment batch 1-4: include graph, fn-ptr mở rộng, sig_key, virtual precision

1. c_include_deps: #include "foo.h" / <openssl/ssl.h> → FileDeps (path nguyên
   văn, alias = tên file không extension) — include graph qua machinery
   file_imports; C + C++ share.
2. c_fn_ptr_assign mở rộng: LHS field_expression (`obj.handler` — dotted key,
   ăn guard fn_ptr_index mới) + pointer_expression (`*handler` → "handler");
   RHS `&f` address-of + `&ns::cb` qualified.
3. cpp_signature_key: params từ function_declarator (function_definition 1
   tầng declarator; method inline field_declaration cũng 1 tầng — dump mới
   thấy, không phải 2); return field "type".
4. Virtual precision trong collect_fanout (C++ path): nếu CÓ candidate mang
   keyword virtual/override (signature chứa — extractor lưu dòng khai báo)
   → chỉ giữ virtual candidates + base decl; không keyword nào → giữ hết
   (soundness fallback). Loại non-virtual cùng tên trong hierarchy.

E2E: cpp_virtual_filter_prefers_override_candidates (D2 non-virtual bị loại).
Tests: 26/26 dynamic_dispatch (2 mới), 121/121 graph lib, 20/21 workspace
(Redis env-only).

* Web UI: dynamic-dispatch badges, Call sites/Pattern/Trace tabs, search pagination + annotation

Explore UI (SvelteKit + GraphQL) lộ đầy đủ query surface mới:

- Flow tab: mỗi call hiện badge resolvedVia ([dyn]/[fn-ptr]/[unresolved]/…)
  + candidate chips click-to-navigate (searchExact). GraphQL enum là
  SCREAMING_SNAKE_CASE — smoke query bắt được bug casing lowercase ban đầu.
- Tab Call sites (references): tìm callers theo call name — thấy cả
  unresolved/library + dynamic calls; prefill theo symbol name.
- Tab Pattern (searchFlow): tìm hàm theo chain pattern (markers/tên/id).
- Tab Trace (traceFullFlow — targetId arg): debug-style paths caller → target,
  indent theo stackDepth, icon theo action (CALL/RETURN/THROW/BRANCH/LOOP),
  màu theo PathEnding; chọn caller depth.
- SymbolSearch: Load more (offset pagination), "continue" khi timed_out
  (resumable cursor), source by name | by annotation
  (graphcodeSearchByAnnotation).

Smoke qua server thật: flow(ingest_with_progress) có 11 HIERARCHY_FAN_OUT
calls với 7 candidates (dyn Storage backends), trace 3 paths,
annotation "derive" 196 kết quả, references set_file_deps 2 callers.
svelte-check 0 errors, build-web assets embed, workspace tests 20/21
(Redis env-only).

* C/C++ batch #6 + #8: declaration–definition linking + namespace-qualified call

#6 link_cpp_decl_def (global, chạy cả ingest lẫn rebuild):
- `void Service::run() {}` trong .cpp (definition, có chain) nối với method
  khai báo trong .hpp (declaration, không chain): cùng tên + cùng sig_key
  (khi cả hai có) + khác file → def re-parent về scope của decl (class/
  namespace) + reclassify theo kind của decl; decl.type_ref → def.
- Hiệu ứng: fan-out/hierarchy thấy definition (có body/flow), class_info
  theo type_ref tới nơi có chain.

#8 qualified call `orders::run()`:
- Short-name fallback split cả '::' (rsplit ['.', ':'] bỏ segment rỗng) —
  trước đây "::" không split → qualified call unresolved hoàn toàn.
- Namespace preference: prefix trước '::' lọc candidate theo tổ tiên Module
  (namespace) cùng tên hoặc file chứa prefix — `foo::run` không còn nhầm
  `bar::run`; không subset khớp → giữ tất cả (soundness).

E2E: cpp_decl_def_linked_across_files (link đúng, pick_best ưu tiên def
has-chain); cpp_qualified_call_prefers_namespace (orders::run chọn đúng
namespace, không chọn bar). 123/123 graph lib, 20/21 workspace (Redis env).

* C/C++ batch cuối: lambda có tên (#5), macro theo thiết kế ghi-nhận (#9-lite), typedef signature (#4-lite)

#5 C++ lambda thành Function symbol:
- decls/func_kinds += lambda_expression → chain riêng cho calls trong lambda
  body (attribution chính xác, không gộp vào enclosing fn).
- anonymous_name_fn cpp_lambda_name: `auto f = [](){}` mượn tên biến —
  LƯU Ý init_declarator đặt tên ở field `declarator`, không phải `name`
  như JS variable_declarator (grammar khác nhau).

#9-lite macro THEO THIẾT KẾ GHI-NHẬN (không resolve):
- preproc_function_def + preproc_def → Constant symbol, signature = định
  nghĩa nguyên văn (`CALL(x) x()`, `MAX 10`) — macro KHÔNG phải function,
  invocation giữ raw call → usage tra qua call-name index (references).
- Hành vi semantic do config khai báo ("LLM tự định nghĩa"): `[[effect_rules]]`
  trong .codegraph/config.toml (matcher + EffectType, xét trước bảng default)
  — test chứng minh rule Contains "CALL" → Panic (exception-like).
- Không làm (đúng defer): macro expansion, conditional compilation.

#4-lite typedef signature:
- HookSpec thêm typedef_sig_fn; c_typedef_sig (C + C++ share): typedef +
  macro → signature = text định nghĩa (strip typedef/#define + ;). Hook
  ƯU TIÊN extract_signature (nó trả full text trước khiến hook không chạy).
- fn-ptr typedef giờ giữ underlying type: `int (*handler_t)(int)` thay vì
  chỉ `int` từ field type.

Tests: cpp_lambda_macro_typedef_batch (lambda symbol + chain + calls, macro
Constant + signature + raw invocation + effect-rule config, typedef sig).
20/21 workspace (Redis env-only), clippy sạch.

* MCP + GraphQL tool cấu hình effect rules runtime (LLM tự định nghĩa macro semantics)

Trước đây `[[effect_rules]]` chỉ đọc được từ .codegraph/config.toml — LLM phải
sửa file ngoài band rồi re-index. Giờ có tool chính tắc:

- config.rs CRUD API: list_effect_rules (raw — kể cả rule lỗi) /
  add_effect_rule (validate matcher + EffectType, toml_edit preserve mọi
  section khác) / remove_effect_rule (theo index). Sau ghi: install_current
  cho thread hiện tại; orchestrator reload config mỗi index nên rule áp dụng
  từ lần re-index kế tiếp (re-classify call records).
- MCP tool `codegraph_config_effects`: op list|add|remove; mô tả tool kèm
  ví dụ macro exception-like (contains CHECK → panic) + ghi chú áp dụng.
- GraphQL mutation `configEffects(op, matcher, text, effect, index)` mirror
  cho web UI.

Test: effect_rule_crud_roundtrip — add 2 rules → list đúng, classifier load
từ file classify CHECK_OK → Panic / db.Query → SqlQuery, effect sai bị chặn
(file không đổi), remove theo index, section khác (storage) nguyên vẹn.
Fix bug bắt được bởi test: or_insert tạo ArrayOfTables với table rỗng dummy
→ rule rỗng đầu danh sách.

* Bump version to v2.2.11

* Dọn debug eprintln sót (DBG by_name/DBG/DBG3/PHPDBG/SCALADBG) sau các batch debug
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant