Skip to content

fix(builderlab): refresh capabilities at feature gates - #3003

Draft
jsibbison-square wants to merge 6 commits into
mainfrom
jsib-261108-builderlab-capabilities
Draft

jsibbison-square wants to merge 6 commits into
mainfrom
jsib-261108-builderlab-capabilities

Conversation

@jsibbison-square

@jsibbison-square jsibbison-square commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Why

  • Builderlab permissions stayed at their sign-in values until another login.

Key changes

  • Refresh only the three /auth/me capability flags at existing remote-agent, Decisions, and community-deletion gates.
  • Share one in-flight request and a one-minute cache per sign-in, including failed attempts. Keep previous permissions on HTTP, network, or parsing failures.
  • Preserve credential identity, app viewers, and the subject/email/name/expiry read at sign-in. No polling or additional relay reads.
  • Reuse the shared cache for Communities instead of its separate account reads; preserve the development broker session when capability checks fail.
  • Discover Decisions grants even while Builderlab is unregistered: on Settings entry, before routing a request within its existing deadline, and before Attention checks classifier readiness.

Reviewer highlights

  • Native and broker sessions fence late results to the original sign-in. Urgent Stop starts a refresh without waiting for it.
  • Self-review and independent review completed; no blockers found. Decisions discovery uses the existing contribution lifecycle and preserves explicit provider choices. No layout, shared controls, navigation, or signing changes.

Validation

  • Full Agents service, Decisions service, and Builderlab decisions test files: 547 passed, 1 existing skip. The final Attention regression and bin/pnpm author:build passed; Settings tests remain covered by the pre-push related-test gate.
  • Regressions reproduced before the fixes and pass afterward: cached remote-agent gates, opening Decisions Settings, making a decision request after a new grant, and Attention watch classification without a TypeSafe key. The Attention regression confirms a rejected event is dropped and a matching event delivered after one shared refresh. Added checks preserve custom provider choices, fallback on discovery failure, plugin removal, and no dispatch after deadline expiry.
  • Coverage includes the one-minute boundary, concurrent checks, unchanged profile fields/viewers, failure retention, account switches, disposal, and the broker HTTP route. The former independent Communities rejection case is covered by session refresh failure tests, including 401 and 503.
  • No browser journeys added or removed; this change uses service tests and mounted React integration tests.
  • Pre-commit and full pre-push hooks passed: TypeScript, related unit tests, design types/guards, and machine policy. Checked head: 5502f2ef (includes Attention readiness discovery).

Deferred acceptance

  • Draft: native app exercise, human acceptance, and rendered checks in both themes, narrow/wide layouts, enlarged text, keyboard and pointer remain pending.

jsibbison-square and others added 4 commits November 8, 2026 08:29
Cache capability checks for one minute, retain permissions on failure, and keep sign-in identity stable.

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Co-authored-by: Codex <codex@openai.com>
Check provider availability independently of registration when opening Decisions settings and within the existing request deadline.

Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Co-authored-by: Codex <codex@openai.com>
@jsibbison-square
jsibbison-square marked this pull request as ready for review November 7, 2026 22:36
@jsibbison-square
jsibbison-square requested review from a team as code owners November 7, 2026 22:36

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Three capability-refresh regressions need attention; details inline.

Comment thread src/features/decisions/service.ts Resolved
const started = generation;
const result = await me(credential, session.signal, true);
if (started !== generation) throw new Error("Builderlab session changed");
return result;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [P2] Preserve refreshed capabilities across browser reload

This returns fresh flags without updating the broker account projection. After signing in without remote-agent access, granting it upstream, and discovering the grant in Settings, reloading restores the original unavailable flags. The restored dev session also starts a fresh one-minute cooldown, so reopening Settings performs no corrective request. This was reproduced in the actual app with the production broker and modeled upstream in Chromium and WebKit: the grant became available, reload removed it with the account-read count unchanged, and another minute restored it. Retain the refreshed flags and freshness with the broker sign-in, or refresh restored snapshots immediately while preserving identity and profile fields.

refreshCapabilities = createCapabilityRefresh(
account,
async () => {
const response = await fetch("/api/builderlab/capabilities");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [P2] Bind the capability request to the expected account revision

The capability GET carries no expected revision and returns none. If another development page switches the shared broker account before this renderer receives its account event, the broker reads the replacement account while owner === current still holds locally. Its flags can therefore be applied to the previous account projection until the event arrives. The broker generation fence only detects switches during its own read. Send and validate the expected public revision before reading capabilities, retaining the post-read fence. This is a source-established UI projection defect; operation routes still validate revisions, and no backend authorization bypass is established.

@jsibbison-square
jsibbison-square marked this pull request as draft November 7, 2026 23:08
jsibbison-square and others added 2 commits November 8, 2026 10:10
Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Jarrod Sibbison <jsibbison@squareup.com>
Co-authored-by: Codex <codex@openai.com>
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