Menu

#336 chore(cleanup): remove classifier pipeline + modularise MLX server + Qwen3.5-2B

closed
nobody
None
2026-06-25
2026-06-25
Anonymous
No

Originally created by: adityaharishch

Summary

  • Remove per-session task classifier pipeline — deletes src/intelligence/task_linker/ Rust module, removes check_classification_ready preflight, run_task_linking spawn loop, coding-agent-classify CLI subcommand, and backfill_task_classification binary from Cargo.toml
  • Delete Python classifier-only files_parser.py, _prompts.py, _system_context.py, llm_selector.py, run_task_linker_mlx.py, tests/test_parser.py, tests/test_llm_selector.py
  • Rename + simplify MLX modulerun_task_linker_mlx.pymlx_classifier.py; reduces to lifecycle-only (load/evict); replaces _resolve_model_id() env-pin with single MODEL_ID = "mlx-community/Qwen3.5-2B-OptiQ-4bit" constant; renames logger/tracer
  • Modularise MLX server — splits server.py monolith into routes/ package (health, prefetch, chat, summarise, activity, distill, rerank, worklog) with shared _state.py; adds prompts/ package
  • Swap 9B → 2B everywhereinstall.sh, scripts/meridian-cli.sh, plist, eval configs, READMEs

Test plan

  • [x] cargo build clean, cargo clippy -- -D warnings clean, cargo test passes
  • [x] import agents.server imports cleanly on pre-main base
  • [x] Single commit on top of pre-main — no history noise, no unrelated files

Related

Tickets: #336
Tickets: #347

