Skip to content

Ask for an invite code in the desktop workspace wizard - #1420

Merged
realtonyyoung merged 4 commits into
mainfrom
ai-3657-desktop-invite-code
Oct 13, 2026
Merged

realtonyyoung merged 4 commits into
mainfrom
ai-3657-desktop-invite-code

Conversation

@realtonyyoung

@realtonyyoung realtonyyoung commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

AI-3657 (no GitHub issue; the work is tracked in Linear)

What & why

When the signup server gates workspace creation (403 invite_required, 400 invalid_code, 409 code_exhausted), the desktop onboarding wizard now asks for an invite code instead of ending the offer, matching the kcap CLI prompt. A wrong or used-up code re-prompts with the reason; three rejected codes, Cancel or a blank code end the offer with the existing invite refusal.

Where to look

  • A 403 answering a code just supplied counts toward the three-code cap, so a server that keeps asking cannot loop the prompt.
  • The server's request link is shown and opened only when LinkPolicy accepts it as a web URL; the entered code is cleared when a run ends.

Verification

  • WizardAuthBridgesTests 38/38, SignInStepViewModelTests 40/40, ReauthCompositionTests 5/5 (class-targeted --treenode-filter runs).
  • dotnet build src/Capacitor.App -c Release: 0 warnings.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Workspace setup can now request an invite code when one is required. You can submit a code, correct it after rejection, or open an available invite-request link.
    • You can make up to three invite-code attempts before workspace setup ends with a failure message.
  • Bug Fixes

    • Provisioning progress is displayed based on whether provisioning is active, even when no progress text is available.

realtonyyoung and others added 2 commits October 13, 2026 14:39
A 403 invite_required answering a code just supplied counts toward the
three-code cap, so a server that keeps asking cannot loop the prompt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The URL is whatever the configured signup server sends, and the opener
launches any scheme it is handed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Oct 13, 2026

Copy link
Copy Markdown

AI-3657

@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: f5f4a99e-448d-4ec2-8f68-3704d7e03df9
📥 Commits

Reviewing files that changed from the base of the PR and between 2e7985b and 18780bf.

📒 Files selected for processing: 7
  • src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs
  • src/Capacitor.App/ViewModels/Onboarding/SignInPhase.cs
  • src/Capacitor.App/ViewModels/Onboarding/SignInStepViewModel.cs
  • src/Capacitor.App/Views/Onboarding/SignInPaneView.axaml
  • src/Capacitor.App/Views/Onboarding/SignInStepView.axaml
  • test/Capacitor.App.Tests.Unit/SignInStepViewModelTests.cs
  • test/Capacitor.App.Tests.Unit/WizardAuthBridgesTests.cs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Workspace provisioning can now request an invite code, retry rejected codes up to three times, and report invite-related refusals. The sign-in wizard provides the code prompt, optional request link, and related error and cancellation handling.

Changes: Invite-gated workspace creation

Layer / File(s) Summary
Provisioning invite-code retries
src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs, test/Capacitor.App.Tests.Unit/WizardAuthBridgesTests.cs
The provisioner prompts for trimmed codes, retries invite-related responses, and stops when no code is supplied or three codes are rejected. It retains the latest nonempty request URL and includes it in refusal messages only when LinkPolicy.IsOpenable accepts it. Tests cover retries, refusal reasons, URLs, and telemetry.
Sign-in wizard invite prompt
src/Capacitor.App/ViewModels/Onboarding/SignInPhase.cs, src/Capacitor.App/ViewModels/Onboarding/SignInStepViewModel.cs, src/Capacitor.App/Views/Onboarding/SignInPaneView.axaml, src/Capacitor.App/Views/Onboarding/SignInStepView.axaml, test/Capacitor.App.Tests.Unit/SignInStepViewModelTests.cs
The sign-in wizard collects and submits codes, preserves a rejected code for correction, and filters request links with LinkPolicy.IsOpenable. It displays prompt errors and provides cancellation and cleanup handling. Tests cover the prompt flow, navigation, URL filtering, and rendering.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant SignInStepViewModel
  participant WizardTenantProvisioner
  participant ProvisioningServer
  WizardTenantProvisioner->>ProvisioningServer: Submit workspace request
  ProvisioningServer-->>WizardTenantProvisioner: Return invite-related response
  WizardTenantProvisioner->>SignInStepViewModel: Request invite code
  SignInStepViewModel->>User: Show invite-code prompt
  User-->>SignInStepViewModel: Submit or cancel code
  SignInStepViewModel-->>WizardTenantProvisioner: Return code or null
  WizardTenantProvisioner->>ProvisioningServer: Retry workspace request with code
