Repository navigation
fix: pipeline item lookup wrong key + stringified label arrays - #74
Conversation
Two independent bugs found investigating a live incident where a
qualified lead's custom_fields and labels were never actually saved:
1. pipeline_manipulation.py's create_task pipeline-item lookup read
`items_response.get("payload", [])`, but GET
/pipelines/{id}/pipeline_items wraps its list under "data"
(`{"success": true, "data": [...], "meta": {...}}`) — "payload"
belongs to a different endpoint shape (conversation labels). This
silently returned an empty list every time, so the lookup always
missed even when the pipeline item existed.
2. manage_conversation_labels.py's _coerce_input_list received
labels='["a", "b", "c"]' as a single string (GLM via OpenRouter
stringified the array instead of emitting real JSON), and treated
the whole bracketed string as one literal label — which never
matched the catalog and was silently rejected. The model then
surfaced this to the user as "these labels don't exist", a
hallucinated explanation for a malformed tool argument.
_coerce_input_list now detects this shape and parses it back into
a real list, falling back to the previous literal-string behavior
if the bracketed string isn't valid JSON.
Added tests/unit/test_coerce_input_list.py covering both the live
regression and the list/None/malformed-input paths. No existing test
exercised pipeline_manipulation's inline GET-list-and-match logic
(only the caller was mocked), so bug 1 has no isolated unit test here
— it was confirmed live and via the private fork's extracted
_find_pipeline_item_id, covered there in a dedicated test file.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Sorry @mateusbellozupko, you've used your own review budget of 250,000 diff characters for the last 7 days.
You can request another review in 1 day and 10 hours by commenting @sourcery-ai review. Upgrade to get a review now.
Reviewer's GuideFixes two independent data-handling bugs: pipeline cards now resolve existing items from the API's Sequence diagram for pipeline item lookupsequenceDiagram
participant CreateTask
participant PipelineAPI
CreateTask->>PipelineAPI: GET /pipelines/{id}/pipeline_items
PipelineAPI-->>CreateTask: data: pipeline items
CreateTask->>CreateTask: item.get(conversation_id)
CreateTask->>CreateTask: item.get(id)
Flow diagram for stringified label array coercionflowchart TD
A[labels input] --> B{value is None}
B -->|yes| C[Return empty list]
B -->|no| D{Bracketed string}
D -->|yes| E[json.loads]
E --> F{Parsed value is list}
F -->|yes| G[Process list items]
F -->|no or invalid JSON| H[Process as literal string]
D -->|no| I{String or list}
I --> G
I --> H
G --> J[Deduplicate string labels]
H --> J
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey - I've reviewed your changes and they look great!
Sourcery assessment
Needs a human reviewer. The changes can persist conversation-label updates and associate newly created tasks with a pipeline item; if the parsing or lookup is wrong, those records may need manual correction or cleanup. Reverting stops future incorrect writes but does not undo values or associations already stored.
Summary
Two independent bugs found while investigating a live incident where a qualified lead's custom_fields and labels were never actually saved to its pipeline card:
pipeline_manipulation.py— thecreate_taskpipeline-item lookup readitems_response.get("payload", []), butGET /pipelines/{id}/pipeline_itemswraps its list under"data"({"success": true, "data": [...], "meta": {...}}) —"payload"belongs to a different endpoint shape (conversation labels). This silently returned an empty list every time, so the lookup always missed even when the pipeline item existed.manage_conversation_labels.py—_coerce_input_listreceivedlabels='["a", "b", "c"]'as a single string (GLM via OpenRouter stringified the array instead of emitting real JSON), and treated the whole bracketed string as one literal label — which never matched the catalog and was silently rejected. The model then surfaced this to the user as "these labels don't exist", a hallucinated explanation for what was actually a malformed tool argument._coerce_input_listnow detects this shape and parses it back into a real list, falling back to the previous literal-string behavior if the bracketed string isn't valid JSON.Test plan
tests/unit/test_coerce_input_list.py— new, covers the live regression plus list/None/malformed-input paths, 6/6 passingpytest tests/unit/(excluding a pre-existing, unrelatedtest_exception_handlers.pycollection error) — 394/394 passingpipeline_manipulation's inline GET-list-and-match logic (only the caller was mocked), so bug 1 has no isolated unit test in this repo — confirmed live and covered with a dedicated test in the private fork's extracted_find_pipeline_item_idhelper🤖 Generated with Claude Code
Summary by Sourcery
Fix pipeline card updates and conversation label handling for malformed or mismatched tool inputs.
Bug Fixes:
Tests: