feat(forge): forge state-transition wire arms and provider methods (RIG-3331) - #1017
Open
rigel-mintaka wants to merge 1 commit into
Open
feat(forge): forge state-transition wire arms and provider methods (RIG-3331)#1017rigel-mintaka wants to merge 1 commit into
rigel-mintaka wants to merge 1 commit into
Conversation
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
This was referenced Sep 8, 2026
|
Compass engineering docs preview: https://compass-forge-rig-3331-provi.compass-eng-docs.pages.dev Deployed from |
rigel-mintaka
force-pushed
the
compass-forge/rig-3331-provider
branch
from
September 8, 2026 21:08
daa4e13 to
f47fddd
Compare
rigel-mintaka
marked this pull request as ready for review
September 8, 2026 21:55
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.
This PR is part of a stack containing 5 PRs:
mainImplements T0-T3 of the frozen record
docs/designs/server/compass-forge-state-transition/design.md(Status: Active, merged in #981).What this is
The wire arms and the provider half of the forge state-transition write op: an agent can move an issue or PR between forge states through the same chokepoint every other forge write goes through.
ForgeCallRequestoneof arms 14/15 +TransitionIssueStateRequest/TransitionPullRequestStateRequest, regenerated into both language lanes. The result arms are REUSED: a successful transition returns the updated artifact on the existing.issue/.pull_requestarms, so a caller sees post-transition truth exactly as a create's caller sees the created artifact.TransitionStateinput +Provider.TransitionIssueState/TransitionPullRequestState, landed together with all four implementors. The record is explicit that this is one slice:var _ Provider = ...assertions infake.go,fake_test.go,github.goandlinear.gomean widening the interface alone is red by construction.PATCH /repos/{repo}/issues/{number}and/pulls/{number}, decoded through the existingghIssue/ghPullDetailstructs. The PATCH response IS the updated artifact, so nothing re-reads.issueUpdatewith per-team workflow-state resolution, andErrUnsupportedon the PR method.Two things a reviewer should look at
doJSONwas POST-only. It now takes a method, with the five pre-existing callers passinghttp.MethodPostexplicitly. A sibling helper would have duplicated the gate / token /Accept/ budget / error-mapping body for one changed word. Behaviour for POST callers is unchanged; the one visible delta is the gate error prefix (%s %s, stillPOST <url>for every existing caller).OQ-2's rule is implemented as ruled (2026-09-07): default to the sole candidate state of the target type,
invalid_argumentnaming the candidates when more than one exists. The asymmetry is deliberate — close defaults tocompleted, nevercanceled. No current Rigel team has twocompletedstates, so the multi-candidate rejection fixture is its only coverage; it exists for that reason.Workflow-state resolution uses its OWN TTL cache with invalidate-and-retry-once, not the invalidation-free
teamIDscache. The retry fires only on a GraphQL-level rejection against a CACHED resolution — a rate limit, auth failure or transport fault never burns it.All four rejection paths return
*StatusError{422}, becausemapForgeErrorreaches in-bandinvalid_argumentby exactly that route; a plainfmt.Errorfwould flatten tointernal.Tests
Golden replay (untagged) for both providers: GitHub close-with-reason / close-default / reopen / PR close / PR reopen / 422-on-merged-PR-reopen; Linear close-by-default / close-by-name / reopen-by-default / unknown-name / duplicate-name-in-team / type-contradiction / two-
completed-states. Plus budget-gate, cache-TTL, retry-once and retry-not-on-rate-limit unit tests.The fixture harness gained
WantErrorbecause four Linear arms must FAIL andWantis a decoded domain value. Each rejection fixture asserts a request COUNT, so a rejection that fires before the wire — or after running the mutation — reddens.Verified:
go build -tags unix ./...clean,go test -tags unix ./internal/forge/ok,go vet+gofmtclean.Ledger-impact: none — this PR adds no ledger row. The record's DL-342/DL-343 landed with the freeze in #981.
Review round 1 — resolved
Reviewed by the
reviewagent over the whole stack (high 3, medium 7, low 6).The core RIG-3331 mechanism (memo ordering, one-shot consume, tenant isolation,
provider methods, Linear resolution, error mapping, recorded-state choice) was
verified correct. All three highs were stack-integration regressions, now fixed:
main; every conflict resolved by regenerating (buf+sqlc), never byhand-merging a generated file.
SessionErrorregen (45 -> 0 occurrences). The regen restores it:SessionErroris back to 45 in
go/gen/compass/v1/compass.pb.goand 14 in the agent TS,with
ownerHandleand the transition arms additive on top.approvalOfloop over all twelve tools (3 reads + 9 writes) with its justification comment,
rather than the two-tool assertion that replaced it.
Mediums fixed:
updated_at/created_at+updated_at_tablesentry forforge_state_transitions(main's RIG-3495 convention, which landed after thisbranched) plus a sqlc regen; the single-column FK divergence documented; the
memo coordinate contract documented on
rememberTransition; the memo-failureerror now names the forge write that landed; the Linear retry gate narrowed to
the actual staleness signal; workflow-state page truncation now fails loud at
422; the two transition schemas routed through the
compassv1barrel.Both new provider tests were mutation-proved: widening the retry gate reddens
TestLinearTransitionDoesNotRetryOnNonStaleness200, and removing the truncationguard reddens
TestLinearTransitionRejectsTruncatedWorkflowStatePage.Gate:
moon ci70 actions, 0 failed againstMOON_BASE=origin/main.The initial
forgelive-oracle 401s were mint contention, not a defect: theLinear
client_credentialsapp holds one active token, so five concurrent CIruns each revoked the previous one's (which is why the last-to-mint PR was
green). Re-run serially, the job passes on every head with no code change.