Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1308,8 +1308,9 @@ jobs:
src=internal/forge/livegithub_test.go
ghskip=$(sed -n 's/.*liveSkipMessage = "\(.*\)"/\1/p' "$src")
lnskip=$(sed -n 's/.*liveLinearSkipMessage = "\(.*\)"/\1/p' "$src")
if [ -z "$ghskip" ] || [ -z "$lnskip" ]; then
echo "::error::could not read the skip messages out of $src (github='$ghskip' linear='$lnskip') — this guard has drifted from the harness and is no longer checking anything"
boardskip=$(sed -n 's/.*liveBoardStateSkipPrefix = "\(.*\)"/\1/p' "$src")
if [ -z "$ghskip" ] || [ -z "$lnskip" ] || [ -z "$boardskip" ]; then
echo "::error::could not read the skip messages out of $src (github='$ghskip' linear='$lnskip' board='$boardskip') — this guard has drifted from the harness and is no longer checking anything"
exit 1
fi
if grep -qF "$ghskip" /tmp/forge-oracle.log; then
Expand All @@ -1322,6 +1323,13 @@ jobs:
grep -nF "$lnskip" /tmp/forge-oracle.log | head
exit 1
fi
# A board-state skip leaves the package reporting ok, so only an
# explicit grep keeps the by-name contracts from silently vanishing.
if grep -qF "$boardskip" /tmp/forge-oracle.log; then
echo "::error::forge live-contract oracle skipped a by-name transition leg — the testbed team's board lacks a needed workflow-state type, so that contract was not asserted"
grep -nF "$boardskip" /tmp/forge-oracle.log | head
exit 1
fi
if ! grep -qE "^ok[[:space:]]+github\.com/RigelBuild/compass/go/internal/forge[[:space:]]" /tmp/forge-oracle.log; then
echo "::error::the forge live-contract package did not report ok — it failed, skipped, or never ran"
exit 1
Expand Down
5 changes: 4 additions & 1 deletion go/internal/forge/linear.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,10 @@ type workflowStateCacheEntry struct {
// workflowStatesQuery is the team workflow-state selection, built once so the
// page cap has ONE source (workflowStatePageCap) shared by the query and the
// truncation guard below rather than a literal repeated in both.
var workflowStatesQuery = fmt.Sprintf(`query CompassTeamWorkflowStates($team: String!) {
//
// $team is ID, not String: it lands in an IDComparator (`id: {eq:}`), and Linear
// rejects a String! variable in that position outright (http 400).
var workflowStatesQuery = fmt.Sprintf(`query CompassTeamWorkflowStates($team: ID!) {
workflowStates(filter: {team: {id: {eq: $team}}}, first: %d) {
nodes { id name type }
}
Expand Down
16 changes: 16 additions & 0 deletions go/internal/forge/linear_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,3 +1057,19 @@ func TestLinearTransitionPullRequestStateUnsupported(t *testing.T) {
t.Fatalf("err = %v, want ErrUnsupported", err)
}
}

// TestLinearIDFilterVariablesAreDeclaredID pins the GraphQL declared TYPE of
// every variable that lands in an id comparator. Linear rejects a String!
// variable in an ID position with an http 400 the fixtures cannot show: a
// golden replay answers our own request, so a malformed query replays green
// forever. Only the live oracle caught it, and only this pins it.
func TestLinearIDFilterVariablesAreDeclaredID(t *testing.T) {
t.Parallel()

if !strings.Contains(workflowStatesQuery, "$team: ID!") {
t.Errorf("workflowStatesQuery must declare $team as ID! (it filters on team.id.eq); got:\n%s", workflowStatesQuery)
}
if strings.Contains(workflowStatesQuery, "$team: String") {
t.Errorf("workflowStatesQuery declares $team as String, which Linear rejects in an id comparator; got:\n%s", workflowStatesQuery)
}
}
Loading
Loading