Skip to content

chore(stage): merge expbkmain and port Claude account rotation to the V2 adapter - #277

Merged
bk-agent-01 merged 13 commits into
stagefrom
t3code/edamame-stage
Oct 6, 2026
Merged

bk-agent-01 merged 13 commits into
stagefrom
t3code/edamame-stage

Conversation

@bk-agent-01

Copy link
Copy Markdown
Collaborator

Problem

stage did not have the newest bkmain work, and Claude account rotation could not fire on stage.

What this PR does

  1. It merges origin/expbkmain into stage. It does not change bkmain.

  2. It resolves the conflicts for the stage code:

    File Decision
    ClaudeAdapter.ts, ProviderCommandReactor.ts (+ tests) They stay deleted. stage runs ClaudeAdapterV2 and orchestration-v2, so 8a30edb73 and fix(server): close question cards when their session has stopped #276 do not apply here as written.
    claudeHardLimitRotation.expbkt3.ts It keeps the stage trigger (the fork account.rate-limits.updated event with the raw rate_limit_event). Git auto-merged the bkmain runtime.warning trigger, but the V2 adapter never sends that event, so rotation would have stopped without an error. From bkmain, it keeps the seven_day_overage_included type. It adds the adapter's overage rule: a rejection that overage absorbs is not a trigger.
    PhaseGroupedSidebar.tsx It keeps the stage archive-progress props and takes the four-argument row class from fix(web): sessions with live subagents or monitors no longer look stopped #274.
  3. It ports the rotation fix to stage:

    • claudeUsageLimits.ts reads the fraction from unifiedWindows when the top-level value is missing (from e826c31ba).
    • ClaudeAdapterV2.ts sends the trigger for every rejection. When no window can be drawn (model-scoped types), the trigger has no windows. The adapter sends it before the active-turn check, so a rejection between turns also triggers rotation.

Tests

  • New ClaudeAdapterV2.test.ts case: the real bkt3 frame, once during a turn and once between turns, plus a seven_day_opus frame. Each sends one trigger.
  • New listener case: the real frame triggers rotation, a frame that overage absorbs does not, and seven_day_overage_included triggers rotation.
  • Restored converter test claudeUsageLimits.expbkt3.test.ts.
  • Host load stayed above 12 on dev-server-1, so CI runs the full check, typecheck, test and build.

Not in this PR

Model: Claude Opus 5.5, Claude Code harness in T3 Code.

🤖 Generated with Claude Code

bk-agent-01 and others added 12 commits October 5, 2026 17:34
…em feed

electron-updater's GitHubProvider reads releases.atom, which lists only the
ten newest releases. Stage and mobile builds share the repository and publish
many times a day, so production builds fell out of the feed and installed
BK T3 Code apps stopped finding updates.

Each BK app now uses the generic provider against its own fixed release
(bk-desktop-production / bk-desktop-staging). After each dated release is
public, the publisher uploads that build's manifest to the fixed release with
payload URLs made absolute into the dated release. Multi-range requests are
off, because GitHub answers them with 501. A re-run repoints the feed for an
already-published build, and the feed never moves to an older version.

Also moves the release repository constant to iamtushar324/bkt3code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-feed

fix(desktop): BK T3 Code finds updates again
…pped

A session that held an actionable plan was filed under Plan Ready even while
its subagents or a monitor loop were still running. Plan Ready also hid the
Working/Monitoring badge, so the row read as parked. Background liveness now
outranks a held plan for grouping, the work badge, the plan pulse, and tree
hoisting. The plan stays visible as the outlined PLAN badge until the work
stops.

Also remove the violet pulsing row highlight for Plan Ready rows. They now
use the default row surface; the PLAN badge and group header still mark them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A rejected rate_limit_event carries its utilization only under
unifiedWindows, so claudeRateLimitEventToUpdate dropped it and no
account.rate-limits.updated event fired. The hard-limit rotation never
ran: Auto threads stopped with the usage-limit row instead of moving to
the next account and continuing.

Read the fraction from unifiedWindows when the top-level one is missing,
and accept seven_day_overage_included in the rotation listener.

