fix(discord-bot): stop posting the same Grok answer twice - #486
Draft
omegent-app[bot] wants to merge 445 commits into
Draft
omegent-app[bot] wants to merge 445 commits into
omegent-app[bot] wants to merge 445 commits into
Conversation
AGENTS.md is the single current fork workflow: - change PRs target `fork/dev` and squash-merge - update `main` from `upstream/main`, then classic-merge into `fork/dev` - catching a change PR up is rebase or merge — pick one Removed the historical stack/handover docs (`docs/fork-stack.md`, `docs/fork-base.md`, `docs/stable-dev-release-branch-handover.md`) so they cannot describe a past or future model. Grok 4.6 / T3 Discord opened by [patroza](https://discord.com/users/95218063095377920) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1538189075251601469/1538189075251601469) · [T3](https://t3vm/?thread=866be431-d52a-48b6-bb4b-cfcd2399d79c) --------- 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>
#401 was squash-merged. That kept the code and threw the lineage away: the 23 upstream commits stopped being ancestors, so `fork/dev` read as **29 commits behind upstream when only 6 were genuinely outstanding**, and the next sync would have re-merged and re-resolved all 23 — on the same mobile files that took sixteen conflicts to land the first time. Nobody noticed for two merges. It surfaced in a deploy alert that said **"Commits (2)"** for a range that had carried 23. ## What this adds A `push`-triggered check on `fork/dev` that fails when a commit which carried a sync has fewer than two parents, and prints the `-s ours` repair in the log. Sync commits are identified by **the head branch of the PR they came from**, not by their subject, because subjects vary by merge method: ``` Merge pull request #400 from patroza/sync/upstream-2026-08-12b Merge upstream/main into fork/dev (23 commits) (#401) merge: sync upstream through b73232b ``` A merge-button commit names the branch inline, so no API call is needed; squash and rebase commits are resolved through the API, with the subject line as a fallback when that is unavailable. **Ordinary fork PRs are untouched** — they are expected to squash, and are never checked. ## Verified against the real commits | commit | what it is | result | |---|---|---| | `5e63531b1` | #401, squash-merged sync | **fails**, exit 1 | | `0bf7835cc` | #400, sync merged properly | recognised as a sync, passes (2 parents) | | `a76069bd9` | #402, an ordinary squashed PR | not flagged | The third row is the one that matters most: the guard has to stay silent on your normal workflow. ## This detects, it does not prevent Worth being explicit, since it was the first question asked: **clicking merge does not fail.** The check runs after the merge lands, because GitHub has no per-PR merge-method control, and a repository-wide setting cannot allow squash for ordinary fork PRs while requiring a merge commit for syncs. Squash merges do fire `push` — `5e63531b1` triggered Fork CI at 08:08 — so this turns a silent, weeks-later discovery into a red check within a minute. Actual prevention is `gh pr merge <n> --merge`, which is how #398, #399 and #400 all landed correctly. That is now written into the sync runbook in `AGENTS.md`. If you would rather it be enforced at the button, the next step is a `sync:upstream` label workflow that merges the PR through the API once checks pass — say the word and I will add it. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) via [T3 Chat](https://t3.chat) on Discord --------- 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>
…PRs (#413) Manual `/omegent today-recap` (alias `/agent today-recap`) starts a recap thread for the repo bound to the calling Discord channel (`t3-<shortName>` topic). No schedule — someone has to run it. ## Why Daily recaps of PR opens/merges/closes (with Discord thread links) are useful and cheap. Doing it as a slash command now lets us iterate on format without a cron. ## What - `/omegent today-recap` in a project channel (e.g. scanner) opens a new thread and asks the agent for that repo's UTC-day recap - Same from a child thread: recap still lands on the parent project channel - `@Omegent today-recap` / `today recap` as a mention fallback - Prompt encodes the format we settled: what/why from PR descriptions, `[PR #N](url)`, bare Discord thread URLs, `## 🟢 MERGED` / `## 🔴 CLOSED` / `## 🟠 OPEN`, `### fix` / `### feat` outline - Recap turns run `--local` (no worktree) ## Test plan - [x] `vp test run` todayRecap, slashCommands, channelInfoPin, mentions, MentionRouter - [x] `apps/discord-bot` typecheck - [x] targeted lint - [ ] After deploy: `/omegent today-recap` in the scanner channel opened by [joshuadima](https://discord.com/users/593167616273809448) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1539325452873769041/1539325452873769041) · [T3](https://t3vm.tail86038f.ts.net/?thread=1c8e37cb-722d-405e-8071-5c8c3cd159fe) --------- Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Joshua Dimaunahan <170177550+MindfulLearner@users.noreply.github.com>
Merges 66 upstream commits into fork/dev. Notable weld points: - ChatComposer: upstream pingdotgg#7150 relocated the prompt editor, length validation and footer, leaving the fork's copies as a second live layout. Ported the fork-only pieces into upstream's copies first — the environment-unavailable placeholder, the model picker's usage snapshot, and the attach-images button that drives the hidden iOS file input — then dropped the stale layout. - MessagesTimeline: upstream's new active-turn block indexes whatever it iterates; the fork walks its collapsed/interleaved list, so the block was rebased onto that list to keep the indices referring to one array. - DesktopUpdates: upstream's action reservation and widened installable check, kept compatible with the fork's Linux dir-install mode. - CommandPalette: dropped the `open` prop upstream removed while keeping the fork's file-picker / content-search overlays, and took upstream's newer reduceCommandPaletteUiState over the fork's relocated copy of the old one. - mobile-showcase-screenshots: GitHub-hosted runners (this fork has no Blacksmith) with upstream's palette-driven timeout. - ProviderRegistry.test: kept the fork's coverage for mergeProviderSnapshots / selectProvidersByKind, which upstream deleted while leaving both exported. Upstream's new t3code/no-native-title-tooltip rule flagged seven fork-only components; four had a title duplicating an existing aria-label, three needed the label moved off the native tooltip. rerere was disabled for this merge: it had replayed earlier resolutions onto new upstream content, which is exactly how a weld goes silently wrong. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
merge: sync upstream through f708f63 (66 commits)
…one (#417) Thread search restricted assistant matches to the single row a turn names as its terminal message: ```sql messages.message_id IN ( SELECT turns.assistant_message_id FROM projection_turns AS turns WHERE turns.assistant_message_id IS NOT NULL ) ``` Providers stream an answer as many assistant items — roughly ten per turn now, and climbing as chunking gets finer — and only the last is linked as `turns.assistant_message_id`. Everything said before it was invisible to search. That is why full-text search appeared to "stop working" without anything visibly changing: the query never changed, the shape of the data under it did. ## Measured on a live `state.sqlite` | | searchable | |---|---| | before | 7,118 / 20,094 settled messages (35%) | | after | 20,094 (100%) | | assistant messages before | 3,430 / 16,406 (21%) | A real query for `worktree` goes from **138 to 187 threads**. All 425 threads with assistant text had *some* searchable row, so the symptom was a search quietly missing most of what was said, not one missing whole threads — which is exactly why it was hard to pin down. ## Scope - **Tool calls were never involved.** They are activities in `projection_thread_activities`, not rows in `projection_thread_messages`, so they stay out by construction. - **`system` notices** are now excluded explicitly rather than incidentally. - **Per-thread dedupe is unchanged**: `thread_match_rank = 1` still collapses a thread to one best row, preferring a user match, then the most recent. - **Streaming rows stay excluded** via the existing `is_streaming = 0`. ## Known limit A phrase that straddles a split boundary still will not match — each message row is matched independently, so "the quick brown" in one item and "fox" in the next is two rows, not one string. Fixing that means matching against a per-turn concatenation, which is a bigger change with its own cost; happy to do it as a follow-up if it matters in practice. ## Tests The existing test asserted the old behaviour outright — its fixture literally read `'Interim needle must not be searchable.'` — so that expectation is inverted here, and a split-answer case is added whose matching half is not the turn's `assistant_message_id`. Mutation-checked: restoring the old restriction fails both new assertions. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com> --------- Signed-off-by: aoright <102943475+aoright@users.noreply.github.com> Co-authored-by: Rodrigo Brechard <rodrigobrechard@gmail.com> Co-authored-by: Rodrigo Brechard <rodrigo@clubtidy.fr> Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: codex <codex@users.noreply.github.com> Co-authored-by: Bilal Bakr <62337003+Bil0000@users.noreply.github.com> Co-authored-by: Eddy Naboulet <93473191+eddy-naboulet@users.noreply.github.com> Co-authored-by: maria <maria@kuuro.net> Co-authored-by: Wout Stiens <71498452+StiensWout@users.noreply.github.com> Co-authored-by: Pavlo Trinko <paul.trinko95@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> Co-authored-by: Chris Deeming <chris@xenforo.com> Co-authored-by: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> Co-authored-by: Francisco Arredondo <95440147+frarredondo@users.noreply.github.com> Co-authored-by: Shivam Sharma <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Nitay Rabinovich <nitayr@wix.com> Co-authored-by: Lars Nieuwenhuis <35393046+lnieuwenhuis@users.noreply.github.com> Co-authored-by: Tristan Knight <admin@snappeh.com> Co-authored-by: Nick Anisimov <n.anisimov.23@gmail.com> Co-authored-by: Maslin Edwin <maslinje@gmail.com> Co-authored-by: aoright <102943475+aoright@users.noreply.github.com> Co-authored-by: Guilherme Barros <gbarros1095@gmail.com> Co-authored-by: Rishet11 <154429365+Rishet11@users.noreply.github.com> Co-authored-by: Augie <augie@luebbers.email> Co-authored-by: Taras <Taras.Fomin@gmail.com> Co-authored-by: Gianmarco <gianmarcosimone89@gmail.com> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: Inaya Yousfi <zied.essaber@gmail.com> Co-authored-by: maria <254055478+maria-rcks@users.noreply.github.com> Co-authored-by: Rakshith Bhat <88523594+RakshithBhat03@users.noreply.github.com> Co-authored-by: GPT-5.6 <noreply@openai.com> Co-authored-by: David Balderston <dbalders@gmail.com> Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Co-authored-by: Luis Gustavo Couto Wacker <luis.wacker@pagar.me> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> 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>
## Why Sentry short ids (`SCANNER-313`) have the same shape as Jira keys (`PROJ-123`). The Discord bot extracted those tokens from sentry.io URLs and Sentry alert embeds, pinned them under **Jira**, and injected `jira: SCANNER-313` into agent turns — so the agent treated an obvious Sentry issue as a Jira ticket. ## What - Do not treat sentry.io URLs, Sentry-bot authors, or Sentry Discord embeds as Jira. Atlassian browse / `selectedIssue` URLs are still extracted. - Drop already-stored false positives on pin refresh and backfill (and skip mining our own Omegent Info pin, which echoed the misclassified key). - Persist sentry.io issue URLs and render them as **Sentry** on the thread-info pin (above Jira). ## Test plan - [x] `vp test run` jiraLinks, sentryLinks, threadInfoPin, ThreadLinkStore, threadContext, MentionRouter - [x] `apps/discord-bot` typecheck - [ ] After deploy: Sentry alert / pasted `https://*.sentry.io/issues/SCANNER-313` should pin **Sentry**, not **Jira** opened by [Patrick Roza](https://discord.com/users/95218063095377920) in chat thread **Discord** · [what happened here?](https://discord.com/channels/1083767712431480922) --------- Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
…#414) ## Summary Omegent on t3vm failed with `T3 did not become ready after a server restart` because the Discord bot re-exchanges `local-bootstrap-credential` on every process start, and that grant was seeded with the **desktop 24h TTL**. After `t3code-server` had been up more than a day, a bot-only restart (or a deploy that restarted only the bot) looped `invalid_credential` forever. - Keep the desktop IPC bootstrap seed at 24h. - Seed the file-backed local grant with a long-lived TTL (colocated trusted clients). - Persist the 30-day bearer under the bot data dir and reuse it on the next start; clear and re-bootstrap if T3 rejects it. - Also include basename asar unpack globs (`*.node` as well as `**/*.node`) so `packWindowsServerAsar` still creates `server.asar.unpacked` on hosts where `@electron/asar` 3.4 does not treat `**` as nested. ## Test plan - [x] `PairingGrantStore` local-file grant still consumes after 25h and 400d - [x] Desktop IPC grant still expires after 24h - [x] Persisted bearer reuse / host mismatch / remaining-time floor / disk round-trip - [x] T3Session existence contract for persist + invalid_credential fallback - [x] `build-desktop-artifact` Windows asar unpack tests - t3vm: rebuilt dist, restarted server then bot; new Discord bot session issued 2026-08-20 06:49 UTC and HTTPS `/` is 200 again --------- Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
…ap (#418) `/omegent today-recap` posted the ack twice (channel starter + slash reply) and opened a thread with no recap in it until/unless the agent finished — so the thread looked empty. ## What - Open one public thread with no starter message - Slash ack is ephemeral (jump only) - Recap is the only public bot message, inside that thread - Mention-in-channel still threads off the mention; mention-in-thread only posts a jump, not a second ack opened by [joshuadima](https://discord.com/users/593167616273809448) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1539325452873769041/1539325452873769041) · [T3](https://t3vm.tail86038f.ts.net/?thread=1c8e37cb-722d-405e-8071-5c8c3cd159fe) Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Joshua Dimaunahan <170177550+MindfulLearner@users.noreply.github.com>
Working + Stop stays stuck above human chat when a later Tasks post is the channel tip, and heartbeat refused to hop during tool-only phases. Scan recent messages for humans after Working (not just the latest message). Hop by creating the replacement Working bubble first, then deleting the original so the live tip actually moves below the humans — no frozen copy left above. opened by [patroza](https://discord.com/users/95218063095377920) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1540285630255464518/1540285630255464518) · [T3](https://t3vm.tail86038f.ts.net/?thread=0b72e901-c83f-42cc-9e69-f51de4531c88) --------- 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>
…ad (#422) `/omegent today-recap` opened a new Discord thread and posted nothing into it until the turn finished, so the thread showed Discord's empty-state copy. ## What - Do not create a Discord thread - Public deferred slash reply in the channel you ran the command in - Recap edits that one message (extra chunks if over 2000 chars) - Mention path replies in the same channel opened by [joshuadima](https://discord.com/users/593167616273809448) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1539325452873769041/1539325452873769041) · [T3](https://t3vm.tail86038f.ts.net/?thread=1c8e37cb-722d-405e-8071-5c8c3cd159fe) Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Joshua Dimaunahan <170177550+MindfulLearner@users.noreply.github.com>
Classic-merge 121 upstream commits (pingdotgg/t3code through 06de9e9) into fork/dev so the deploy branch keeps upstream as a second parent.
… weld Keep queue-bound mobile sends from scrolling, accept Codex localMessages on the steered feed, land inactive pins in the settled recency section (pingdotgg#7969), and keep send-disabled covering both feedback uploads and loading messages.
Windows workspace paths must go through classifyMarkdownImageSource so relative and drive-letter forms keep their signed-asset paths. The fork normalizer only covers Codex `attachment:` / generated_images URIs the shared classifier blocks.
Keep clearing the session before provider interrupt, then still record a failed interrupt unless a newer ready snapshot won the race. Tests now expect migrations 041/042, Claude /compact, ACP runtime item ids, and bootstrap thread.delete on worktree failure.
The new upload-queue tests mocked `@t3tools/client-runtime/state/runtime` without spreading the real module. Under the fork's isolate:false unit project that incomplete mock leaked into PullRequestListFilters.
merge: sync upstream through 06de9e9 (121 commits)
## Why Fork CI on the #423 merge SHA (`1b3f2f52e`) failed its **Test** job while Check / Release Smoke / Mobile Native / Upstream Lineage Guard were green. The only failure was the pingdotgg#8006 perf assertion: `session-logic.test.ts > session activity performance > updates 20,000 ordered tool activities within 100 ms` `AssertionError: expected 139.01 to be less than 100` That merge tree is identical to the last green PR tip (`2efc0552e`). Same code, noisier GitHub-hosted runner. ## What - Skip the copy+sort in `deriveWorkLogEntries` when activities are already ordered (the streaming-append path ChatView actually hits). - Widen the budget from 100ms to 250ms. That still fails a quadratic rebuild; 100ms was too tight for this runner class. ## Test plan - [x] `vp test run apps/web/src/session-logic.test.ts -t "orders work log by activity sequence|session activity performance"` - [ ] Fork CI Test on this PR / then on `fork/dev` after merge Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Classic-merge 11 upstream commits (pingdotgg/t3code through a3a8cbd) into fork/dev so the deploy branch keeps upstream as a second parent.
ProjectionThread gained required unsettledAt from upstream 043; the fork fixture used by WorktreeLifecycle tests still built rows without it.
The last-N assertions on the independent upstream ledger still ended at 042. 043_ProjectionThreadsUnsettledAt is a true upstream migration.
Those tests mock useAssetUrlState. Under isolate:false ChatMarkdown is already bound to the real asset URL atom, so useAtomValue() is null and the signed-URL cases throw on `_tag`.
The suite mocks ~/localApi. Under isolate:false the module is already bound, so confirm never hits the mock and pending-state assertions fail.
merge: sync upstream through a3a8cbd (11 commits)
## Problem `.githooks/post-checkout` deletes `apps/*/dist` on every branch checkout. The production server serves `apps/server/dist/client` live from disk, so a Discord-only deploy's `git switch` immediately returns **Web assets unavailable** (HTTP 503) until something rebuilds the tree. ## Fix Skip `apps/server/dist` in the emit wipe. Still clear other `apps/*/dist`, `dist-electron`, `packages/*/dist`, and `*.tsbuildinfo`. ## Test plan - [x] Harness: server dist preserved; web/package dist removed - [ ] After merge + deploy: Discord-only promote no longer 503s `https://t3vm.tail86038f.ts.net/` opened by [andreasimonecosta](https://discord.com/users/446049435810791424) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1536393400130076773/1536393400130076773) · [T3](https://t3vm.tail86038f.ts.net/?thread=28d099c3-603c-4659-bdac-b87fb8d03261) --------- Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Andrea Simone Costa <24520167+jfet97@users.noreply.github.com> Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
… status (#427) ## Why `/omegent today-recap` looked stuck on Discord’s deferred “ci sto lavorando…” spinner because the slash only edited the thinking message after the T3 recap turn finished. The recap that did land was hard to read: jargon, `###` type headings, Discord’s 2000-char split cut [PR pingdotgg#1880](https://github.com/macs-holding/scanner/pull/1880) in half, and related PRs (1880 merged + 2273 open follow-up) repeated the same Packmittel story twice. ## What - Edit the deferred slash reply immediately with `Writing today's recap of \`<repo>\` (YYYY-MM-DD UTC)…`. - Log recap start, T3 thread id, settle, timeout, and working-status webhook failures. - Treat `latestTurn.state === "error"` as terminal. - Recap prompt: `(fix)` / `(feat)` on the PR line, plain-language what/why, spell out shop-floor terms. - Related PRs (same change, follow-up, or a first try closed because a later PR handled it) are one history block; do not list those PRs again. Unrelated closed PRs stay in CLOSED. - Split follow-up Discord messages on blocks, not mid-sentence. ## Test plan - [ ] `/omegent today-recap` replaces “thinking” with the working status within a second, then the recap. - [ ] Recap uses `(fix)` / `(feat)` next to each heading `PR #N`. - [ ] Related PRs appear once (history under the latest status); unrelated closed PRs only under CLOSED. - [ ] A recap longer than 2000 characters does not split a block in half. - [ ] Bot journal shows `today-recap starting T3 turn` / `today-recap T3 thread started` / `today-recap T3 turn settled`. Scanner tickets referenced in the recap format discussion: [SA-437](https://macs-holding.atlassian.net/browse/SA-437) · [SA-449](https://macs-holding.atlassian.net/browse/SA-449) · [SA-438](https://macs-holding.atlassian.net/browse/SA-438) opened by [joshuadima](https://discord.com/users/593167616273809448) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1539325452873769041/1539325452873769041) · [T3](https://t3vm.tail86038f.ts.net/?thread=1c8e37cb-722d-405e-8071-5c8c3cd159fe) --------- Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Joshua Dimaunahan <170177550+MindfulLearner@users.noreply.github.com>
Discord turns inject linked Jira keys as context. Agents treated that as a request to post completion summaries on the ticket (example: unsolicited Omegent comment on [SA-438](https://macs-holding.atlassian.net/browse/SA-438), now deleted). Reply only on the originating surface unless the user explicitly asked. Opening a GitHub PR for landable work is still allowed; commenting on Jira/GitHub/Confluence is not. ## Test plan - [x] `vp test run` threadContext + T3AgentRules - [x] changed-file `vp check` - [ ] After deploy: a Discord turn that mentions a Jira key must not comment on the issue unless asked opened by [enricopolanski](https://discord.com/users/147977704522645504) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1542173337164447804/1542173337164447804) 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>
Classic-merge pingdotgg/t3code main into fork/dev (4 commits). 3-way weld where Grok work overlapped: keep fork Kimi usage, Direnv, session-mode pinning, and mid-session set_model; take upstream Grok Build transcript scanning, permission-mode spawn args, skills, and ACP reliability.
merge: sync upstream through ead4ce5 (4 commits)
Related follow-ups stay inside the latest PR's paragraph. Drop "landed today". Co-authored-by: Joshua Dimaunahan <170177550+MindfulLearner@users.noreply.github.com>
Replay bootstrap now updates the worktree path before the duplicate thread.create. Made-with: Grok 4.6 (xhigh) in T3 Code
PullRequestDetailPanel always mounts the checks popover, and the summary tab mounts the reaction picker on comments. react-test-renderer has no Element/window, so CI failed 29 tests with floating-ui errors. Isolate the files so the mocks cannot be stolen under isolate:false.
sync: classic-merge upstream/main (56a9bf2) into fork/dev
…44293 # Conflicts: # pnpm-lock.yaml
Upstream pingdotgg#12326 committed the placeholder `set this to true or false`, which Schema.Boolean rejects. Desktop artifact publish then failed on every 30s poller retry and Discord treated each timestamped journal line as a new failure. Keep the native addon allowed to build.
sync: classic-merge upstream/main (52e4b44) into fork/dev
) After the Effect 4.0.0-rc.115 weld, Omegent looks healthy (REST slash registration, rehydrate) but **never receives Discord gateway events**. `dfx` 1.0.15 still does `writeRaw = yield* socket.writer` then `writeRaw(...)`. On rc.115 that throws `TypeError: writeRaw is not a function` (`DiscordWS.ts:75`), shard count stays 0, and mentions/slash go nowhere. Bump catalog `dfx` **1.0.15 → 1.0.16** (`writer.write` + `reader.pull`). Test asserts the installed dfx is 1.0.16+. Guest evidence on `t3code-discord-bot` at `d16d055996`: error at 10:27:14 UTC, then zero `MESSAGE_CREATE` while archived-thread REST noise continues. Restart-only will not fix this. After merge the poller will deploy discord. Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Fork CI on `b4ad10f8` (dfx 1.0.16) failed twice on all 11 `BoardCard` tests: `No \"environmentServerConfigsAtom\" export is defined on the \"../../state/server\" mock` BoardCard now opens PRs through `useOpenPrLink` → that atom. Under `isolate: false`, `UsagePage.refresh.test.tsx` binds a stub `state/server` mock first and poisons BoardCard. That red push job blocks the poller from deploying the Discord gateway fix. Isolate BoardCard and the stub mock so they cannot share a module registry. Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
…3c149 # Conflicts: # .agents/skills/test-t3-app/SKILL.md # .agents/skills/test-t3-mobile/SKILL.md # .github/VOUCHED.td # apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx # apps/mobile/src/features/home/HomeHeader.tsx # apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx # apps/mobile/src/features/threads/ThreadRouteScreen.tsx # apps/mobile/src/features/threads/thread-list-items.tsx # apps/mobile/src/features/threads/thread-list-v2-items.tsx # apps/mobile/src/native/StackHeader.tsx # apps/server/src/mcp/PreviewAutomationBroker.ts # apps/server/src/orchestration/Layers/ProviderCommandReactor.ts # apps/server/src/persistence/Layers/ProjectionThreads.ts # apps/server/src/persistence/Services/ProjectionThreads.ts # apps/server/src/pullRequest/PullRequestService.ts # apps/server/src/server.test.ts # apps/server/src/textGeneration/TextGeneration.ts # apps/server/src/vcs/GitVcsDriver.test.ts # apps/server/src/vcs/VcsProcess.ts # apps/server/src/ws.ts # apps/web/src/components/BranchToolbar.tsx # apps/web/src/components/GitActionsControl.tsx # apps/web/src/components/ProjectScriptsControl.tsx # apps/web/src/components/Sidebar.tsx # apps/web/src/components/chat/ChatHeader.tsx # apps/web/src/components/chat/ComposerBannerStack.tsx # apps/web/src/components/chat/MessagesTimeline.tsx # apps/web/src/components/chat/OpenInPicker.tsx # apps/web/src/hooks/useThreadActions.ts # packages/contracts/src/ipc.ts # packages/contracts/src/providerRuntime.ts # packages/contracts/src/vcs.ts # pnpm-workspace.yaml
ThreadStatusPresentation only has StatusTone + kind/pulse. The weld left iconColor/iconBackground on plan-ready and typecheck failed.
Fork ElectronApp.Service only exposes setAsDefaultProtocolClient. Upstream's harness field does not exist on the service type.
Schema mapFields is a value; use its Type for row decode. Fork ledger
tests still called removed NodeSqliteClient.layerMemory — use
layer({ filename: ':memory:' }) like upstream migration tests.
…oser banners Archive undo tests hit previewWorktreeCleanup without a mock; optional-chain the tagged result so a missing preview degrades to a plain archive. Isolate composer banner tests so a stub Button mock cannot steal buttonVariants.
sync: classic-merge upstream/main (1de563c) into fork/dev
…7b73a # Conflicts: # apps/mobile/app.config.ts # apps/mobile/src/Stack.tsx # apps/mobile/src/features/home/HomeHeader.android.tsx # apps/mobile/src/features/home/HomeHeader.tsx # apps/mobile/src/features/home/HomeHeader.types.ts # apps/mobile/src/features/home/HomeRouteScreen.tsx # apps/mobile/src/features/home/HomeScreen.tsx # apps/mobile/src/features/home/home-list-filter-menu.test.ts # apps/mobile/src/features/home/home-list-filter-menu.ts # apps/mobile/src/features/home/home-list-options.test.ts # apps/mobile/src/features/home/home-list-options.ts # apps/mobile/src/features/home/homeListItems.test.ts # apps/mobile/src/features/home/homeListItems.ts # apps/mobile/src/features/home/homeThreadList.ts # apps/mobile/src/features/threads/ThreadDetailScreen.tsx # apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx # apps/mobile/src/features/threads/ThreadRouteScreen.tsx # apps/mobile/src/features/threads/thread-list-items.tsx # apps/mobile/src/features/threads/threadListV2.ts # apps/mobile/src/features/threads/threadPresentation.ts # apps/mobile/src/persistence/mobile-preferences.ts # apps/server/src/ws.ts # apps/web/src/components/BranchToolbarBranchSelector.tsx # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/LegacySidebar.tsx # apps/web/src/components/ProjectScriptsControl.tsx # apps/web/src/components/Sidebar.tsx # apps/web/src/components/ThreadStatusIndicators.tsx # apps/web/src/components/chat/MessagesTimeline.tsx # apps/web/src/components/chat/OpenInPicker.tsx # apps/web/src/components/chat/ProviderStatusBanner.tsx # apps/web/src/components/chat/ThreadErrorBanner.tsx # apps/web/src/components/ui/scroll-area.tsx # packages/contracts/src/settings.test.ts # packages/contracts/src/settings.ts # pnpm-lock.yaml
PopoverPopup dropped viewportClassName; Button size owns padding/type.
Full vp check lints the whole tree. Fork board/jump/identity/host status still restyled SidebarInset, Spinner, TooltipPopup, DialogPanel.
HomeHeader uses title=\"Ownership\" on NativeHeaderToolbar.Menu, not the object form title: \"Ownership\".
Incoming t3.json submodule-init setting matches \"work\" and must stay in the catalog list.
sync: classic-merge upstream/main (829af7b) into fork/dev
Grok extra ACP prompt parts (`<runtime_info>`, `<pull_request_linking>`) were persisted as user-role text. The Discord bridge treated that as t3-client input and posted the raw harness instructions as `💭 from **unknown@unknown**`. Classify those envelopes as internal scaffolding so they are not mirrored, and strip them from echoed text as a fallback. Pushing this branch required the current `fork/dev` typecheck unblocks: ChromiumCookies yield* union, updates harness feed types, HostPowerMonitor / NativeTelemetryClient Option.match. grok-4.6 / Grok harness opened by [Patrick Roza](https://discord.com/users/95218063095377920) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1552207449409200192/1552207449409200192) · [T3](https://t3vm/?thread=02e592b7-34fe-4b0f-bf3f-651f0883c29f) [(.)](t3code://t3vm/?thread=02e592b7-34fe-4b0f-bf3f-651f0883c29f) --------- 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>
## Summary GitHub, Discord, and Teams refuse anyone who is not on the identity map. They cannot start, continue, stop, or approve a T3 thread. Jira uses the same gate for the agent. An unmapped Jira account can still leave a context note on a thread that is already linked. That note does not start or continue the agent. Teams people are matched by `teamsAadObjectId` (Azure AD object id / Graph `from.user.id`) or `teamsUserId` (Bot Framework `29:…` id). An empty map denies everyone. ## Test plan - [x] Identity map, Teams actor, and Jira trust tests - [x] Changed-file check and typecheck on the first push - [ ] After deploy, an unmapped Teams user cannot open or continue a thread; an unmapped Jira user can leave a context note on an already-linked thread and cannot run the agent grok-4.7 / Grok harness --------- Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
) ## Problem Browser automation broke in the desktop app. `preview_status` and `preview_open` succeeded, but `preview_snapshot`, `preview_navigate`, `preview_evaluate`, `preview_wait_for` (and click/type/press/scroll/color scheme/recording) failed with `PreviewAutomationExecutionError`. Desktop traces show the actual cause: ``` PreviewTabNotFoundError: Preview tab not found: tab_1 PreviewWebviewNotInitializedError: Preview tab "tab_1" has no webview registered ``` ## Root cause Upstream moved desktop preview tabs to a runtime identity: `previewRuntimeTabId(threadRef, serverEpoch, tabId)`. An upstream merge into the fork kept a stale fork copy of `PreviewAutomationHosts.tsx`. In that copy, `status` and the overlay-ready wait use the runtime id, but every other bridge call still passes the bare server id (`tab_1`). So status reports a healthy tab while everything else misses it in the desktop `PreviewManager`. This is unrelated to the Discord browser host. The failing client was the desktop renderer host (`preview-…`), not `discord-browser-*`. ## Fix - Restore `PreviewAutomationHosts.tsx` from the last merged upstream commit (`829af7b73a`). That brings back runtime ids everywhere, the viewport rollback, the presentation settle, and the shared `waitForNavigationReadiness`. - Keep the one intentional fork change: `resolveNavigableUrl` for `open`/`navigate`. - I checked every other file that uses `runtimeTabId`; none diverge from upstream. ## Tests The new test `PreviewAutomationHosts desktop operations` checks that a `snapshot` request reaches the desktop bridge with the runtime tab id. It fails on the current `fork/dev` file and passes with this change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
#484) Fork CI on `ce3ef6b4` (#483) failed all four `citation comment source disappearance` tests in `AssistantCitationChip.test.tsx` with `TypeError: Cannot read properties of null (reading 'isServer')` from the real TanStack `Link`. The file mocks `@tanstack/react-router`, but in the `unit` project (`isolate: false`) a sibling file can bind the real module first. The file passes on its own, and the failure depends on test order, the same hazard already documented for the other entries in `isolatedUnitTestFiles`. This PR moves the file into the isolated project. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tream pingdotgg#10982) (#485) Imports the open upstream PR pingdotgg#10982 (by @Mnigos), which fixes the accepted upstream bug pingdotgg#10980: an agent's `preview_click` leaves keyboard focus inside the preview page, so the user's typing and pastes go to the page, even for hidden `open: false` tabs. ## Provenance - Source: pingdotgg#10982, commits `5d24187dd3`, `b577a8380f` and `a2e44cd6c2`, squashed into one commit. - Imported unchanged: `apps/desktop/src/preview/Manager.ts` and `Manager.test.ts`. The test file needed a 3-way merge but no changes. - Nothing adapted or excluded. It adds no migrations. ## Change The click path now saves and restores the previously focused WebContents through a `restoreFocusedWebContents` helper it shares with `preview_press`. The restore runs whether the click succeeds or fails. It does nothing if focus moved to another renderer during the action or the user switched to another app. ## Tests Upstream's new Manager tests are included. All 93 tests in `src/preview/Manager.test.ts` pass locally. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Mnigos <makowskiigor@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Grok/ACP often opens a second assistant id with the same body. Discord treated that as a new bubble, finalized again, and the stats footer changed so accept-without-ack could not adopt the first post. Drop later assistants whose text matches the already-posted final, collapse consecutive duplicate bubbles, and ignore stats/T3 footers when matching an already-landed Discord final. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
patroza
force-pushed
the
fork/dev
branch
4 times, most recently
from
October 3, 2026 10:00
80434dc to
fc6701e
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Grok/ACP often opens a second assistant id with the same body. Discord treated that as a new bubble, posted another final, and the stats footer (
37s · 149kvs31s · 157k) meant accept-without-ack could not adopt the first message.Drop later assistants whose text matches the already-posted final, collapse consecutive duplicate bubbles, and ignore stats/T3 footers when matching an already-landed Discord final.
grok-4.6 / Grok harness
opened by Patrick Roza in chat thread Discord · Stop echoing Grok runtime_info · T3 (.)