[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[fork] downstream changes - #2

Closed
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes
Closed

[fork] downstream changes#2
patroza wants to merge 52 commits into
fork/candidatesfrom
fork/changes

Conversation

@patroza

@patrozapatroza commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Managed downstream layer

RoleValue
Basefork/candidates
Headfork/changes
PurposeCanonical downstream product changes
DeploymentNever directly; composed into fork/integration

This is the permanent downstream product layer and the normal base for feature PRs. It contains our shared/fork-owned changes on top of the Tim and upstream-candidate provenance layers.

The following implementations are deliberately excluded and remain in managed draft overlays:

Private operations, credentials, machine topology, host configuration, and deployment implementation remain outside this public repository.

This PR intentionally remains open and draft. Do not merge it; fork/integration is the deployable aggregate.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 24, 2026
@patroza
patrozaforce-pushed the fork/tim branch 2 times, most recently from c6b394a to 83d75d0CompareJuly 25, 2026 05:23
@patroza
patroza changed the base branch from fork/tim to fork/candidatesJuly 25, 2026 08:12
@patroza
patrozaforce-pushed the fork/changes branch 2 times, most recently from 2a67c78 to 27a72d4CompareJuly 25, 2026 08:30
@patrozapatroza changed the title feat: apply public fork changesfeat: apply our fork changesJul 25, 2026
@patrozapatroza changed the title feat: apply our fork changes[fork] trunkJul 25, 2026
@patrozapatroza added FORK Long-lived protected fork provenance or private layer; do not merge directly. and removed vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XXL labels Jul 25, 2026
@patroza
patrozaforce-pushed the fork/changes branch 4 times, most recently from 79176b5 to d526bc4CompareJuly 26, 2026 08:56
@patrozapatroza changed the title [fork] trunk[fork] private changesJul 26, 2026
patrozaand others added 30 commits August 5, 2026 16:04
#44)
Source: pingdotgg#4506
Source SHA: f7eaa00
Imported unchanged as one candidate provenance commit.
…tgg#4558)
Imported from https://github.com/pingdotgg/t3code/pull/4558\n\nAdapted to retain our provider restart-recovery constants while replacing the local default-title check with the shared policy.
…gdotgg#4379) (#312)
Imported from pingdotgg#4379 at
a27510d060645809ae1472bba4dbb248dc624e25.
Open file previews revalidate on mount and subscribe to debounced
native filesystem watches so external edits (editors, git, agents)
show without a manual refresh.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Enrico Polanski <16064771+enricopolanski@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
… (#328)
Imported from pingdotgg#5344 at source SHA
783fd02 (commits b623dc2 + 783fd02
squashed into one provenance commit).
Imported behavior:
- `reduceThreadStreamItems`, a pure reducer that folds a batch of thread
stream items into one state and one persistable snapshot.
- `Stream.groupedWithin(64, 16ms)` on the live subscription so a burst of
thread events publishes the `SubscriptionRef` once instead of per event,
and web/mobile stop rebuilding large thread views per streamed event.
- `eventBatchSize` on `EnvironmentThreadStateOptions`, plus the upstream
regression tests for ordered single-publication bursts and for persisting
a settled snapshot when a batch ends with a non-persistable turn start.
Local adaptations:
- Kept our `httpSnapshotLoadAttempted` guard around the HTTP snapshot
fallback; the call now goes through `applyItems([...])`.
- Restored `setDeleted` (removed upstream) for the terminal
`thread-deleted` subscription failure, which never reaches the item
stream and so cannot go through the batch reducer. Cache removal is
shared with the reducer path via `removeCachedThread`.
Excluded:
- `tasks/todo.md`, the author's scratch checklist.
Follow-up (fork/changes, not this layer): our `reload-required` branch and
`reloadFromServer` are built on the deleted `setThread`, so rebasing
fork/changes onto this layer must re-express them against the reducer
(split the batch at the reload point, then re-enter `applyItems` with the
remainder).
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork platform layer in one commit: agent/stack docs, pr-stack and overlay
ownership, restack/compose/fork-stack scripts, Fork CI and compose
workflows, and root workspace/lockfile tooling.
Shared schemas for orchestration, RPC, settings, and related protocol
surfaces used by server and clients.
Runtime helpers, product-family helpers, and oxlint plugin rules shared
across the monorepo.
Client runtime state, connection diagnostics, and list helpers shared by
web and mobile.
Supporting packages that diverge from upstream for the fork product.
Server product layer: work-item bridges, queue/recovery, VCS drivers,
single-source RPC authorization scopes, worktree bootstrap, and related
tests. Includes thread.context.compact contracts wiring on the server.
Web UI product deltas including lists, composer, usage gauges, file/content
search, and thread-loading send guards.
Mobile shell product, list modes, composer queue API, and scroll behavior
after rolling back experimental feed layout work.
Desktop packaging scripts/config and backend ownership behavior for the
fork desktop shell.
Make the product default for draft threads match the preferred worktree
workflow: New worktree with Start from origin enabled. Mobile falls back
to the shared server defaults when config is still loading.
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
* feat(server): reap idle dev stacks from a level-triggered sweep
Dev stacks that repositories start outside T3's process tree have been surviving
for hours after the work that needed them finished. In the case that prompted
this, ten stacks stayed up for thirteen hours across two already-merged PRs,
holding roughly 15 GB of RSS.
Teardown was never broken; nothing invoked it. Both existing triggers are
edge-triggered. runOnWorktreeRemove needs a worktree removal, and merging a PR
does not remove one. runOnPrMerged fires from VcsStatusBroadcaster only when it
observes a not-merged -> merged transition for a worktree it happens to be
polling, so an agent that finishes its work and a human who merges an hour later
produce no observer, no edge, and no teardown.
Add a sweep that looks at state rather than events, so a missed hook costs one
idle window instead of an unbounded number of hours. Both project scripts stay:
they are the early reap and are strictly faster when they do fire. This is the
floor under them, not a replacement.
The registry format (`dev-stack/1`, contracts/devStack.ts) carries facts only —
pids, ports, and where each process runs — because the sweep reads every
project's stacks and cannot hold per-repo knowledge. Policy is declared per
checkout under `devStacks` in t3.json: idle window, consumer patterns, and the
ordered entry roles. That split matters beyond tidiness: an idle window is a
property of a repository rather than of one running instance, so changing it now
applies to stacks that are already up, on the next sweep.
Decisions worth knowing:
- Opt-in. A repository without `devStacks` is left alone rather than swept under
a guessed policy.
- `entryRoles` is ordered and we watch the first role present. A frontend holds
keep-alive connections to its own API, so also watching the API port would read
a stack as busy for as long as the frontend is up, and nothing would ever look
idle. An api-only stack falls through to the API by the same rule.
- An absent `entryRoles` watches every port. That over-detects activity, which is
the right way to be wrong: a stack lives too long instead of dying mid-run.
- A stack is never reaped on the sweep that first sees it. A cold boot plus a
build can outlast the window, so the clock starts from an observation.
- The producer's start/stop lock is honoured, so a stack that is halfway up is
skipped rather than killed.
- Ownership is confirmed against /proc/<pid>/cwd before signalling, so a recycled
PID is never mistaken for a stack's own process.
The sweep runs as one layer-scoped fiber in the server that already runs, rather
than a separate unit: the server is what starts the agents that create these
stacks, so "server down" means "no new stacks", and a per-stack systemd TTL is
the better answer for a hung server than a second daemon would be. Failures are
logged and swallowed. Each sweep reports its duration and counts, and logs at
info when it acted or ran long, so whether it burdens the main loop stays a query
rather than a guess.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* chore(contracts): keep the dev-stack contract free of downstream references
The producer of dev-stack/1 is a private repository; naming it here, and using
its worktree paths and tenant names as test fixtures, leaks downstream detail
into a contract that is meant to be repo-agnostic and is read by anyone adopting
the format.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(server): green dev stack reaper PR
---------
Co-authored-by: Stack Test <stack-test@example.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com>
* fix(vcs): treat bare repositories as valid worktree sources
A repository with `core.bare=true` was reported as "not a repository" at
detection, because `detectRepository` gated on `rev-parse --is-inside-work-tree`
— which conflates "is a Git repository" with "has a checkout". Every Git route
then failed with "Failed to resolve the VCS driver for this Git command",
including `fetchRemote` and `createWorktree`, so no thread could start against
that repository.
Starting a thread does not need the source repository to have a checkout: the
thread gets its own worktree, and `git worktree add`, `git fetch`, and ref
plumbing all work against a bare repository. Only operations that touch a
checkout need one.
- Detect bare repositories instead of rejecting them, and carry `bare` on the
repository identity. Detection now uses one combined
`rev-parse --is-bare-repository --is-inside-work-tree`, which separates
"no repository" / "bare" / "checkout" in a single call, so negative detection
stays at one git invocation.
- Let the bare-safe routes through: createWorktree, fetchRemote,
resolveRemoteTrackingCommit, removeWorktree, renameBranch, and createRef when
it is not also switching.
- Checkout-dependent routes (switchRef, pullCurrentBranch, stacked actions, PR
thread preparation) now fail with the actual reason — that the repository has
no working tree — instead of a routing error.
- Status polling reports a bare repository as having no workspace rather than
erroring on every poll.
* style: format files drifted on fork/changes
Whitespace only, no behavior change. These three files were already
unformatted on fork/changes and are untouched by this branch's fix, but the
agent ship gate runs a whole-repo `vp check`, so publishing is blocked until
they are formatted.
* fix(desktop): add the missing removeCommandLineSwitch test stub
`ElectronApp` gained `removeCommandLineSwitch`, but the DesktopUpdates test
mock was not updated, so `@t3tools/desktop` failed typecheck on fork/changes
before this branch. Untouched by this branch's fix, but the agent ship gate
runs the workspace typecheck, so publishing is blocked until it compiles.
* fix(vcs): supply the required worktree path in the bare-repo test input
* refactor(server): use Effect FileSystem and Schema for the runtime descriptor
serverRuntimeStartup wrote and cleaned up the runtime descriptor with
`node:fs/promises`, `node:path`, and hand-rolled `JSON.stringify`/`JSON.parse`,
which the Effect diagnostics flag (nodeBuiltinImport, preferSchemaOverJson) and
which failed the workspace typecheck.
- Write and remove the descriptor through Effect `FileSystem` (`mode: 0o600` is
preserved) and join its path with Effect `Path`.
- Encode and decode with the existing `ServerRuntimeDescriptor` schema from
`@t3tools/shared/serverRuntime` rather than untyped JSON. That schema was
already the one the desktop client decodes with, so the file now round-trips
through a single definition instead of two hand-written shapes.
- Keep prior failure semantics: a descriptor that cannot be written is a defect
(as it was under `Effect.promise`), and cleanup stays best-effort so a
missing, unreadable, or malformed file cannot fail shutdown.
- Pin the on-disk format with a test that decodes the written contents the same
way `DesktopExistingBackend` does, since that shape is a cross-process
contract.
* test(server): decode the descriptor via the schema JSON codec
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… of limit (#321)
* fix(usage): stop extra-usage pools from marking a provider out of limit
The ai-usage daemon reports Claude's extra-usage credit buffer as a
`monthly` window. That buffer is only drawn from once the 5-hour and
weekly plan windows are exhausted, so a drained (or switched-off) pool
says nothing about whether Claude is usable right now — yet
`usageMarkerForItem` treated any window at 100% as a hard block, painting
the provider dot red and the tooltip "limit reached" while 5h sat at 18%.
Markers, the outlook ring, and `worstUsagePercent` now only consider
enforced windows: daemon-flagged `informational` pools, extra-usage /
credit / on-demand buffers, and windows labelled `(off)` are context
only. The tooltip renders those rows with a neutral bar instead of a red
one. Money-denominated plan windows (opencode-go monthly $, cursor
billing cycle) keep enforcing.
Also picks up the daemon's `informational` and `limit` window fields in
the contract.
* test(usage): assert the tooltip stays neutral for a drained extras pool
---------
Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FORKLong-lived protected fork provenance or private layer; do not merge directly.size:XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@patroza@tim-smart