Conversation
A label-scoped Linear connection was unusable. Two independent faults:
1. The scope value went straight into `labels: { id: { in: [...] } }`, so
a human-written value such as `requester:yosi` made Linear reject
*every* issue query with "Argument Validation Error: each value in in
must be a UUID". Scope values are now resolved: UUIDs pass through
untouched, anything else is looked up as a label name against a
per-API-key directory (paginated, cached, re-read once before a name
is declared unknown, evicted on failure). An unresolvable value fails
with a message naming the value and the fix.
2. `cycle`, `cycles`, `user` and `users` were blocked outright for scoped
connections, so a scoped agent could not answer "what is assigned to
me this cycle" at all — it bypassed the plugin and called Linear's
GraphQL API directly. The scope restricts issue *content*; these are
workspace metadata, like teams, states and labels, which were never
blocked. Reads are allowed; cycle/user writes stay blocked, as do
comments, attachments, projects, views, initiatives and webhooks.
The scope helpers became async as a result; call sites in issues.ts and
views.ts follow.
Descriptions are the entire disclosure surface: Vex's system prompt lists
only plugin and action *names*, so a description is all an agent sees when
it picks between neighbours in `actions.find` or the catalog.
- Every action a scoped connection cannot run now ends with "Unavailable
on scoped connections." Previously only attachment.list and comment.list
said so, and the other ~35 failed only at call time - a wasted turn each,
and the exact trap that drove an agent off this plugin in SHFT-1644. The
note is derived from the block set for list/get actions, so the copy
cannot drift from the behaviour, and a new test asserts the invariant in
both directions across all 90 actions.
- team.members is no longer blocked under scope. It is the same people
surface as user.list, narrowed to one team.
- issue.list documents its convenience filters and the assignee/cycle/open
filter shapes; cycle.list documents `{ isActive: { eq: true } }`. Those
two are the "what is assigned to me this cycle" path.
- issue.listComments points at comment.list, which subsumes it; user.me
says what it is for; issue.get gets its missing period.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A label-scoped Linear connection was unusable for an agent. Two independent faults, both in the
linearplugin's scope layer.1. A non-UUID scope value broke every issue query
The configured value went straight into
labels: { id: { in: [...] } }, so a human-writtenLINEAR_SCOPE_LABEL_IDS=requester:yosimade Linear reject every issue query withArgument Validation Error: each value in in must be a UUID.Scope values are now resolved before use:
2. Cycles and users were blocked outright
cycle,cycles,useranduserswere inSCOPED_BLOCKED_ROOT_FIELDS, so a scoped agent could not answer "what is assigned to me this cycle" at all — it bypassed the plugin and called Linear's GraphQL API directly with the same key, defeating the scope entirely.The scope restricts issue content. Cycles and users are workspace metadata, like teams, states and labels, which were never blocked. So:
cycle.list/get,user.list/getcycle.create/update/archive,team.cyclesDeleteAll,user.update, and every previously blocked surface — comments, attachments, projects, milestones, project updates, views, initiatives, webhooks,org.getThe scope helpers became async as a result; call sites in
issues.tsandviews.tsfollow.Tests
Linear suite 37 → 48 tests, covering name resolution, cache reuse, the UUID fast path, the actionable unknown-label error, recovery when a label is created after the directory was cached, and the cycle/user read-vs-write split.
bun run testat the repo root: 497 pass, 0 fail. Biome clean;tsc --noEmitreports no errors underlinear/.