Skip to content

Fork cannot follow upstream #67

Closed
Closed

Description

@github-actions

Fork cannot follow upstream

Plan: The plan did not finish. Run: https://github.com/scuttletoby/t3code/actions/runs/43576432978

Rebasing the series from dc032d7 onto v0.1.10-nightly.20261114.4669 stopped at: 1cfd0a7 fork: the server and CLI update from the desktop app's repository (#1)

Conflicting files:

  • apps/server/vite.config.ts
  • apps/web/tsconfig.json
  • apps/web/vite.config.ts

The series was left as it is. To follow by hand: git fetch https://github.com/pingdotgg/t3code.git tag v0.1.10-nightly.20261114.4669,
git rebase --onto v0.1.10-nightly.20261114.4669 dc032d7c8f88 <series branch>, resolve, run the tests, then push the branch with
--force-with-lease, and start the follow workflow once (gh workflow run fork-follow.yml --repo scuttletoby/t3code):
it releases the series and disables the upstream workflows that push started.

What State now
Series branch main at 595f5334f813
Candidate branch fork-follow/candidate absent
Release none: the plan did not pick a commit

Activity

  1. scuttletoby commented on Nov 14, 2026

    @scuttletoby
    Owner

    lens: fork-integrity (rebase) · reviewer: opus high (t3lens-follow-sec) · read at: 4273894

    covered:

    checks:

    • Tests ran under heavy with tokens unset and an empty gh config. All passed:
      • fork-tests-drift.test.cjs
      • fork-ci-tests.test.cjs
      • fork-workflow-triggers.test.cjs
      • fork-contracts.test.py
      • fork-follow.test.sh
      • fork-reusable-permissions.test.py
    • The TS/vitest tests (workAdmission, EffectWorker, ElectronShell, settings) were NOT run. The capacity check said NOT OK and the worktree has no node_modules, so I reviewed them by reading.
    • Runs again / old state:
      • Old settings files: renameRetiredAutoUpdateKeys is unchanged, so autoUpdateServer still loads as automaticUpdates.
      • Gate held during an upgrade: nothing is claimed while it is held. One claim per slot waits, and inFlight goes up and down inside an uninterruptible admit.
      • A hung provider request still counts as busy, so the update waits. That is the same as before the rebase.
    • Stops half-way: the plan runs git rebase --abort and leaves the series as it is.
    • Follow runs before the push: from old main it rebases and stops red on conflicts (as in this issue).
    • The force-push changes issue-labels.yml and stale-needs-more-info.yml, so GitHub may register them and start them once (push/schedule only, so outsiders cannot start them). The plan's "Disable upstream workflows" sweep then turns them off. This is the known behaviour.

    finding: minor · .github/scripts/fork-follow.sh:351 (rebase path 410-414) · Upstream already has a newer nightly, v0.1.10-nightly.20261114.4682. After this hand push, the follow run takes target 4682, which is not the same as base 4669, so it rebases instead of releasing. I simulated that rebase against real upstream: it stops on #17 3359d10 with conflicts in apps/web/src/components/ChatMarkdown.permissions.browser.test.tsx and apps/web/src/components/chat/MarkdownFileLink.tsx. The run goes red and nothing is released. That is safe (the series is left as it is), but the hand push alone does not ship a release. Fix: rebase onto 4682 before pushing, or after the push dispatch fork-release.yml by hand on main with publish=true.

    findings: 1 (minor)

    verdict: SAFE

  2. scuttletoby commented on Nov 14, 2026

    @scuttletoby
    Owner

    lens: correctness (rebase) · reviewer: opus high (t3lens-follow-corr) · read at: 4273894

    covered: git range-diff of old main dbe9c16 (base dc032d7) against v0.1.10-nightly.20261114.4669..4273894f76; git diff <tag>..4273894f76 read in full for EffectWorker.ts, workAdmission.ts/.test.ts, ChatMarkdown.tsx, ElectronShell.ts, index.css, contracts settings.ts, shared serverSettings.ts, server and web vite.config.ts, web tsconfig.json; scripts/lib/tagged-source-version.ts and release-repository.ts; fork-follow.sh base/series logic; the two new commits (issue-vouch.yml removal, fork-tests drift). Per-file check over all 144 files touched by either side: the fork's added/removed lines are identical before and after the rebase except in the expected files (deleted upstream workflows, EffectWorker.ts + its test, index.css, the two new commits, and #11's CommandPalette test, which upstream now has byte-for-byte as pingdotgg#35107).

    checks:

    • EffectWorker.ts:975-999: with the gate open or off (pass-through), the Deferred completes as soon as runOnce starts, so upstream fix(server): one unresponsive provider no longer stalls every thread's effects pingdotgg/t3code#35027's 30 s slot wait is unchanged. Proof: upstream's own test ("starts another thread's turn while every worker holds a start that never returns") passes as is, passes with an enforced open gate patched in, and fails when the slot wait is made 5 h (so the test really exercises it). While held, each slot keeps exactly one admit waiting, the same as the fork before fix(server): one unresponsive provider no longer stalls every thread's effects pingdotgg/t3code#35027. No double claim: one runOnce per admit. No new overrun: the only extra running work after 30 s is upstream's intended timed-out execution, which stays counted in inFlight (admit's ensuring), so an update hold still waits for it. Scope close interrupts both the waiting slot and the forked attempt.
    • New test workAdmission.test.ts:86 fails without the fix: with the naive merge (admission.admit(runOnce) forked, no wait for admission) it reports 12 claims instead of 2 after five 31 s waits under a hold. It passes at head.
    • ChatMarkdown.tsx: all fork lines kept; remote-editor onOpen, onOpenFullSize, onDownload sit on upstream's useOpenInPreferredEditor(environmentId, availableEditors, cwd) and use resolveHostPath().absolutePath, which goes through upstream's multi-root/agent-directory lookup.
    • ElectronShell.ts: upstream's isAppLaunchUrl(url) kept; the fork only narrows isRemoteEditorUrl with url.href === rawUrl.
    • index.css: the -webkit-touch-callout: none rule moved into upstream's existing .chat-markdown-file-link block. Same effect, no duplicate selector.
    • settings.ts / serverSettings.ts: compared with the tag, only additions (all upstream settings present). All fork settings are present (automaticUpdates, automaticUpdatesQuietCommand, usagePacing, headlessUsageRefreshInterval) with decoding defaults, so old and empty settings files decode. The old autoUpdateServer name is still renamed on load (autoUpdateSettings tests pass).
    • vite.config.ts x2 + web tsconfig.json: upstream's resolveTaggedSourceVersion kept, plus the fork's releaseRepositoryDefine(). That function only accepts ^v\d+\.\d+\.\d+$ tags at HEAD with unedited manifests, so a -fork.N tag is never read as an upstream version.
    • Tests at head (Node 24): workAdmission, EffectWorker, the fix(server): one unresponsive provider no longer stalls every thread's effects pingdotgg/t3code#35027 FoundationPersistence case, contracts settings + editor, shared serverSettings + cliRelease, server serverSettings, ElectronShell, MarkdownFileLink.logic, tagged-source-version, release-repository, and every other fork test file changed in the series (server 19 files/637 tests, web 3/40, desktop 1/2): all pass. Typecheck (effect-tsgo tsrs --noEmit) passes for contracts, shared, server, desktop and web.
    • State question: (a) old/empty settings files: decode via defaults (above). (b) A gate held during upgrade: slots wait at the gate without timing out and keep one claim each; after release each slot makes one claim. Held rows stay pending for startup recovery as before. (c) The series is 35 plain commits, all fork-own, no merges, sitting on the 4669 tag (merge-base HEAD upstream/main = the tag). So after the push, fork-follow.sh finds base 4669 and rebases only those 35 onto the next nightly (4682 already exists). No old fork release is in the new history, so the built-on-tag check does not trip. If the follow runs again before the push, it fails on the old main as before; origin main is still dbe9c16, so the force-with-lease push is still valid and refuses if main moves first.

    findings: none

    verdict: SAFE

  3. scuttletoby commented on Nov 14, 2026

    @scuttletoby
    Owner

    lens: fork-integrity (rebase 4682) · reviewer: opus high (t3lens4682-sec) · read at: 476513a

    covered:

    • The range-diff from the 4669 series (4273894) to this one: 33 patches are =. feat(web): file links open remotely, full size, download from their menu #17 and feat(server): keep a history of provider usage-limit readings #24 are !. In feat(server): keep a history of provider usage-limit readings #24 only the context line in usageLimits.ts changed.
    • feat(web): file links open remotely, full size, download from their menu #17 MarkdownFileLink.tsx, compared with the 4682 tag: the fork's menu (open-in-panel, open-full-size, download, copy-path-only) passes upstream's source to contextMenu.show. Right-click and click use contextMenuSourceOf(event). Long-press passes "mouse", so the menu does not preselect its first item. The upstream keyboard test is kept, with the pathOnly field added. The fork's long-press test also checks for "mouse".
    • Upstream 4669..4682 (114 commits): the only change under .github is release.yml. In that file only the "Merge desktop updater manifests" step changed, with no trigger change. No workflow was added or removed. release.yml is still disabled_manually on the fork. Every upstream workflow that outsiders can start (pull_request_target, issue_comment, issues, workflow_run) is either deleted by fork-removed-workflows.txt or listed by GitHub as disabled_manually. The list is still complete.
    • Fork workflows and actions: compared with old main, no unpinned third-party uses: was added. The only tag ref is the fork's own job-changed@ci-release, which old main already had. No new secret reference.
    • fork-release.yml keeping the old script is correct. Upstream's new merge-release-update-manifests.ts (pairArchitectures) throws "missing its arm64 manifest" when a Windows channel has only x64. The fork builds Windows x64 only, so it renames *-win-x64.yml to latest.yml. scripts/merge-update-manifests.ts is unchanged in 4669..4682. Upstream's new script still imports it, and its own test still runs the CLI with --platform mac. release-desktop.yml did not change in 4669..4682.
    • Upstream fix 8a072ca (the unenv pin) is in the series. The fork does not touch pnpm-workspace.yaml, pnpm-lock.yaml or package.json, so the fix applies unchanged.
    • Nothing personal added: added lines that look personal are byte-identical in old main dbe9c16 (unchanged patches). All 35 commits use the noreply author. There are no merge commits.

    checks:

    • Tests ran under heavy with GH_TOKEN and GITHUB_TOKEN unset and an empty GH_CONFIG_DIR. All passed:
      • fork-tests-drift.test.cjs, fork-workflow-triggers.test.cjs and fork-ci-tests.test.cjs
      • fork-contracts.test.py, fork-release-workflow.test.py and fork-reusable-permissions.test.py
      • fork-follow.test.sh and fork-release.test.sh
    • fork-tests-drift.cjs at head: "Upstream test jobs match". The 4682 release.yml change is outside the copied test jobs. The last commit's subject still says 4669, but its content is still right for 4682.
    • The web vitest tests for feat(web): file links open remotely, full size, download from their menu #17 did not run because this worktree has no node_modules. I reviewed them by reading.
    • Plan simulation: I ran fork-follow.sh at head against a local upstream frozen at the 4682 tag, with the fork's real tags. Result: action=release, base_tag 4682, base_commit 820f620, new_workflows empty. Real upstream's newest nightly is still 4682.
    • Runs again, stops half-way, old state:
      • A daily follow run before the push works from old main: it rebases 4669 onto 4682 and stops red on the feat(web): file links open remotely, full size, download from their menu #17 conflict, as is already known. It pushes nothing.
      • After the push, the run plans release from this main. The base-tag-moved check is skipped because no fork release is in the new history.
      • If the release stops half-way, main stays as it is and no fork tag is made. The next run plans release again.
      • If a newer nightly lands before the release, the run takes the rebase path. A conflict there stops red and leaves the series as it is.
      • If main moves first, the force-with-lease push refuses. Origin main is still dbe9c16.
      • After the force-push, GitHub may again start the changed push/schedule upstream workflows once. Outsiders cannot start any of them, and the plan's sweep disables them. This is the known behaviour.

    findings: none

    verdict: SAFE

  4. scuttletoby commented on Nov 14, 2026

    @scuttletoby
    Owner

    lens: correctness (rebase 4682) · reviewer: opus high (t3lens4682-corr) · read at: 476513a

    covered:

    • I recomputed git range-diff v0.1.10-nightly.20261114.4669..4273894f76 v0.1.10-nightly.20261114.4682..476513abe8. It matches the stored one byte for byte: 33 patches are =, feat(web): file links open remotely, full size, download from their menu #17 and feat(server): keep a history of provider usage-limit readings #24 are !.
    • Per-file check over all 143 files the series touches: the fork's own +/- lines (git diff <tag>..<series>) are identical before and after the move in every file except the two feat(web): file links open remotely, full size, download from their menu #17 conflict files (ChatMarkdown.permissions.browser.test.tsx and MarkdownFileLink.tsx). feat(server): keep a history of provider usage-limit readings #24 (usageLimits.ts) differs only in context.
    • Upstream 4669..4682 touches 7 fork-patched files. I read each upstream diff against the fork lines:
      • MarkdownFileLink.tsx: upstream fix(desktop): keyboard-opened message link menus select their first item pingdotgg/t3code#24889 adds source: ContextMenuSource to showFileContextMenu and passes contextMenuSourceOf(event). Upstream fix(web): remove routine success notifications pingdotgg/t3code#36527 drops the copy success toast. The head keeps both. The fork's markdownFileMenuItems call passes position, source. The fork's long press calls showFileContextMenu({ x, y }, "mouse"). On the options button, onClick still reaches handleContextMenu(event) with the real event when no long press fired, so keyboard Enter/Space (detail 0) still gives "keyboard". handleCopy is upstream's .catch form with no success toast.
      • ChatMarkdown.permissions.browser.test.tsx: upstream's two new keyboard tests are kept. The only change is pathOnly in the props of upstream's new MarkdownFileLink test, which the fork's markdownFileCopyPaths return type requires. All fork tests are kept, and the long-press test now also checks the "mouse" source.
      • ChatMarkdown.tsx, server.ts (watchManagedTunnelOrigin), apps/web/vite.config.ts (browser test port 20000-23999), runtimeLayer.test.ts (settle tests): upstream hunks and fork hunks do not meet.
      • usageLimits.ts: upstream changes the Limits UI key in collectLimitAccounts (hubIdentity). The fork's usage history keys accounts through providerAccountIdentity -> accountKey/nativeReport, which upstream did not change. No fork file reads LimitAccount.key, so the stored history keys stay the same.
    • Release path: upstream a8e60d4 (fix(release): require complete updater manifests pingdotgg/t3code#23700) replaces release.yml's merge steps with merge-release-update-manifests.ts. That script requires both arm64 and x64 for macOS and Windows: pairArchitectures throws "Windows ... missing its arm64 manifest". fork-release.yml builds Windows x64 only (desktop_win_x64; there is no arm64 Windows job), so keeping the old step is correct. scripts/merge-update-manifests.ts is still in 4682, unchanged since before 4669, with the same --platform mac <primary> <secondary> [output] CLI. The new script imports it, so it will not disappear soon. The fork's macOS loop (*-mac-x64.yml + *-mac.yml -> merged into *-mac.yml) matches what the new script does for macOS.
    • The Release Smoke fix 8a072ca (fix(ci): pin unenv so release smoke installs resolve its exact peer pingdotgg/t3code#36638, pin unenv) is an ancestor of 4682. release-smoke.ts in 4682 calls the new script on its own arm64+x64 fixtures, which is fine for fork-tests.yml.
    • Upstream ci.yml did not change 4669..4682 (the only .github change is release.yml). fork-tests-drift.cjs says the jobs match, so the last commit's "at 4669" title is still accurate.
    • Merge-base of head with upstream/main is exactly the 4682 tag. It is upstream's newest nightly right now. All 35 commits use the noreply author. The added lines carry nothing personal: only the repo name, the owner login and CIDR ranges in docs, all identical to before.

    checks:

    • Tests ran under heavy, with GH_TOKEN/GITHUB_TOKEN unset and an empty GH_CONFIG_DIR, at head 476513a:
      • server: runtimeLayer.test.ts, UsageReadingsHistory.test.ts, workAdmission.test.ts. 3 files, 215 tests, all pass. This includes the fork's "closed gate, then restart" test next to upstream's changed settle rules.
      • shared: usageLimits.test.ts, 91 pass.
      • web browser (chromium): ChatMarkdown.permissions.browser.test.tsx, 17 pass, including upstream's keyboard/mouse source tests and the fork's long-press, remote-editor and full-size/download tests. A first attempt hung with no output and was killed by my timeout. The rerun was clean.
      • fork-tests-drift.test.cjs: 6 pass.
    • Attack (mutation): changing the long-press source to "keyboard" makes the fork's long-press test fail (expected 'keyboard' to be 'mouse'). So the resolution is pinned by a test. Reverted after.
    • Not run: the web typecheck. t3-capacity went NOT OK (load) after the tests, so I checked the types by reading: ContextMenuSource comes from contracts, and contextMenu.show(items, position, source?) is in ipc.ts.
    • State question:
      • Runs again before the push: origin main is still dbe9c16, so the force-with-lease push is valid and refuses if main moved first. A follow run on old main rebases onto 4682 and stops red on feat(web): file links open remotely, full size, download from their menu #17 as before. Nothing is pushed.
      • Runs again after the push: base = 4682 = target, so it takes the release path. There is no newer nightly yet. When one comes, it rebases only the 35 fork commits.
      • Stops half-way: git rebase --abort leaves the series as it is.
      • Old state: old usage-history files keep their account keys (see usageLimits above). Old settings: settings.ts/serverSettings.ts were not touched by upstream 4669..4682, and the fork lines are identical.
      • Empty release assets: the fork's "Check updater manifests" step still refuses a release without latest.yml, latest-mac.yml and latest-linux.yml.

    findings: none

    verdict: SAFE

  5. github-actions commented on Nov 14, 2026

    @github-actions
    Author

    Fork follows upstream

    Plan: Release the series on v0.1.10-nightly.20261114.4682 as it is. Run: https://github.com/scuttletoby/t3code/actions/runs/43592875081

    What State now
    Series branch main not moved: at c361a194194d
    Candidate branch fork-follow/candidate absent
    Release v0.1.10-nightly.20261114.4682.fork.1 published at 476513abe819
    Upstream workflows disabled .github/workflows/issue-labels.yml, .github/workflows/mobile-showcase-screenshots.yml, .github/workflows/publish-aur.yml, .github/workflows/release-desktop.yml, .github/workflows/stale-needs-more-info.yml, .github/workflows/windows-tests.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions