Skip to content

REG-1909 Foundation 1 - #3619

Open
sirdodger wants to merge 12 commits into
clee/preview-error-fixfrom
clee/preview-foundation
Open

REG-1909 Foundation 1#3619
sirdodger wants to merge 12 commits into
clee/preview-error-fixfrom
clee/preview-foundation

Conversation

@sirdodger

@sirdodger sirdodger commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

REG-1909 Foundation 1

Foundation PR for the upcoming rover contract preview and rover subgraph preview commands (two independent stacks, both rooted on this branch: REG-1909 Subgraph Preview 2a/3a, REG-1909 Contract Preview 2b/3b). Stacked on REG-1909 Error Fix 0, an unrelated bug fix that was split out of this PR at review request. (original large PR, for posterity and PR feedback comments.)

  • crates/rover-client/src/shared/async_build_response.rs: AsyncBuildStatus, PreviewJobResponse — the async build-status/response shapes shared by both preview commands.
  • crates/rover-client/src/shared/filter_config.rs: ContractFilterConfig — the include/exclude/hide-unreachable-types filter shared by both commands.
  • crates/rover-client/src/shared/preview_poll.rs: require_variant/poll_preview_build, the generic async-preview polling helper built on the existing check-workflow poller (shared/check_workflow_poll.rs).
  • crates/rover-client/.schema/schema.graphql: schema additions for the new async preview mutations/queries.

Nothing in this crate calls the new preview_poll helpers yet — the contract-preview and subgraph-preview operations that consume them land in the two stacks above.

Test plan

  • cargo test -p rover-client
  • cargo clippy --locked --workspace --all-features --all-targets
  • cargo +nightly fmt --all -- --check

[x] A CHANGELOG.md entry is not needed for this PR

@sirdodger
sirdodger requested a review from a team as a code owner August 20, 2026 19:23
@apollo-librarian

apollo-librarian Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

✅ Docs preview has no changes

The preview was not built because there were no changes.

Build ID: c87a6ea9770631888740796a
Build Logs: View logs


✅ AI Style Review — No Changes Detected

No MDX files were changed in this pull request.

Review Log: View detailed log

This review is AI-generated. Please use common sense when accepting these suggestions, as they may not always be accurate or appropriate for your specific context.

@sirdodger sirdodger changed the title clee/preview foundation Add shared async-preview-job plumbing (foundation) Aug 20, 2026
@sirdodger sirdodger changed the title Add shared async-preview-job plumbing (foundation) REG-1909 Foundation 1 Aug 20, 2026
@sirdodger
sirdodger force-pushed the clee/preview-foundation branch from 1a3f6d4 to 1fcaa86 Compare August 20, 2026 20:36
@sirdodger
sirdodger changed the base branch from main to clee/preview-error-fix August 20, 2026 20:38
Comment thread crates/rover-client/src/shared/async_build_response.rs Outdated
Comment thread crates/rover-client/src/shared/preview_poll.rs Outdated
Comment thread crates/rover-client/src/shared/check_workflow_poll.rs
Comment thread crates/rover-client/src/shared/preview_poll.rs Outdated
Comment thread crates/rover-client/src/shared/preview_poll.rs Outdated
Comment thread crates/rover-client/src/shared/preview_poll.rs
@claude

claude Bot commented Aug 24, 2026

Copy link
Copy Markdown

Code review

Two findings.

1. Shallow assertion discards the field the function under test threads through

crates/rover-client/src/shared/preview_poll.rs#L36-L41

assert_that!(matches!(err, RoverClientError::GraphNotFound ..)).is_true() collapses the error to a boolean variant check and drops graph_ref — the one thing require_variant actually threads through. The test constructs a specific test-graph@test-variant ref, but would still pass if the implementation dropped it, defaulted it, or substituted a different ref.

CLAUDE.md → Testing Conventions:

When asserting with speculoos's assert_that!, assert on the full object or the full string (.is_equal_to(...) against a complete expected value), not just .is_ok()/.is_some()/.contains(...). A shallow assertion (result is Ok, string contains a substring) passes even when the rest of the value silently regresses

The sibling test just above (L28-L35) already uses the full-value form. Suggested replacement for line 40:

let RoverClientError::GraphNotFound {
    graph_ref: actual_graph_ref,
} = err
else {
    panic!("expected RoverClientError::GraphNotFound");
};
assert_that!(&actual_graph_ref).is_equal_to(&graph_ref);

2. No linked planning artifact in the PR description

The description references the ticket as a bare string (REG-1909) and links to the original large PR #3522, but a PR link is not an issue reference and the bare ticket ID is not a link to a planning doc. Per CLAUDE.md → Planning Prerequisites:

When reviewing a PR, check the description for a linked Confluence PRD/One-Pager or a referenced GitHub issue (e.g. Fixes followed by an issue number). Flag the PR if neither is present, unless the change is clearly trivial.