Loading

Suggested reviewers: nortonandreev

Merge Risk: ⚪ Minimal · up to 18780

No demonstrated issue remains that would prevent merging after normal checks.

Security architecture risk: 🔵 Low · up to 18780

Invite retries are bounded and preserve existing authentication and web-only link controls. No new security defect was established. Remaining uncertainty concerns how the signup service handles rejected or interrupted creation requests.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The directly evidenced scope is an authenticated user's workspace-creation offer and a user-activated browser destination. The rejection cap limits one offer, not repeated runs or direct service requests; tenant-wide authorization and service-wide abuse limits remain server responsibilities not established by this client evidence.

Trust Boundaries and Controls

  • observed — The new server-controlled link consumer preserves the existing absolute HTTP/HTTPS scheme boundary. A file URL is tested as neither displayed nor opened. Arbitrary web hosts and HTTP remain permitted; this policy prevents privileged URI schemes but does not authenticate destination trustworthiness.

Resilience and Maintainability Implications

  • observed — The unchanged provisioning client collapses request cancellation into transport failure, potentially obscuring whether remote creation completed. The new invite loop does not retry that outcome, so an introduced automatic duplicate-creation path was not established. Lost-response ownership recovery remains unverified.

Hardening Proposals

  • proposed — Document and verify that invite refusals have no creation or redemption side effects, that successful redemption is atomic with the intended ownership transition, and that interrupted creation has an authenticated recovery path. Do not rely on the optional telemetry correlation field as an idempotency guarantee without an explicit server contract.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 16.22% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 37 functions across 5 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding invite-code requests to the desktop workspace wizard.
Full details: Docstring Coverage

Explanation

Docstring coverage is 16.22% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 37 functions across 5 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Prompt for invite codes during desktop workspace creation

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Prompt for an invite code when the signup server gates workspace creation, rather than ending the
 offer.
• Explain rejected codes and allow retries, capped at three rejected codes.
• Show only safe web request links and clear entered codes when a run ends.
Diagram

graph TD
  C["Create confirmed"] --> P["Tenant provisioner"] --> A["Signup service"] --> G{"Invite gate?"}
  G -- "invite needed" --> R{"Attempts left?"} -- "retry" --> I["Invite prompt"] --> P
  R -- "limit or cancel" --> F["Offer refused"]
  G -- "created" --> S["Workspace created"]
Loading
High-Level Assessment

Keep invite handling in the existing tenant provisioner and expose the prompt through its UI hook. This preserves provisioning outcomes and the wizard’s established prompt and cancellation pattern without introducing a separate signup flow.

Files changed (7) +506 / -41

Enhancement (5) +174 / -38
WizardAuthBridges.csRetry invite-gated provisioning with a bounded code prompt +54/-29

Retry invite-gated provisioning with a bounded code prompt

• Adds an invite-code prompt hook and resubmits provisioning requests with trimmed codes. Explains rejected codes, counts a 403 response to a supplied code toward the three-rejection limit, and retains the refusal outcome when no code is provided.

src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs

SignInPhase.csAdd an invite-code sign-in phase +1/-1

Add an invite-code sign-in phase

• Defines a distinct phase for the invite prompt so the wizard can show its own headline and panel.

src/Capacitor.App/ViewModels/Onboarding/SignInPhase.cs