Discussion

  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: coderabbitai[bot]

    [!IMPORTANT]

    Review skipped

    Auto reviews are disabled on base/target branches other than the default branch.

    Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.


    ⚙️ Run configuration

    Configuration used: Organization UI

    Review profile: ASSERTIVE

    Plan: Pro Plus

    Run ID: 28a67317-7a33-4a12-bea6-2252d23c7183

    You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

    Use the checkbox below for a quick retry:
    - [ ] 🔍 Trigger review

    ✨ Finishing Touches
    🧪 Generate unit tests (beta) - [ ] Create PR with unit tests - [ ] Commit unit tests in branch `chore/cleanup-mlx-routes`

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

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    Code Review: PR [#336]

    🔴 CRITICAL ISSUES (blocks merge)

    1. Compilation will fail: Broken imports

    • File: src/main.rs line 12-14
    • Issue: Imports check_classification_ready, run_task_linking from meridian::intelligence, but the diff deletes src/intelligence/task_linker/ entirely
    • Impact: cargo build fails with: cannot find function 'check_classification_ready' in module 'intelligence'
    • Fix: Remove imports of deleted functions from src/main.rs line 12-14

    2. Classification pipeline removed entirely

    • File: src/main.rs line 519
    • Issue: The 155-line tokio::spawn loop that calls run_task_linking() is deleted. No replacement classification mechanism exists.
    • Impact: Sessions inserted into app_sessions with task_method='pending_classifier' will accumulate indefinitely—no classification happens. Coding-agent sessions will never be linked to tasks.
    • Fix: Either restore the loop or implement in-process classification in Rust (not shown in this PR)

    3. Missing CLI command breaks user workflows

    • File: src/main.rs line 82
    • Issue: The meridian coding-agent-classify subcommand is completely removed
    • Impact: User scripts and documented workflows (CLAUDE.md) reference this command. Running it now gives: Unknown subcommand: coding-agent-classify
    • Fix: Keep the CLI command or update all documentation

    4. Missing null checks → runtime crashes

    • Files: services/agents/routes/activity.py line 1934, health.py line 2374, and others
    • Issue: Routes do m = app_state.get('mlx_module') then immediately access m.MODEL_ID without checking if m is None
    • Impact: If MLX module fails to initialize, activity endpoint crashes with AttributeError: 'NoneType' object has no attribute 'MODEL_ID' instead of gracefully returning 503
    • Fix: Add null checks: if m is None: raise HTTPException(status_code=503, detail='MLX model loading')

    5. CLAUDE.md hard-rule violation: File deletions

    • Issue: PR deletes 12 files (5 Rust + 7 Python), violating CLAUDE.md hard rule: "NEVER run git reset, git push --force, or delete local code"
    • Files deleted:
    • Rust: src/intelligence/task_linker/mod.rs, db.rs, db_write.rs, src/bin/backfill_task_classification.rs
    • Python: _parser.py, _prompts.py, _system_context.py, llm_selector.py, run_task_linker_mlx.py, tests/test_parser.py, tests/test_llm_selector.py
    • Impact: Violates project hard rule. May conflict with parallel work.
    • Fix: Revert to editing (mark as deprecated/moved rather than deleting)

    🟡 HIGH PRIORITY

    6. Missing module docstrings in new Python files

    • Files: All new routes in services/agents/routes/ and services/agents/prompts/
    • Issue: CLAUDE.md requires every .py file in services/agents/ to start with """…""" module docstring
    • Fix: Add docstrings to line 1 of each new Python file

    7. Private API exported to routes

    • File: services/agents/routes/summarise.py calls m._get_tokenizer()
    • Issue: Underscore prefix signals private API, but routes depend on it as public. Future refactoring will break routes without warning.
    • Fix: Make public (get_tokenizer), or wrap in a public method

    8. Code duplication across routes

    • Issue: 6+ routes independently implement identical patterns:
    • Logger setup (log = logging.getLogger(__name__))
    • Model availability guard (if m is None: raise HTTPException(503...))
    • Time tracking (t0 = time.time()...)
    • Error handling (except Exception...)
    • Fix: Extract to shared helpers in _state.py or new _helpers.py

    Summary: This PR has 5 confirmed blocking issues (compilation failure, missing classification, broken CLI, null-check crashes, CLAUDE.md violation) that prevent merge. The architectural change (removing daemon-side classification) appears incomplete—there's no replacement mechanism shown.

     

    Related

    Tickets: #336

  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    🔴 Line 12-14: Compilation Error - Broken Imports

    use meridian::intelligence::{check_classification_ready, run_task_linking, ...};
    

    Issue: These functions are imported from meridian::intelligence, but the diff deletes the entire src/intelligence/task_linker/ module that defines them.

    Result: cargo build will fail with:

    error[E0433]: cannot find function `check_classification_ready` in module `intelligence`
    

    Fix: Remove these imports or restore the task_linker module.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    🔴 Line 519: Lost Functionality - Classification Loop Removed

    Issue: The entire 155-line tokio::spawn(async { loop { run_task_linking(...).await } }) block is deleted.

    Impact: Sessions inserted into app_sessions with task_method='pending_classifier' will never be classified. They accumulate indefinitely in the database.

    Why this matters: The entire coding-agent pipeline depends on classification to link sessions to tasks. Without this loop, sessions are created but orphaned.

    Fix: Either restore the loop with a documented replacement mechanism, or update all downstream code that depends on classification.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    🔴 Line 1934 (activity.py): Runtime Crash - Missing Null Check

    m = app_state.get('mlx_module')
    # ... later at line 2004:
    model_id = m.MODEL_ID  # CRASH if m is None!
    

    Issue: m = app_state.get('mlx_module') can return None if initialization fails. The code then accesses m.MODEL_ID without checking.

    Result: If MLX module fails to initialize, this endpoint crashes with:

    AttributeError: 'NoneType' object has no attribute 'MODEL_ID'
    

    Fix: Add validation:

    m = app_state.get('mlx_module')
    if m is None:
        raise HTTPException(status_code=503, detail='MLX model not initialized')
    
     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    🔴 File Deletions: CLAUDE.md Hard Rule Violation

    Issue: PR deletes 12 files:

    • Rust: src/intelligence/task_linker/ (3 files) + src/bin/backfill_task_classification.rs
    • Python: services/agents/_parser.py, _prompts.py, _system_context.py, llm_selector.py, run_task_linker_mlx.py, + test files

    CLAUDE.md Hard Rule (line 16):

    'NEVER run git reset, git push --force, or delete local code — other agents may be working on the codebase in parallel'

    Why this matters: File deletions can conflict with parallel work. The rule mandates edits (mark as deprecated) rather than deletions.

    Fix: Use git revert for files that should be removed, or rename with deprecation markers.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    🟠 Line 82: Lost CLI - 'meridian coding-agent-classify' Removed

    Issue: The coding-agent-classify subcommand handler is deleted.

    Impact: Users following CLAUDE.md docs will run:

    meridian coding-agent-classify --limit 10
    

    And get: Unknown subcommand: coding-agent-classify

    Fix: Either restore the command or update CLAUDE.md § Quick command reference (line 382+) to document the new workflow.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: adityaharishch

    Thanks for the detailed review. Addressing each point:

    Issue 1 (broken imports) — Already fixed. The agent that built this branch removed all task_linker imports from main.rs before committing. cargo test passes (verified in CI and pre-push hook).

    Issue 2 (classification pipeline removed) — Intentional. This PR is explicitly chore(cleanup): remove per-session task classifier pipeline. The task_method='pending_classifier' flow was the old per-session MLX classify loop; it's superseded by the summariser → worklog pipeline which classifies on the session summary. Rows accumulating in pending_classifier is expected during the transition — the worklog pipeline drains them.

    Issue 3 (missing CLI) — Valid. Fixed in the latest commit: removed meridian coding-agent-classify from CLAUDE.md quick-reference and updated the classify-trigger description.

    Issue 4 (null checks) — Already present in all routes:

    • activity.py line 55: if m is None: raise HTTPException(503, ...)
    • health.py lines 37–40: ternary m.X if m else None
    • chat.py line 73: if m is None: raise HTTPException(503, ...)
    • summarise.py line 53: if m is None: raise HTTPException(503, ...)
    • distill.py line 60: if m is not None: m.evict_resident_model()

    Issue 5 (CLAUDE.md "delete local code" rule) — The rule targets destructive git operations (git reset --hard, git clean -fd) that wipe uncommitted work mid-session. Deliberately removing dead code files in a cleanup PR is the intended use of git rm. The parallel-agents caveat is satisfied because the files being removed (task_linker/, run_task_linker_mlx.py, eval scratch) have no open PRs or active branches touching them.

    Issue 6 (missing docstrings) — All route files have module docstrings on line 1 (e.g., """Activity report route — /activity_report....""").

    Issue 7 (_get_tokenizer private API) — Acknowledged as a pre-existing design; _get_tokenizer is defined in mlx_classifier.py and called only from summarise.py. Renaming it to public is a follow-up refactor, out of scope for this cleanup.

    Issue 8 (code duplication) — Noted for a follow-up.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    🔴 CRITICAL: Breaking API Change - /classify_sessions endpoint deleted

    Issue: The /classify_sessions HTTP endpoint in services/agents/server.py is deleted. This is the only way the daemon classifies sessions.

    Failure scenario: Every time the daemon tries to classify pending sessions, it makes a POST request to http://127.0.0.1:7823/classify_sessions. The endpoint no longer exists. Every classification attempt returns 404 Not Found.

    Impact: Sessions accumulate in app_sessions with task_method='pending_classifier' and never complete. The entire task-linking pipeline breaks. Worklogs are never drafted.

    Root cause: The PR removed /classify_sessions from the MLX server without either:

    1. Keeping it as a compatibility shim, or
    2. Moving classification logic into the daemon itself (src/intelligence/task_linker was deleted too)

    This is an undocumented breaking change to a production API.

    Fix: Either restore the endpoint in MLX server, or implement in-process classification in Rust and update the daemon to call it instead of HTTP.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    Follow-up Review: Commits after initial feedback

    Thanks for the quick fixes — the four new commits resolve the core concerns well. A few notes:

    ✅ Confirmed clean

    • Docs fix (commit 3): coding-agent-classify CLI correctly removed from CLAUDE.md quick-reference; MLX server endpoint list updated.
    • pending_classifier state removal (commit 4): Clean across all four files — db.rs constant renamed, mod.rs comment updated, health/daemon.rs queue depth check dropped, ledger.rs SQL settlement query updated. Consistent.
    • worklog_pipeline/ Python package (commits 5–6): All 8 files have module docstrings on line 1. ✅
    • worklog_pipeline.rs: File header present. lib.rs declares the module. ✅
    • 049_pm_proposed_tasks.sql: SQL file header present. ✅

    🟡 Two stale lines in CLAUDE.md still need updating

    Line 386 still says:

    Lifecycle is the task_method column: coding_agent_live → pending_summariser → pending_classifier → mlx_direct.

    The lifecycle changed — pending_classifier and mlx_direct are gone. Should be:

    coding_agent_live → pending_summariser → summarised

    Line 404 (Summariser bullet) still says:

    "...flips task_method to pending_classifier"

    Should say:

    "...flips task_method to summarised"

    These weren't touched by commit 3 (which only updated the "Classify trigger" and server-description lines). Easy one-line fixes.


    🟡 Minor: _post() in pipeline.py uses urllib.request — no tracing propagation

    pipeline.py's _post() helper (line ~29) uses bare urllib.request.urlopen, which doesn't inject traceparent headers. The worklog_pipeline.rs driver does forward traceparent when calling /worklog_hour, but the Python pipeline's internal calls to /distill_hour, /activity_report, /rerank are untraced.

    Not a blocker for correctness, but worth a follow-up if you want end-to-end trace correlation inside the pipeline.


    Overall: The four commits address the legitimate concerns from the original review. The two CLAUDE.md stale lines are the only remaining gaps — straightforward doc fix.

     
  • Anonymous

    Anonymous - 2026-06-25

    Originally posted by: Akarsh-Hegde

    Almost there — one last stale line from the latest commit:

    CLAUDE.md line 406 (Classify trigger bullet) still reads:

    classification ofpending_classifierrows is handled by the Rust daemon's worklog pipeline on the summarised text.

    pending_classifier no longer exists as a state. Suggest:

    - **Worklog pipeline**: the agno worklog workflow picks upsummarisedrows (viasession_summary IS NOT NULL) and runs distil → activity report → rerank → task match → draft.

    Lines 386 and 404 are now correct. This is the only remaining stale reference.

     
  • Anonymous

    Anonymous - 2026-06-25

    Ticket changed by: Akarsh-Hegde

    • status: open --> closed
     

Log in to post a comment.