IW-701: Send Linear user values as GraphQL variables #765

Merged
mph merged 10 commits from IW-701 into main 2026-10-08 06:21:32 +00:00
Member

Summary

LinearClient put user values (title, description, search text, team id, issue id, cursors) into GraphQL string literals inside a JSON string. That embedding needs two escaping layers; escapeForJson gave one, and the search and recent-issues builders gave none. A quote, a backslash or a newline made the GraphQL text or the JSON invalid.

Defects fixed

  • Phase 1 (#764): the five request builders (buildCreateIssueMutation, buildSearchIssuesQuery, buildListRecentIssuesQuery, buildIssueCommentIdsQuery, buildIssueCommentsQuery) now send a constant GraphQL text with the values in variables, written by ujson.write through one graphqlRequest helper. escapeForJson is removed.

Testing

  • LinearClientCreateIssueTest, LinearClientMockTest, LinearIssueTrackerTest decode the body and check that each value round-trips exactly in variables and that query is the constant text. 9 new or rewritten tests failed before the fix.
  • The manual reproduction program from analysis.md prints GraphQL OK on all 7 inputs.
  • Not verified: a round trip against a real Linear workspace. It needs a LINEAR_API_TOKEN. The variable types come from the published Linear schema.

Follow-ups

Two LinearClient.scala items (deprecated issueSearch; buildLinearQuery still interpolates IssueId) are attached to #643.

Release notes

Projekty, které vedou úkoly v Linearu, teď spolehlivě přenesou do Linearu přesně ten text, který uživatel zadal. Dříve stačila v názvu nebo popisu úkolu jediná uvozovka, zpětné lomítko nebo zalomení řádku, a Linear požadavek odmítl. Protože skoro každý delší popis má více řádků, nešlo o okrajový případ, ale o běžnou situaci.

Příkaz pro založení nového úkolu nyní projde i s názvem jako „Řekni "ahoj"“, s cestou k souboru obsahující zpětná lomítka nebo s popisem na mnoho řádků. Název i popis dorazí do Linearu znak po znaku tak, jak byly napsány, nic se cestou neztratí ani nezmění.

Opravené je i hledání úkolů na dashboardu. Hledaný výraz s uvozovkou dříve způsobil chybu a výraz se zpětným lomítkem se před odesláním tiše pozměnil, takže hledání vracelo jiné výsledky, než uživatel čekal. Teď Linear dostane hledaný výraz přesně v té podobě, v jaké ho uživatel napsal. Stejně spolehlivě se přenášejí i údaje, se kterými dashboard načítá poslední úkoly týmu a komentáře k úkolům.

Projektů, které používají GitHub, GitLab, Forgejo nebo YouTrack, se změna netýká. Jejich chování zůstává stejné.

Closes #701

🤖 Generated with Claude Code

## Summary `LinearClient` put user values (title, description, search text, team id, issue id, cursors) into GraphQL string literals inside a JSON string. That embedding needs two escaping layers; `escapeForJson` gave one, and the search and recent-issues builders gave none. A quote, a backslash or a newline made the GraphQL text or the JSON invalid. ## Defects fixed - **Phase 1** (#764): the five request builders (`buildCreateIssueMutation`, `buildSearchIssuesQuery`, `buildListRecentIssuesQuery`, `buildIssueCommentIdsQuery`, `buildIssueCommentsQuery`) now send a constant GraphQL text with the values in `variables`, written by `ujson.write` through one `graphqlRequest` helper. `escapeForJson` is removed. ## Testing - `LinearClientCreateIssueTest`, `LinearClientMockTest`, `LinearIssueTrackerTest` decode the body and check that each value round-trips exactly in `variables` and that `query` is the constant text. 9 new or rewritten tests failed before the fix. - The manual reproduction program from `analysis.md` prints `GraphQL OK` on all 7 inputs. - **Not verified:** a round trip against a real Linear workspace. It needs a `LINEAR_API_TOKEN`. The variable types come from the published Linear schema. ## Follow-ups Two `LinearClient.scala` items (deprecated `issueSearch`; `buildLinearQuery` still interpolates `IssueId`) are attached to #643. ## Release notes Projekty, které vedou úkoly v Linearu, teď spolehlivě přenesou do Linearu přesně ten text, který uživatel zadal. Dříve stačila v názvu nebo popisu úkolu jediná uvozovka, zpětné lomítko nebo zalomení řádku, a Linear požadavek odmítl. Protože skoro každý delší popis má více řádků, nešlo o okrajový případ, ale o běžnou situaci. Příkaz pro založení nového úkolu nyní projde i s názvem jako „Řekni "ahoj"“, s cestou k souboru obsahující zpětná lomítka nebo s popisem na mnoho řádků. Název i popis dorazí do Linearu znak po znaku tak, jak byly napsány, nic se cestou neztratí ani nezmění. Opravené je i hledání úkolů na dashboardu. Hledaný výraz s uvozovkou dříve způsobil chybu a výraz se zpětným lomítkem se před odesláním tiše pozměnil, takže hledání vracelo jiné výsledky, než uživatel čekal. Teď Linear dostane hledaný výraz přesně v té podobě, v jaké ho uživatel napsal. Stejně spolehlivě se přenášejí i údaje, se kterými dashboard načítá poslední úkoly týmu a komentáře k úkolům. Projektů, které používají GitHub, GitLab, Forgejo nebo YouTrack, se změna netýká. Jejich chování zůstává stejné. Closes #701 🤖 Generated with [Claude Code](https://claude.com/claude-code)
LinearClient.escapeForJson escapes a value only once, so a quote breaks the GraphQL string

Artifacts:
- analysis.md
- issue.md

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuB38s4FzXfyuePZHx32w7
LinearClient.escapeForJson escapes a value only once, so a quote breaks the GraphQL string

Artifacts:
- tasks.md

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuB38s4FzXfyuePZHx32w7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VuB38s4FzXfyuePZHx32w7
Issue: IW-701
Phase: 1 - User values enter Linear GraphQL text with fewer escaping layers than the embedding needs

This commit marks the checkpoint for phase 1 context generation.
Use dx-fix IW-701 to return to this point.

The comment builders from IW-610 share the root cause and are in
scope; analysis.md now says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
User values enter Linear GraphQL text with fewer escaping layers than the embedding needs

Artifacts:
- phase-01-tasks.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chore(IW-701): file follow-ups on #643
All checks were successful
CI / changes (pull_request) Successful in 5s
CI / contract (pull_request) Has been skipped
CI / format (pull_request) Successful in 11s
CI / lint (pull_request) Successful in 11s
CI / compile (pull_request) Successful in 1m33s
CI / dashboard-build (pull_request) Successful in 1m26s
CI / test (pull_request) Successful in 18m20s
08804ff8eb
Both LinearClient.scala items went onto the open issue #643 as one comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mph merged commit 020a78c77a into main 2026-10-08 06:21:32 +00:00
Sign in to join this conversation.
No description provided.