SignInStepViewModel.csConnect invite-code prompts to wizard state and commands +57/-7

Connect invite-code prompts to wizard state and commands

• Adds code entry, rejection feedback, submission, cancellation, and phase state. Filters server-supplied request links through LinkPolicy before offering or opening them, and clears the entered code when a run ends.

src/Capacitor.App/ViewModels/Onboarding/SignInStepViewModel.cs

SignInPaneView.axamlAdd the invite-code card to the onboarding pane +26/-0

Add the invite-code card to the onboarding pane

• Displays code entry, rejection feedback, an optional invite-request link, and Continue and Cancel actions.

src/Capacitor.App/Views/Onboarding/SignInPaneView.axaml

SignInStepView.axamlRender the invite prompt in the sign-in step +36/-1

Render the invite prompt in the sign-in step

• Adds the invite-code controls and optional request link to the sign-in step. Hides provisioning text while the invite prompt is active.

src/Capacitor.App/Views/Onboarding/SignInStepView.axaml

Tests (2) +332 / -3
SignInStepViewModelTests.csCover invite prompting and rendering in the desktop wizard +195/-0

Cover invite prompting and rendering in the desktop wizard

• Tests retry feedback, successful submission, cancellation, link filtering, navigation cleanup, and pane visibility.

test/Capacitor.App.Tests.Unit/SignInStepViewModelTests.cs

WizardAuthBridgesTests.csCover invite-code provisioning outcomes and retry limits +137/-3

Cover invite-code provisioning outcomes and retry limits

• Tests trimmed code submission, blank or missing answers, rejection messages, the three-code limit, repeated invite-required responses, and reported failure reasons.

test/Capacitor.App.Tests.Unit/WizardAuthBridgesTests.cs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@qodo-code-review

qodo-code-review Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. The invite prompt comment is unclear ✓ Resolved
Description
The XML comment above PromptInviteCode says “Asked with where to request an invite” and does not
clearly describe what the delegate receives or returns. A later maintainer cannot reliably infer the
request URL, prior rejection message, and entered-code response contract from this documentation.
Code

src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[R126-127]

+    /// Asked with where to request an invite and the complaint about the last code, if any.
+    public Func<string?, string?, CancellationToken, Task<string?>>? PromptInviteCode { get; set; }
Relevance

●●● Strong

Recent app precedents accept rewriting redundant or unclear comments to preserve behavior-critical
documentation.

PR-#1328
PR-#1063

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added XML comment is difficult to understand and does not clearly document the delegate
contract, contrary to the requirement that comments be understandable from the current file and
document useful behavior-critical information.

Rule 2762993: Restrict comments to documenting non-obvious, behavior‑critical constraints
src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[126-127]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The XML comment for `PromptInviteCode` is grammatically unclear and does not accurately explain the delegate's inputs and result.

## Fix Focus Areas
- src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[126-127]

## Recommended Fix
Rewrite the comment to state that the delegate receives the server's optional request URL and the optional reason the previous code was rejected, then returns the next invite code or null when the user cancels or submits no code.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Commits omit required issue suffix ✗ Dismissed
Description
Both commit subjects, Ask for an invite code in the desktop workspace wizard and `Open the invite
request link only when it is a web URL, lack the required trailing (#<digits>)` reference. The
subjects therefore fail the repository's single-clause commit format even though their wording is
imperative and concise.
Code

src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[115]

+    internal const int MaxInviteCodeAttempts = 3;
Relevance

●●● Strong

Repository guidance explicitly requires issue-referenced commit subjects; the commits violate that
format.