This adds new shared abstractions, new error variants, new schema types, and a new generic Tower retry policy, so it is not trivial. Adding the Confluence PRD/One-Pager URL for REG-1909 to the description closes this out.


Checked and clean: PollRetryPolicy deadline/retry semantics and the in-place Err rewrite on timeout, AsyncBuildStatus serde/Display agreement and is_terminal, the new RoverClientError variants wired into RoverErrorMetadata, schema additions (no duplicate type definitions, all union members resolve), and rover-tower dependency/feature wiring.

Posted as a top-level comment rather than an inline review comment — the inline-comment API was unavailable in this environment. Apologies for the placeholder text previously in this comment.

@sirdodger
sirdodger force-pushed the clee/preview-foundation branch 2 times, most recently from e4fdc9f to b3c5e0f Compare August 25, 2026 06:55
Comment thread crates/rover-tower/src/attempt_timeout.rs Outdated
Comment thread crates/rover-tower/src/poll_retry.rs Outdated
@sirdodger
sirdodger force-pushed the clee/preview-foundation branch from 5a2c7c1 to c56b684 Compare August 25, 2026 21:15
Comment thread crates/rover-tower/src/poll_retry.rs Outdated
Comment thread crates/rover-tower/src/poll_retry.rs Outdated
Comment thread crates/rover-tower/src/poll_retry.rs Outdated
@sirdodger
sirdodger force-pushed the clee/preview-foundation branch from f24c713 to 64b041b Compare August 27, 2026 19:15
…onse, filter_config)

Foundation types/functions for the upcoming `rover contract preview` and
`rover subgraph preview` commands: the async build-status/response shapes,
the shared filter-config type, and the generic async-preview polling helper
built on the existing check-workflow poller.

Nothing in this crate calls the new preview_poll helpers yet -- the
contract-preview and subgraph-preview operations that consume them land in
follow-up PRs stacked on this one.

Stacked on the error.rs NoData fix (split out per review request).
Replaces the hand-rolled poll loop (poll_preview_build/map_preview_errors)
with a tower::retry::Policy: polling is just a retry whose retry condition
is "not finished yet" instead of "the call failed". Wraps the same
tower::retry::Retry/ServiceBuilder::retry(...) machinery normal per-request
retries use, rather than a bespoke poll-loop or timeout-racing type.

PollRetryPolicy owns both the poll cadence and the give-up-after-timeout
decision: tower::retry::Policy::retry() gets a &mut Result, so on timeout
it rewrites an in-flight "not finished" Ok into the caller-supplied
timeout Err before telling Retry to stop, rather than needing a separate
outer timeout layer that would just race and drop the poll loop (losing
that rewrite opportunity).

No normal-call retry policy (e.g. for RoverClientError::is_transient()) is
needed here: RateLimitExceeded is structurally unreachable from the
preview status/result queries (it only appears in the check-submission
mutation's response union), and SendRequest is already retried by the
RetryLayer wrapped into studio_graphql_service() before it ever surfaces
as a RoverClientError.

require_variant is unchanged and still unused in this PR (foundation) --
the contract/subgraph preview operations stacked on top wire
PollRetryPolicy in and start calling it.
Mirrors the existing WHOAMI_ATTEMPT_TIMEOUT/CLIENT_CREDENTIALS_ATTEMPT_TIMEOUT
layering (an inner per-attempt TimeoutLayer under an outer RetryLayer, so
one hung attempt can't consume the whole retry budget) -- generalized so
the give-up-on-this-attempt outcome is a caller-supplied fallback response
rather than an error, since it needs to compose underneath
PollRetryPolicy as just another "not finished yet" result instead of
aborting the poll early.
This file belongs to the contract-impl PR (which already has its own,
correctly-worded copy) -- it got swept into this branch's earlier fmt
commit by mistake and doesn't belong on the foundation PR at all
(operations::contract doesn't even declare a preview submodule here).

Also fixes a doc-comment typo and a trailing-whitespace fmt nit that came
along with the same commit.
Per-call resilience belongs in each operation's own retry/timeout
composition, not a bespoke attempt-timeout layer bolted onto the poll
retry policy. PollRetryPolicy's Err(_) => None already treats any
error from the wrapped service as terminal, so no changes are needed
there.
A bare bool return from a status-check service isn't self-documenting
at the call site -- true/false carries no semantic meaning. Callers
that don't need more than done/not-done now use SimplePollOutcome
instead.
The trait was still narrowing every implementor's status down to a
bare bool at the boundary, throwing away the enum's self-documenting
meaning right where it mattered most: the actual poll-retry decision
in PollRetryPolicy::retry. The enum now flows through the whole
chain -- callers implement poll_outcome() -> SimplePollOutcome instead
of is_finished() -> bool.
@sirdodger
sirdodger force-pushed the clee/preview-foundation branch from 64b041b to 4e71956 Compare September 1, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants