Skip to content

fix: Codex account switch releases the conversation, Reset usage on the limit banner - #32863

Closed
ScriptedAlchemy wants to merge 492 commits into
pingdotgg:mainfrom
ScriptedAlchemy:fix/codex-account-switch-and-reset-usage
Closed

ScriptedAlchemy wants to merge 492 commits into
pingdotgg:mainfrom
ScriptedAlchemy:fix/codex-account-switch-and-reset-usage

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Contributor

Two phone-reported bugs, plus the root cause of why quitting the app was the only workaround.

1. Switching Codex accounts stranded the conversation

Hitting the usage limit on one Codex account, switching the thread to another Codex account, and sending failed with "This conversation is open in another Codex client" — forever, until the desktop app was quit.

Root causes, from the server logs and traces of the failed thread:

  • ProviderSessionManager.detach only unloaded native threads still bound to the old session in the projection. An account switch rebinds the thread to the new account's session in the same commit, so the main conversation was never unsubscribed on the old account's app-server (only a subagent's was), and that process held Codex's writer lock indefinitely. Quitting the app killed the process, which is why quit-and-reopen "worked".
  • Even after thread/unsubscribe, Codex holds the lock until its idle sweep emits thread/closed about 60s later, while turn-start retries span ~1.5s.

Fix: detach also unloads this thread's same-driver native threads that were rebound to another session, taking the driver from the live runtime (the detached event has already removed the session's projection binding, so the projection cannot supply it). A process-wide release registry records threads this server unsubscribed; a resume refused for one of those waits up to 90s for thread/closed (or app-server exit) and retries once. Threads held by genuinely external clients (Codex app/CLI/IDE) still fail immediately with the same message. Expect the first message after a switch to pause up to ~a minute instead of erroring.

2. No way to reset usage from the limit banner

The usage-limit banner/card only offered "Resume at reset" and "Snooze until reset", though the usage panel could already spend a banked reset credit. When the limited account reports banked reset credits, the banner (web/desktop) and card (iOS/Android) now offer Reset usage: confirm, redeem via the existing consumeResetCredit command, then send to continue. It appears even when no reset time is known and respects the providers-manage scope. Mobile's redemption hook moves to usage/useResetCredit.ts so panel and card share it.

Proof

  • New regression tests for both server fixes; each fails on the old code (the detach test replays the real commit ordering, detached event included, and asserts the rebound root thread is unloaded) and passes with the fix.
  • vp run check:changed passes: format, lint, knip, typecheck (41 packages), tests beside the changes, React compiler.
  • Not exercised in a live client; the banner change is covered by its unit tests and the server behavior by the replay/manager tests.

Model: muse-wonder-1.0-contributor (Muse Code)

ScriptedAlchemy and others added 30 commits October 23, 2026 03:34
Bound cleanup in existing summary passes and retain summaries referenced by handoff deliveries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Open summaries from thread actions, show pass outcomes and stale reasons, and page through canonical source messages only while the viewer is open.

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

The dev server runs under node --watch, which exports WATCH_REPORT_DEPENDENCIES; the
analysis child inherited it and reported its imports over the IPC channel, so every
query in vp run dev failed as an invalid result. The child environment now drops it.

The SDK's index .gitignore keeps itself tracked, which left .codegraph-t3/ in the
user's git status. T3 writes a .gitignore that ignores itself too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Render fact origins once and list only message citations across provider context, web and mobile. Return resolved preview labels and text for the web draft footer, keeping the exact payload in an explicit disclosure and supporting older remote servers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
project.readLoomWindow scanned every null-child native task in the
database, walked each lane's whole run history for a 7-day window,
sorted command payloads, parsed every lane's full pull request JSON,
and let unbounded titles push a response past its 256 KiB cap. Lane
eligibility also dropped older threads whose only activity in the
window was a still-active run, a checkpoint, a PR link, a native task
or a transfer, and a fork shared its parent's PR marker ids.

Runs are now read as three indexed cases (requested in the window,
completed in or after it, still active), with migration 077 adding the
completion, command-candidate and linked-thread indexes. Lanes come
from bounded candidate sets, reads run in one read-only transaction on
the reader connection, labels are cut in SQL, PR markers are
lane-qualified and read compactly, and the byte cap measures the whole
response. Coverage reports when the untimed task count hit its bound,
and web and mobile share the coverage notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
recognizeTestCommand labelled `cargo test --no-run`, `pytest
--collect-only`, `cargo nextest list`, `jest --listTests`, `vitest
--help` and version flags as test runs. Those modes are now rejected,
`cargo nextest` needs `run`, and `go test -list`/`-c` no longer count.

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

"Older lanes" sent the cursor without from/to, so in the default window
the server resolved a new "now" and rejected page two. Each cursor now
travels with the bounds of the page that produced it, and the paging
state is keyed by environment and project too. A run with no recorded
start is no longer drawn as all queue time unless its status says it
has not started, and the limits notice now includes scan coverage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The sidebar's Loom icon always opened a grouped project's primary
environment, and both the sidebar and the command palette offered Loom
on servers without the projectLoom capability. Both now pick the active
member when it decides, otherwise offer each supporting environment by
name, and hide Loom where no member supports it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fit reset the view to the whole window, so a few minutes of runs stayed a
sliver at the right edge. It now frames the window's runs, markers and
transfers with a margin. The scale also keeps an inset at both ends, so a
marker at the current time is no longer clipped in half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Palette and agent symbol search returned an import node for every file
that imported the match. Search now drops the same structural kinds the
file outline already excludes, keeping file nodes for path searches.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds LoomRunActivity, a compact [offsetMs, kind] list of a run's turn items, so the
Loom can draw tool calls, messages and edits on each lane. The server returns an
empty list until the read lands.

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Traex gpt-6.1-sol
…the tick limit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the lane-field helpers with a weave: each root thread and its descendants
become a workstream, each strand knows its extent, spawn (exact from an edge or
inferred from creation), rejoin and events. The timeline and event panel now share
the marker key, active-run set and selection-thread lookup from this module.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Pure modules for the weave. The spindle places workstreams as bands around a spine
with a smoothstep fan at both anchors, bins ticks to one dot per column and culls
glyphs by rank with a per-strand spacing and a global cap. The branch layout gives a
workstream's children alternating lanes in spawn order, nests grandchildren beyond
their parent, draws spawn and rejoin S-curves, and clusters dense events into capped
nodes led by the most telling event.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Real windows have one root with dozens of subagents, most of which record
nothing but their creation, so the spindle and branch geometry rendered a
thin sliver and a column of empty lanes.

- A runless subagent's extent runs from its recorded spawn to its result.
- The loaded tail ends at the window's end when the as-of time is later.
- The spine workstream's branches get their own colours, shared by both modes.
- The spindle spreads a sparse weave to fill the field, busiest strands nearest.
- Overview glyphs cull in two dimensions and leave spawns to Agent mode.
- Agent lanes pack in time, quiet children become spawn nodes on the parent,
  transfers cluster with the parent's events, and early events sit on the lane.
- Fit can keep the loaded tail in frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wheel zoom, wheel pan and drag-to-pan move out of LoomTimeline so the weave
field can use the same gestures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Loom opens on the workstream spindle: every thread fans from a start
node into its workstream's strands and converges on the loaded tail, solid
only where a thread was active. Agent mode shows one workstream as a bright
root spine with its subagents curving off at spawn, labelled event nodes,
and rejoin curves. Lanes keeps the previous timeline.

Around the field: a legend, a minimap with a draggable view, and a branch
navigator that opens a workstream in Agent mode. The view opens fitted to
the activity and the tail. Glow is a static halo stroke, not a filter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Traex gpt-6.1-sol
…ode's activity

With dozens of subagents, Agent mode held each lane for a label's width
after its strand ended, so short subagents spread over many lanes and
their curves became tall loops. Lanes now stay taken only a small gap
after a strand ends (or long enough for a short strand's title), bursts
of spawns take lanes shortest first so longer strands enclose shorter
ones, lanes sit 96px apart, and a strand shorter than two curve runs
still bends over a minimum hump.

Agent mode opens framed on its workstream's activity, and Fit does the
same. Workstream mode frames the window's activity with room on the left
for labels, and the spindle's anchors sit at the start of that activity
and at the loaded tail instead of the field's edge. Children that
recorded nothing but their creation no longer get a strand in Workstream
mode, matching Agent mode.

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

Count badges sit off each node's upper right instead of over its icon.
Workstream labels sit in the gutter left of the spindle's start anchor on
a backdrop, and the anchor's own label sits above it, so neither runs
over the strands; the start anchor hides once the view pans past it.
Agent lane titles sit higher so the badges below them stay clear. A
child that recorded nothing but its creation shows as a dot on its
parent's strand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace invalid cited-source delivery excerpts before inspection or replay and scrub stale summary text while retaining reference skeletons.

Co-Authored-By: Traex gpt-6.1-sol
Regression coverage for the published-generation implementation. The test intentionally fails until cold queries stop synchronizing the graph.

Co-Authored-By: Traex gpt-6.1-sol
…y cannot starve turn starts

Co-Authored-By: Traex gpt-6.1-sol
Prove shared-pool saturation through the daemon and SQLite outbox, and preserve independent per-type ordering while routing short title jobs through turn capacity.

Co-Authored-By: Traex gpt-6.1-sol
ScriptedAlchemy and others added 24 commits November 5, 2026 22:41
providerEnv.ts removes T3_ variables from test workers. FilePreviewModal.test.tsx
therefore read iOS while the code under test was compiled for Android, so its
Android run failed on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude models now advertise ultracode, and resolveOptions fills in every option
that does not set speed. The expected targets predate that option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(server): cleanup follows the checked-out branch

Maintenance kept every worktree whose agent had switched branches, because
nothing wrote HEAD back to the thread. A new WorktreeBranches service reads
HEAD and rebinds the threads on that worktree. Cleanup keeps for one pass after
a rebind, then applies the existing rules. A detached HEAD stays kept unless a
ref outside refs/t3 holds its commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(server): threads learn their branch when a run ends

A thread kept its old branch name after its agent switched branches, so the
pull request refresh skipped it and cleanup had to repair it later. Run
finalization now syncs the worktree branch before that refresh. A sync failure
only logs, so it cannot block the next turn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* refactor(server): launch rebinds threads through worktree branch sync

Launch carried its own copy of the loop that writes a branch to every thread
on a worktree. It now calls WorktreeBranches.sync after the rename, so one path
writes thread.branch for a worktree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(server): a rebound thread recreates on its new branch

Pins the resume half of the cleanup change. Once a thread is rebound and its
worktree is removed, the next turn recreates the checkout on the branch the
agent switched to, at that commit, and not on the stale name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(server): cleanup removes a deleted owner's worktree after a rebind

A deleted owner's record cannot be rewritten, so only its surviving subagents
are rebound. This pins that the group comparison still lets removal proceed on
the next pass, and that the branch ref survives.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(server): branch sync leaves foreign checkouts and held branches alone

An independent check of the cleanup change found three ways to lose or strand
work. A different repository at the worktree path had its branch written to the
thread, so the thread forgot its own branch. A branch another checkout holds was
recorded even though the thread could not recreate its worktree there. And the
detached HEAD check ran before later steps that gave a holding ref time to go.

Sync now compares the worktree's repository with the project's before it writes,
and treats a branch another checkout holds like the default branch. Cleanup checks
the holding ref last, immediately before removal.

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

* fix(server): a prunable remote branch does not protect a detached commit

Cleanup counted any remote-tracking ref as holding a detached commit. A routine
`git fetch --prune` removes a remote branch that was deleted upstream, so the
commit could become unreachable after its worktree was gone.

Only local branches, tags, and the remote's default branch count now. A detached
worktree held by any other remote branch stays kept.

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

* fix(server): cleanup keeps what removal would strand and rebinds every thread

Adversarial review reproduced more ways for this change to lose work or never
finish. Removing a detached or default-branch worktree could lose a commit only
its reflog held, or strand a thread whose recorded branch another checkout held.
A remote-tracking ref counted as protecting a commit even though a routine prune
or a stale origin/HEAD could remove that protection. A run end skipped a sibling
whose write had been deferred to it. Threads with a trailing slash in their path
or no recorded branch never rebound, and mismatched records on a detached or
default-branch worktree were kept forever. A held index lock blocked rebinding,
and main counted as the default branch when the remote's default was trunk.

Cleanup now checks HEAD and the reflog against local branches and tags only, and
keeps a worktree while another checkout holds a recorded branch. Sync compares
HEAD with every thread on the worktree instead of the caller's record, reads HEAD
without depending on the index lock, finds threads by the path each one stored,
and asks the remote when no local HEAD ref names its default.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* fix(server): cleanup keeps commits only a reflog holds on every worktree

An adversarial review of this branch reproduced commit loss that main prevents.
A rebound worktree counted as bound on its next pass, which skipped the reflog
check, so cleanup removed it and gc then pruned commits only its reflog held. A
deleted owner with no surviving threads skipped the same check. Another
repository's linked worktree at the path skipped the repository check and lost
its untracked files to `git clean`. Two detached worktrees recording one branch
were both removed, and with no local origin/HEAD a default other than main or
master could become a thread's recorded branch.

The reflog check now runs on every worktree. Rewritten commits land in the reflog
too, so an amended or rebased worktree waits until gc expires those entries.
Cleanup compares the worktree's repository with the project's before it reads the
checkout, by file identity so a differently cased path still matches. It keeps a
detached or default-branch worktree while a thread elsewhere records the same
branch. The service asks the remote for its default whatever the name, once per
checkout.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* test(pstack): roles pin Ultracode off now that it is its own option

The upstream sync split Ultracode out of the effort list into a boolean option.
pstack pins every option except speed, so a role at effort=xhigh now resolves with
ultracode false, which is what that effort meant before: not Ultracode. This test
is fork-only, so the sync did not update it, and it left main's required Fork Check
failing for every pull request.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…o-create

feat(memory): save project facts without an approval queue
* feat(server): index worktrees for active agents, outside the repo

A checkout only indexed when something asked it a code question, the file
cap could leave a repo's own source out of its index, and the index folders
sat inside the user's repo.

T3 now indexes a project when it is added and a worktree when an agent
starts in it. An idle worktree is not rebuilt, and its index goes when its
thread settles, by the rules that let a worktree be deleted. Settings > Labs
has one switch for all of this; while it is off, only a code question builds
an index.

Indexes now live in T3's data directory. The SDK only takes a data directory
inside its project root, so each checkout gets a private root that links back
to its top-level entries. Folders an older version left in a checkout are
removed the next time it indexes, and a sweep drops indexes for checkouts that
are gone or no longer known.

Listings over the cap now rank first-party source first, builds run at low
priority with at most two at once, and the badge reports first builds and
failures. The Windows link and copy paths are untested.

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

* fix(server): harden code index cleanup and refresh

Preserve build lock inodes during cleanup and reject linked legacy lock paths. Rebuild when checkout indexing configuration changes, and follow settled ancestors when releasing subagent worktree indexes.

Add regression coverage for cleanup locking, config changes, and parent-settlement sweeps; drain background refreshes in generation assertions and document retained legacy lock files.

* fix(server): cleanup follows the checked-out branch

Maintenance kept every worktree whose agent had switched branches, because
nothing wrote HEAD back to the thread. A new WorktreeBranches service reads
HEAD and rebinds the threads on that worktree. Cleanup keeps for one pass after
a rebind, then applies the existing rules. A detached HEAD stays kept unless a
ref outside refs/t3 holds its commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(server): threads learn their branch when a run ends

A thread kept its old branch name after its agent switched branches, so the
pull request refresh skipped it and cleanup had to repair it later. Run
finalization now syncs the worktree branch before that refresh. A sync failure
only logs, so it cannot block the next turn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* refactor(server): launch rebinds threads through worktree branch sync

Launch carried its own copy of the loop that writes a branch to every thread
on a worktree. It now calls WorktreeBranches.sync after the rename, so one path
writes thread.branch for a worktree.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(server): a rebound thread recreates on its new branch

Pins the resume half of the cleanup change. Once a thread is rebound and its
worktree is removed, the next turn recreates the checkout on the branch the
agent switched to, at that commit, and not on the stale name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(server): cleanup removes a deleted owner's worktree after a rebind

A deleted owner's record cannot be rewritten, so only its surviving subagents
are rebound. This pins that the group comparison still lets removal proceed on
the next pass, and that the branch ref survives.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(server): harden code indexes on Windows

Avoid defensive SQLite lock journals, share checkout identity across path casing, and reject UNC checkout junctions instead of publishing partial indexes.

Model: Devin built by Cognition AI`nHarness: Devin
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(server): leave nothing of the code index behind in repos or T3's data

Cleanup kept `.codegraph-t3/` in users' repos, could add new untracked lock
files there, deleted any file a user had put in that folder, and left a
lock-only folder per worktree in T3's data directory that every hourly sweep
locked again. Old folders in a checkout that no build reached stayed forever.

Removal now deletes the lock files and their folders too. So a builder cannot
trust a lock on a file that was deleted before its lock landed, it compares the
file's identity across taking the lock and backs off if it changed. Lock files
go while held where the OS allows it, and on release where an open file cannot
be deleted. Old folders lose only the files T3 and the SDK wrote, and a
generation holding anything else is left alone. Startup and hourly sweeps clear
them from every project and worktree T3 knows, even with automatic indexing off.

Also from review: a pinned or explicitly active thread keeps a shared worktree's
index, source in a language outside the SDK's catalog makes coverage partial
once it is over 5% of the code, and an unreadable codegraph.json or .gitignore
no longer fails builds and reads.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* test(server): abort the analysis process in a way Windows supports

Two code index tests sent SIGABRT, which Windows rejects with ENOSYS, so they
failed before reaching the behaviour under test. They now use SIGKILL on Windows
and keep SIGABRT elsewhere; production treats any unexpected exit the same.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* fix(server): branch sync leaves foreign checkouts and held branches alone

An independent check of the cleanup change found three ways to lose or strand
work. A different repository at the worktree path had its branch written to the
thread, so the thread forgot its own branch. A branch another checkout holds was
recorded even though the thread could not recreate its worktree there. And the
detached HEAD check ran before later steps that gave a holding ref time to go.

Sync now compares the worktree's repository with the project's before it writes,
and treats a branch another checkout holds like the default branch. Cleanup checks
the holding ref last, immediately before removal.

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

* fix(server): a prunable remote branch does not protect a detached commit

Cleanup counted any remote-tracking ref as holding a detached commit. A routine
`git fetch --prune` removes a remote branch that was deleted upstream, so the
commit could become unreachable after its worktree was gone.

Only local branches, tags, and the remote's default branch count now. A detached
worktree held by any other remote branch stays kept.

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

* fix(server): cleanup keeps what removal would strand and rebinds every thread

Adversarial review reproduced more ways for this change to lose work or never
finish. Removing a detached or default-branch worktree could lose a commit only
its reflog held, or strand a thread whose recorded branch another checkout held.
A remote-tracking ref counted as protecting a commit even though a routine prune
or a stale origin/HEAD could remove that protection. A run end skipped a sibling
whose write had been deferred to it. Threads with a trailing slash in their path
or no recorded branch never rebound, and mismatched records on a detached or
default-branch worktree were kept forever. A held index lock blocked rebinding,
and main counted as the default branch when the remote's default was trunk.

Cleanup now checks HEAD and the reflog against local branches and tags only, and
keeps a worktree while another checkout holds a recorded branch. Sync compares
HEAD with every thread on the worktree instead of the caller's record, reads HEAD
without depending on the index lock, finds threads by the path each one stored,
and asks the remote when no local HEAD ref names its default.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* feat(server): Maintenance clears code indexes that are no longer relevant

Code indexes outlived their use. When Maintenance removed a worktree its index
stayed until the next hourly sweep, "Delete now" never touched indexes, and an
unsettled worktree that Maintenance kept held its index forever.

Maintenance now removes a worktree's index just before the folder, while the path
still resolves and a running build can stop first. The index sweep follows every
Maintenance run instead of keeping its own timer, so both share one schedule. A
worktree's index also goes after 7 days with no activity on its threads, unless
one is pinned or marked active. The next agent run rebuilds it.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* fix(server): cleanup keeps commits only a reflog holds on every worktree

An adversarial review of this branch reproduced commit loss that main prevents.
A rebound worktree counted as bound on its next pass, which skipped the reflog
check, so cleanup removed it and gc then pruned commits only its reflog held. A
deleted owner with no surviving threads skipped the same check. Another
repository's linked worktree at the path skipped the repository check and lost
its untracked files to `git clean`. Two detached worktrees recording one branch
were both removed, and with no local origin/HEAD a default other than main or
master could become a thread's recorded branch.

The reflog check now runs on every worktree. Rewritten commits land in the reflog
too, so an amended or rebased worktree waits until gc expires those entries.
Cleanup compares the worktree's repository with the project's before it reads the
checkout, by file identity so a differently cased path still matches. It keeps a
detached or default-branch worktree while a thread elsewhere records the same
branch. The service asks the remote for its default whatever the name, once per
checkout.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* fix(server): a same-named branch in another project keeps no worktree

Cleanup keeps a detached or default-branch worktree while a thread in another
worktree records the same branch, because only one checkout can hold it. The rule
compared branch names across all projects, so a same-named branch in an unrelated
repository kept the worktree with an untrue reason. It now compares threads in the
same project. Two projects sharing one repository are not compared, and resume
there still reports Git's error.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

* fix(index): recheck cleanup safety after stopping checkout indexes

Wait for index shutdown before the final activity, branch, local-change,
submodule, and recovery-reference checks. This preserves late tracked edits
when submodule removal requires force and retains detached history if its
last holding ref disappears during shutdown.

Keep worktrees when reflog or worktree-list inspection is truncated. Use
Effect Path for native cleanup fixture paths and preserve the Android
test-platform environment variable.

* test(server): make cleanup fixtures portable to Windows

Assert report accounting against filesystem-provided allocated bytes instead of assuming tiny files allocate nonzero space. Move and restore the Git-created hidden file for the invalid-pointer case.

* test(server): host casing test passes on case-insensitive Macs

The test decided its expected result by asking whether the upper-cased path exists,
to detect the Windows runner. That is also true on a Mac, where the linux row still
compares case-sensitively, so it failed on every Mac. It now checks the real host.

Model: Opus 5.5
Harness: Claude Code in T3 Code

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix(mobile): keep providers listed when their health probe lags

On iOS, Claude disappeared from both the model picker and @Opus autocomplete while Claude subagents were running fine in the same thread. Mobile removed a provider's whole group whenever the snapshot said not-installed or signed-out (states a pending or failed account probe reports), and model mentions additionally required status ready, so a warning probe hid the provider there too. Web keeps an enabled provider visible with its reason.

Keep enabled providers in the mobile picker and mark their models unavailable instead of erasing the group (Antigravity keeps its setup gate, since its catalog only exists once set up). Let mobile and web mentions name models from warning-status providers, matching what the server still delegates through. Also forward the model short name in mobile mention search, like web already does.

Done with Muse Code (muse-wonder-full-1.0).

* fix(test): stop scrubbing the mobile test platform flag

providerEnv deletes every T3_-prefixed variable, which removes T3_MOBILE_TEST_PLATFORM before tests read it. The mobile Vite config still transformed components for Android, so FilePreviewModal tests took iOS branches against Android-rendered code and failed the Client and package tests job on this PR and on main. Keep the flag, like the other test-only opt-ins.

Done with Muse Code (muse-wonder-full-1.0).
Automatic learning is now on by default, so a settled run queues an extract
effect that stays pending until the worker drains it. These tests never run the
worker and do not test learning, so they read that pending effect as work left
over after recovery.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removes Loom from web, desktop, mobile, server, contracts, and docs. Migration 91
drops the six indexes that only Loom read, and the shell's pending-secret lookup
now names its status index so that drop does not change its plan.

Also lands #72, which saves project facts without an approval queue. Migration 92
rewrites stored facts to the saved and forgotten states.

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

fix(mcp): expose account pool members for delegation checks
…ions (#75)

* test(mobile): reproduce linked thread title subscription loop

* fix(mobile): keep cited thread families mounted while links remain
Merge upstream/main at beaeeff while retaining fork permissions, provider installation, memory, summaries, code intelligence, provider pools, linked environments, and packaging. Fix final ACP frames to carry JSON line lengths through the new bounded-notification protocol; extend the existing EOF notification test.

Implemented and verified with GPT-6.1 via Codex.
…20261107

chore(sync): merge upstream main and preserve fork integrations
* fix(ssh): preserve installed service network settings

* docs: explain restarting an SSH host service
Detach only unloaded native threads still bound to the old session, but
an account switch rebinds the thread to the new account's session in the
same commit (and removes the old session's projection binding), so the
root conversation was never unsubscribed and the old account's app-server
held its writer lock indefinitely. The new account's resume then failed
with 'This conversation is open in another Codex client'.

Detach now also unloads this thread's same-driver native threads that
were rebound away, taking the driver from the live runtime. Codex also
keeps the lock ~60s after unsubscribe until its idle sweep closes the
thread, so a resume refused for a thread this server released waits up
to 90s for thread/closed and retries once; threads held by genuinely
external clients still fail immediately.

Model: muse-wonder-1.0-contributor (Muse Code)
The usage panel could spend a banked reset credit, but the usage-limit
recovery banner/card only offered Resume at reset and Snooze until
reset. When the limited account reports banked reset credits, the banner
(web/desktop) and card (iOS/Android) now offer Reset usage, which
confirms then redeems a credit via the existing consumeResetCredit
command. Mobile's redemption hook moves to usage/useResetCredit.ts so
the panel and card share it.

Model: muse-wonder-1.0-contributor (Muse Code)
@github-actions github-actions Bot added the vouch:unvouched Author is not yet trusted in the VOUCHED list. label Nov 8, 2026
@ScriptedAlchemy

Copy link
Copy Markdown
Contributor Author

Opened against the wrong repository — this branch lives on the ScriptedAlchemy fork, where the PR is ScriptedAlchemy#82. Closing.

@macroscopeapp

macroscopeapp Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $42.83, which exceeds your per-review limit of $15.00.

The top 3 files driving up this estimate:

File Diff Size Estimate
packages/pstack/UPSTREAM.json 107.68KB $4.28
apps/server/src/project/knowledge/persistence.ts 35.36KB $1.40
apps/mobile/src/components/ProjectKnowledgeEntry.tsx 23.99KB $0.95

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

@github-actions github-actions Bot added the size:XXL 1,000+ changed lines (additions + deletions). label Nov 8, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The requested comparison makes mobile OTA updates opt-in and adds explicit static-analysis suppressions. Human review is required to accept the update-delivery default and diagnostic exceptions.

Needs human approval because:

  • Per-review cost limit exceeded (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings, or comment @macroscope-app review this PR to bypass the limit and review now. You can add or adjust custom eligibility rules. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched Author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants