feat(forge): Linear provider (read + write, issues half) (RIG-2170) - #400
Merged
Conversation
|
Compass engineering docs preview: https://compass-server-rig-2209-line.compass-eng-docs.pages.dev Deployed from |
Add go/internal/forge/linear.go: a hand-rolled net/http GraphQL client for Linear, a co-equal forge write target beside GitHub, per the frozen write-path design §5. Stdlib-only (no go-github/GraphQL library), mirroring github.go's posture and sharing its seams: a TokenSource for LINEAR_FORGE_TOKEN (DL-052), a mu-guarded fail-fast rate gate, and an injectable clock. Linear is issues-only (DL-051): CreateIssue/CommentOnIssue/GetIssue/ListIssues implement the issues half; the PR/review family (CreatePullRequest, CommentOnPullRequest, SubmitReview, GetPullRequest, Checks) returns ErrUnsupported. repo is the Linear team key, resolved to a team UUID once and cached. Attribution (design §5, OQ-5/OQ-8): writes set Linear's createAsUser/displayIconUrl to one constant shared Compass app identity, gated by a one-time actor-capability probe (viewer.app); a non-actor token degrades to stamp-only and emits the named log line. The fine-grained per-agent owner truth rides the Service's StampOwner header unchanged. Rate limits map a 429 or a GraphQL RATELIMITED code to ErrBudgetExhausted with the reset instant from Retry-After / X-RateLimit-Requests-Reset; a GraphQL AUTHENTICATION_ERROR or HTTP 401 invalidates the token. 17 hermetic tests over a stubbed RoundTripper cover request goldens, team-cache, read mapping/filter/pagination, ErrUnsupported, the rate/auth/degrade paths. Refs RIG-2209. Co-authored-by: Matt Wilkinson <matt@sealedsecurity.com>
mattwilkinsonn
force-pushed
the
compass-server-rig-2209-linear-provider
branch
from
August 19, 2026 03:06
26370de to
b8a25e8
Compare
…e (RIG-2209 review) Review M1: actorAttribution cached a TRANSIENT probe failure (a network blip, HTTP 5xx, or an already-armed rate gate) as a permanent not-capable, poisoning attribution to stamp-only for the whole process even after the token/budget recovered. The probe is meant to reflect the token's nature, not runtime state — so only cache an authoritative answer (probeErr == nil); a transient error degrades this one write and re-probes on the next. Review M2/L2: add success-path budget-gate coverage (a 200 whose X-Ratelimit-Requests-Remaining equals the reserve arms the gate; above-reserve leaves it open) and both untested rateLimitReset branches (Retry-After HTTP-date, and the X-Ratelimit-Requests-Reset epoch-ms fallback). Review L1: ListIssues could loop forever if Linear ever returned hasNextPage=true with an empty endCursor (advancing on an empty cursor drops the after variable and refetches page 1); terminate on a malformed page instead. New M1 regression test is red-green verified (fails against the permanent-cache behavior, passes with the fix). All four gates green (gofmt/vet/-race/lint); 21 Linear tests pass race-clean. Refs RIG-2209. Co-authored-by: Matt Wilkinson <matt@sealedsecurity.com>
mattwilkinsonn
approved these changes
Aug 19, 2026
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.
Add go/internal/forge/linear.go: a hand-rolled net/http GraphQL client for Linear, a co-equal forge write target beside GitHub, per the frozen write-path design §5. Stdlib-only (no go-github/GraphQL library), mirroring github.go's posture and sharing its seams: a TokenSource for LINEAR_FORGE_TOKEN (DL-052), a mu-guarded fail-fast rate gate, and an injectable clock.
Linear is issues-only (DL-051): CreateIssue/CommentOnIssue/GetIssue/ListIssues implement the issues half; the PR/review family (CreatePullRequest, CommentOnPullRequest, SubmitReview, GetPullRequest, Checks) returns ErrUnsupported. repo is the Linear team key, resolved to a team UUID once and cached.
Attribution (design §5, OQ-5/OQ-8): writes set Linear's createAsUser/displayIconUrl to one constant shared Compass app identity, gated by a one-time actor-capability probe (viewer.app); a non-actor token degrades to stamp-only and emits the named log line. The fine-grained per-agent owner truth rides the Service's StampOwner header unchanged.
Rate limits map a 429 or a GraphQL RATELIMITED code to ErrBudgetExhausted with the reset instant from Retry-After / X-RateLimit-Requests-Reset; a GraphQL AUTHENTICATION_ERROR or HTTP 401 invalidates the token. 17 hermetic tests over a stubbed RoundTripper cover request goldens, team-cache, read mapping/filter/pagination, ErrUnsupported, the rate/auth/degrade paths.
Refs RIG-2209.
Co-authored-by: Matt Wilkinson matt@sealedsecurity.com