PR-#659

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The supplied commit subjects do not end with (#<digits>), which violates the required
commit-subject format.

Rule 2897961: Enforce single-clause imperative commit subject with GitHub issue reference and 80-char limit

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The commit subjects do not end with a GitHub issue reference in the required `(#<digits>)` format.

## Fix Focus Areas
- src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[115-115]

## Recommended Fix
Rename each commit subject to one imperative clause followed by exactly one space and an explicit GitHub issue reference, such as `Ask for an invite code (#1234)`, keeping each subject at or below 80 characters.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Invite link vanishes after a rejected code ✓ Resolved
Description
OfferCreateCoreAsync replaces requestUrl with the value from every rejection, and the prompt
assigns InviteRequestUrl to null when that value is absent. If the initial gate supplies a link
but an invalid_code or code_exhausted response omits it, the retry prompt hides the request link
and the eventual refusal also omits it.
Code

src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[196]

+                    var requestUrl   = outcome.Body.RequestUrl;
Relevance

●●● Strong

The optional retry URL can erase a valid initial link, matching accepted precedents for preserving
dropped context.

PR-#638
PR-#608

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The response model makes RequestUrl optional, and the new test exercises an initial gate with a
URL followed by invalid_code without one. The changed provisioner forwards that absent value; the
view model clears its URL, and both views hide their request-link sections when it is empty.

src/Capacitor.Cli.Core/Auth/ProvisioningModels.cs[30-38]
test/Capacitor.App.Tests.Unit/SignInStepViewModelTests.cs[706-719]
src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[192-207]
src/Capacitor.App/ViewModels/Onboarding/SignInStepViewModel.cs[177-184]
src/Capacitor.App/Views/Onboarding/SignInPaneView.axaml[225-229]
src/Capacitor.App/Views/Onboarding/SignInStepView.axaml[269-275]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A rejection without `requestUrl` discards a valid link supplied by the initial invite gate, leaving the retry prompt and final refusal without it.

## Fix Focus Areas
- src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[192-207]
- src/Capacitor.App/ViewModels/Onboarding/SignInStepViewModel.cs[177-184]
- src/Capacitor.App/ViewModels/Onboarding/SignInStepViewModel.cs[815-818]

## Recommended Fix
Retain the last supplied invite-request URL for the current provisioning offer when a later response omits it, and use that URL for subsequent prompts and the final refusal. Keep the existing web-URL validation before displaying or opening it, and clear the view-model URL when the run ends.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (1)
4. PR references lack GitHub closure ✗ Dismissed
Description
The PR description begins with AI-3657 (no GitHub issue; the work is tracked in Linear) and never
provides a single reference line containing a GitHub closing keyword and issue number. Reviewers
cannot identify a GitHub issue that this change closes or resolves from the PR description.
Code

src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[R126-127]

+    /// Asked with where to request an invite and the complaint about the last code, if any.
+    public Func<string?, string?, CancellationToken, Task<string?>>? PromptInviteCode { get; set; }
Relevance

●● Moderate

The rule favors GitHub closure references, but precedent allows explicitly stating when a GitHub
issue does not exist.

PR-#659

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The supplied PR description identifies AI-3657 but explicitly says there is no GitHub issue and
contains no Closes, Fixes, or Resolves reference with a GitHub issue number.

Rule 2897991: PR description must contain both GitHub and Linear issue references; PR title must not contain issue IDs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR description contains a Linear issue key but no single reference line combining a GitHub closing keyword, GitHub issue number, and Linear issue key.

## Fix Focus Areas
- src/Capacitor.App/Services/Onboarding/WizardAuthBridges.cs[126-127]

## Recommended Fix
Add a dedicated first-line reference such as `Closes #1234 AI-3657` when a linked GitHub issue exists; otherwise create or link the appropriate GitHub issue before updating the PR description.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 64 rules
✅ Cross-repo context — repo relationships
  Explored: repo: kurrent-io/kcap-web (sha: fdd4af3c) — View relationship
Review mode: Auto: 🧠 Deep: Substantial onboarding logic spans provisioning, view models, UI, and concurrency-sensitive tests.

Grey Divider

Tip of the day
💡 Did you know, you can turn these tips off under Display > Comment parts

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@realtonyyoung
realtonyyoung merged commit 839232a into main Oct 13, 2026
9 checks passed
@realtonyyoung
realtonyyoung deleted the ai-3657-desktop-invite-code branch October 13, 2026 19:54
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.

1 participant