An Auto thread whose window resets within five minutes now keeps its
account: the session stops, a notice names the continue time, and the
thread continues on the same account a minute after the reset. A user
message, an account-mode change or a thread delete cancels the wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review findings on the first commit:

- The converter fix still dropped model-scoped and overage rejections,
  and it let rejections that overage absorbs stop the thread. Trigger the
  rotation from the adapter's usage-limit runtime.warning instead: it
  carries rate_limit_info, covers every limit type, and fires only when
  the rejection blocks the turn. The upstream converter is unchanged.
- Clear the dedup key when a wait ends, so a fresh rejection on the
  same account is handled instead of swallowed.
- Only wait while the reset is still ahead; a rejection whose reset
  has passed moves the thread instead of waiting again.
- Cancel the wait as soon as a message is accepted for the thread
  (thread.turn-start-requested), not only once its turn starts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(server): Claude threads continue after an account hits its limit
…plan

fix(web): sessions with live subagents or monitors no longer look stopped
A background subagent or monitor can make the CLI call the API while no
T3 turn runs. When that call is rejected, the rate_limit_event arrives
with no turnState, so the adapter raised no usage-limit warning. A
second later the CLI starts a turn of its own, which fails with an
assistant `rate_limit` error and no fresh window event. The warning is
the only rotation trigger, so Auto threads stopped on the exhausted
account instead of moving and continuing. On bkt3, 2026-10-06 10:09 UTC,
three Auto threads on `sam` stopped this way.

Hold a blocking rejection that lands between turns on the session, drop
it on any recovery event, and raise the same warning (same
rate_limit_info detail) when the next turn fails with `rate_limit`. The
rotation listener and account service are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An answer or approval sent to a thread whose provider session had stopped
failed with "No active provider session is bound to this thread." Clients
only close a pending request on a stale-request failure, so the card stayed
open and every retry added another error row.

Report these failures with the existing stale-request detail so the server
count and every client close the request after the first attempt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(server): close question cards when their session has stopped
Brings stage up to expbkmain a5d6bb7 (bkmain 7c0b134 plus 8a30edb
and PR #276): #273 desktop update feed, #274 sidebar live work over plan,
#275 Claude limit auto-continue, 8a30edb between-turns rotation.

Resolutions:
- ClaudeAdapter.ts and ProviderCommandReactor.ts (+ tests) stay deleted:
  stage runs ClaudeAdapterV2 and orchestration-v2. 8a30edb and #276
  target those files, so neither applies here as written.
- claudeHardLimitRotation.expbkt3.ts keeps stage's trigger, the fork
  account.rate-limits.updated event carrying the raw rate_limit_event.
  Git auto-merged bkmain's runtime.warning trigger into it, which the V2
  adapter never emits, so rotation would have silently stopped. Kept from
  bkmain: the seven_day_overage_included type. Added: a rejection that
  provisioned overage absorbs is not a trigger (the adapter's own rule).
- PhaseGroupedSidebar.tsx keeps stage's archive-progress props and takes
  #274's four-argument row class.

Stage port of the rotation fix: ClaudeAdapterV2 sent the trigger only
when claudeRateLimitEventToUpdate produced windows, and a real rejection
carries its fraction only under unifiedWindows, so no rejection reached
rotation. The converter now reads unifiedWindows (from e826c31), and
the adapter sends the trigger for every rejection, with no windows when
none can be drawn (model-scoped types). The V2 adapter already emits it
before the active-turn check, so between-turns rejections are covered.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL labels Oct 6, 2026
… shell uses

#274's phaseSidebarIsAgentLive picked the bkmain shell's `session` field,
which stage's ThreadShell names `runtime`, so the stage merge failed the
client-runtime typecheck and the liveness test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bk-agent-01
bk-agent-01 merged commit 668aab6 into stage Oct 6, 2026
27 checks passed
bk-agent-01 added a commit that referenced this pull request Oct 6, 2026
stage moved to 668aab6 (PR #277: expbkmain and the Claude rotation port)
while the upstream merge was in progress. Two conflicts: one import line in
ClaudeAdapterV2.test.ts, and the restored claudeUsageLimits test, which git
moved out of provider/Layers/ (flattened upstream). publish-bk-desktop-dmg.ts
follows the new prefer-catch-tags lint rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant