Skip to content

Linear GraphQL/CLI hardening: non-retryable retries, missing connection precheck, duplicated plumbing, and headless as-any casts #470

@arul28

Description

@arul28

Summary: With the now user-facing ade linear graphql (PR #451), a malformed query is retried 4× and a disconnected project surfaces a raw exception; the GraphQL/card-publish plumbing is also implemented redundantly three divergent ways, and the headless Linear bootstrap uses as-any/as-never casts that erase compile-time safety. Related to the Linear-CLI expansion (ADE-65).

Runtime bugs:

  • GraphQL request retries non-retryable validation errors up to maxRetries (4 round-trips, ~3.5s wasted, burns quota). The retry guard gates on (isRateLimited || res.status>=500) but the validation throw is caught by the broad catch that sleeps+retries. linearClient.ts:267,:273,:279; cli.ts:8868. Fix: tag the throw {retryable:false} and rethrow immediately; only retry on network/abort/5xx/429.
  • graphql action runs with no connection-status precheck, so a disconnected project throws the raw 'Linear token missing…', indistinguishable from 'bad query'. registry.ts:2476; linearClient.ts:223; headlessLinearServices.ts:1350. Fix: call buildRuntimeLinearConnectionStatus(runtime) first and throw a typed 'not connected' error.

Duplicated plumbing:

  • publishLinearChatLink card-publish/dedup duplicated across main.ts and bootstrap.ts. bootstrap.ts:439; main.ts:1795; linearLaneCardService.ts — extract createLinearChatLinkPublisher(…).
  • GraphQL argument validation duplicated three times with divergent rules/messages (cli.ts no clamp; registry.ts clamps 0..10; TUI ignores maxRetries). cli.ts:2075,:2104; registry.ts:2534; tuiClient/linearCommands.ts:168 — one shared parseLinearGraphQLInput(raw).
  • Redundant runGraphQL action: duplicate override + allowlist entry no caller dispatches (all callers use graphql). registry.ts:2475,:2479,:600,:612 — delete it; update registry.test.ts:390,403.

Headless casts & cli.ts monolith:

  • createHeadlessLinearServices wires real desktop services through as-any/as-never casts, so a new required method isn't caught at compile time (the dispatcher cast is what let the stub-binding defect ship). headlessLinearServices.ts:1739,:1746,:1782,:1812,:1816,:1843 — type stubs against real interfaces + satisfies Partial<X>.
  • cli.ts is a 14,235-line monolith (~245 top-level functions, 34 buildXxxPlan) that PR Expose Linear GraphQL through ADE CLI #451 added Linear helpers to. cli.ts:9431,:8720,:1 — split each builder into commands/<domain>.ts.

Verification confidence: High on the retry bug and all dedup/count claims; medium on the precheck UX and the casts (runtime-only risk).

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions