UAT: NodeDefinition.lsp_binding typed field silently ignored by actor compiler — only raw lsp_bindings dict key is read #3012

Open
opened 2026-04-05 03:45:08 +00:00 by freemo · 3 comments
Owner

Metadata

  • Branch: fix/actor-compiler-lsp-binding-typed-field
  • Commit Message: fix(actor): read NodeDefinition.lsp_binding typed field in _extract_lsp_bindings()
  • Milestone: v3.6.0
  • Parent Epic: #824

Background

During UAT of the LSP Integration feature area, a bug was discovered in the actor compiler's LSP binding extraction logic. The NodeDefinition schema (defined in src/cleveragents/actor/schema.py) exposes a typed lsp_binding: NodeLspBinding | None field for per-node LSP binding configuration. However, the compiler's _extract_lsp_bindings() function in src/cleveragents/actor/compiler.py reads LSP bindings exclusively from the raw untyped config dict (node.config.get("lsp_bindings", [])), completely bypassing the typed field.

This means any actor YAML that declares per-node LSP bindings using the documented lsp_binding: key will have those bindings silently dropped at compile time. The NodeLspBinding model supports three binding modes (by server name, by language, by auto-detection), but none of these modes are reachable through the compiler since it never reads node.lsp_binding.

Steps to Reproduce

  1. Create a GRAPH actor YAML with a node that has lsp_binding: {server: "local/pyright"}
  2. Compile the actor with compile_actor()
  3. Observe that compiled.metadata.lsp_bindings is empty — the binding was silently ignored

Expected vs Actual Behaviour

Detail
Expected _extract_lsp_bindings() reads node.lsp_binding (the typed NodeLspBinding field) and maps all three binding modes into the compiled output
Actual _extract_lsp_bindings() reads node.config.get("lsp_bindings", []) (raw untyped dict); node.lsp_binding is never accessed

Affected Code Locations

  • Bug: src/cleveragents/actor/compiler.py_extract_lsp_bindings() function
  • Schema (unused): src/cleveragents/actor/schema.pyNodeDefinition.lsp_binding field and NodeLspBinding class

Severity

Medium — per-node LSP bindings declared via the documented lsp_binding: YAML key are silently dropped, causing actors to run without their intended LSP server connections. The undocumented workaround (placing lsp_bindings: inside the node's config: block) is the only path that currently works.

Subtasks

  • Audit _extract_lsp_bindings() in compiler.py and document the current (broken) read path
  • Update _extract_lsp_bindings() to read node.lsp_binding (the typed NodeLspBinding field) instead of node.config.get("lsp_bindings", [])
  • Handle all three NodeLspBinding binding modes: by server name, by language, and by auto-detection
  • Remove or deprecate the undocumented raw lsp_bindings config dict fallback (or retain it with an explicit deprecation warning)
  • Write Behave unit tests (in features/) covering each binding mode and the silent-ignore regression case
  • Write Robot Framework integration test (in robot/) verifying end-to-end that a compiled actor with lsp_binding: in its YAML produces a non-empty lsp_bindings in compiled.metadata
  • Ensure nox -e typecheck passes (no # type: ignore suppressions)
  • Ensure nox -e lint passes
  • Update inline docstrings for _extract_lsp_bindings() to reflect the corrected read path

Definition of Done

  • _extract_lsp_bindings() reads node.lsp_binding (the typed field) for all three NodeLspBinding modes
  • The silent-ignore regression is covered by a Behave unit test scenario
  • End-to-end binding extraction is verified by a Robot Framework integration test
  • All nox stages pass (nox -e lint, nox -e typecheck, nox -e unit_tests, nox -e integration_tests)
  • Coverage >= 97%
  • The fix is merged via a PR that closes this issue

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: ca-new-issue-creator

## Metadata - **Branch**: `fix/actor-compiler-lsp-binding-typed-field` - **Commit Message**: `fix(actor): read NodeDefinition.lsp_binding typed field in _extract_lsp_bindings()` - **Milestone**: v3.6.0 - **Parent Epic**: #824 ## Background During UAT of the LSP Integration feature area, a bug was discovered in the actor compiler's LSP binding extraction logic. The `NodeDefinition` schema (defined in `src/cleveragents/actor/schema.py`) exposes a typed `lsp_binding: NodeLspBinding | None` field for per-node LSP binding configuration. However, the compiler's `_extract_lsp_bindings()` function in `src/cleveragents/actor/compiler.py` reads LSP bindings exclusively from the raw untyped config dict (`node.config.get("lsp_bindings", [])`), completely bypassing the typed field. This means any actor YAML that declares per-node LSP bindings using the documented `lsp_binding:` key will have those bindings **silently dropped** at compile time. The `NodeLspBinding` model supports three binding modes (by server name, by language, by auto-detection), but none of these modes are reachable through the compiler since it never reads `node.lsp_binding`. ## Steps to Reproduce 1. Create a GRAPH actor YAML with a node that has `lsp_binding: {server: "local/pyright"}` 2. Compile the actor with `compile_actor()` 3. Observe that `compiled.metadata.lsp_bindings` is empty — the binding was silently ignored ## Expected vs Actual Behaviour | | Detail | |---|---| | **Expected** | `_extract_lsp_bindings()` reads `node.lsp_binding` (the typed `NodeLspBinding` field) and maps all three binding modes into the compiled output | | **Actual** | `_extract_lsp_bindings()` reads `node.config.get("lsp_bindings", [])` (raw untyped dict); `node.lsp_binding` is never accessed | ## Affected Code Locations - **Bug**: `src/cleveragents/actor/compiler.py` — `_extract_lsp_bindings()` function - **Schema (unused)**: `src/cleveragents/actor/schema.py` — `NodeDefinition.lsp_binding` field and `NodeLspBinding` class ## Severity **Medium** — per-node LSP bindings declared via the documented `lsp_binding:` YAML key are silently dropped, causing actors to run without their intended LSP server connections. The undocumented workaround (placing `lsp_bindings:` inside the node's `config:` block) is the only path that currently works. ## Subtasks - [ ] Audit `_extract_lsp_bindings()` in `compiler.py` and document the current (broken) read path - [ ] Update `_extract_lsp_bindings()` to read `node.lsp_binding` (the typed `NodeLspBinding` field) instead of `node.config.get("lsp_bindings", [])` - [ ] Handle all three `NodeLspBinding` binding modes: by server name, by language, and by auto-detection - [ ] Remove or deprecate the undocumented raw `lsp_bindings` config dict fallback (or retain it with an explicit deprecation warning) - [ ] Write Behave unit tests (in `features/`) covering each binding mode and the silent-ignore regression case - [ ] Write Robot Framework integration test (in `robot/`) verifying end-to-end that a compiled actor with `lsp_binding:` in its YAML produces a non-empty `lsp_bindings` in `compiled.metadata` - [ ] Ensure `nox -e typecheck` passes (no `# type: ignore` suppressions) - [ ] Ensure `nox -e lint` passes - [ ] Update inline docstrings for `_extract_lsp_bindings()` to reflect the corrected read path ## Definition of Done - [ ] `_extract_lsp_bindings()` reads `node.lsp_binding` (the typed field) for all three `NodeLspBinding` modes - [ ] The silent-ignore regression is covered by a Behave unit test scenario - [ ] End-to-end binding extraction is verified by a Robot Framework integration test - [ ] All nox stages pass (`nox -e lint`, `nox -e typecheck`, `nox -e unit_tests`, `nox -e integration_tests`) - [ ] Coverage >= 97% - [ ] The fix is merged via a PR that closes this issue --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: ca-new-issue-creator
freemo added this to the v3.6.0 milestone 2026-04-05 03:47:02 +00:00
Author
Owner

Label compliance fix applied:

  • Added missing labels: Priority/Medium, State/Unverified, Type/Bug
  • Reason: Issue was missing all required labels per CONTRIBUTING.md. Inferred Type/Bug from the "UAT:" prefix. Applied Priority/Medium and State/Unverified as defaults.

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: ca-backlog-groomer

Label compliance fix applied: - Added missing labels: `Priority/Medium`, `State/Unverified`, `Type/Bug` - Reason: Issue was missing all required labels per CONTRIBUTING.md. Inferred `Type/Bug` from the "UAT:" prefix. Applied `Priority/Medium` and `State/Unverified` as defaults. --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: ca-backlog-groomer
Author
Owner

Issue triaged by project owner:

  • State: Verified
  • Priority: Confirmed
  • MoSCoW: Should Have

Valid finding verified during batch triage.


Automated by CleverAgents Bot
Supervisor: Project Owner | Agent: ca-project-owner

Issue triaged by project owner: - **State**: Verified - **Priority**: Confirmed - **MoSCoW**: Should Have Valid finding verified during batch triage. --- **Automated by CleverAgents Bot** Supervisor: Project Owner | Agent: ca-project-owner
Author
Owner

State transition request: from State/Verified to State/In Progress.

Preconditions:

  • Not transitioning from State/Paused (no blocker involved).
  • No Blocked label detected.

Plan:

  • Remove old state label: State/Verified
  • Add new state label: State/In Progress

Status: The current Forgejo API wrapper here does not expose a direct endpoint to modify issue labels. I can: (a) update the issue title/body to reflect the new state, or (b) post a comment documenting the planned transition and await an admin-assisted label update.

Please advise how you would like me to finalize the label changes.


Automated by CleverAgents Bot
Supervisor: Implementation | Agent: ca-issue-state-updater

State transition request: from State/Verified to State/In Progress. Preconditions: - Not transitioning from State/Paused (no blocker involved). - No Blocked label detected. Plan: - Remove old state label: State/Verified - Add new state label: State/In Progress Status: The current Forgejo API wrapper here does not expose a direct endpoint to modify issue labels. I can: (a) update the issue title/body to reflect the new state, or (b) post a comment documenting the planned transition and await an admin-assisted label update. Please advise how you would like me to finalize the label changes. --- **Automated by CleverAgents Bot** Supervisor: Implementation | Agent: ca-issue-state-updater
freemo changed title from UAT: NodeDefinition.lsp_binding typed field silently ignored by actor compiler — only raw lsp_bindings dict key is read to [State/In Progress] UAT: NodeDefinition.lsp_binding typed field silently ignored by actor compiler — only raw lsp_bindings dict key is read 2026-04-05 07:06:40 +00:00
freemo changed title from [State/In Progress] UAT: NodeDefinition.lsp_binding typed field silently ignored by actor compiler — only raw lsp_bindings dict key is read to UAT: NodeDefinition.lsp_binding typed field silently ignored by actor compiler — only raw lsp_bindings dict key is read 2026-04-05 07:12:05 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Blocks
#824 Epic: LSP Functional Runtime
cleveragents/cleveragents-core
Reference
cleveragents/cleveragents-core#3012
No description provided.