TUI: add a safe home-agent rail with isolated thread state#658
Draft
TZZheng wants to merge 99 commits into
Draft
TUI: add a safe home-agent rail with isolated thread state#658TZZheng wants to merge 99 commits into
TZZheng wants to merge 99 commits into
Conversation
# Conflicts: # tui/internal/tui/ANATOMY.md
37 tasks
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.
Summary
This is the PR 5 milestone from #645: deliver the first selectable ordinary-Agent rail with target-bound cold thread state, durable unread discoverability, and the minimum safe width/input contract while Main remains aggregate temporarily.
Enterable.ProjectMailStore, global mailbox cache/snapshot, scanner, tick loop, and inventory lifecycle; selecting an ordinary Agent does not create or scan a second global cache.ThreadStatefor projection, send/reply, history, telemetry, editor, draft, focus, and generation.syncCurrentThreadFromMailprojection mirror in the same PR.Dependencies and stacked review shape
Depends on #646 and draft #652. Draft #652 itself depends on #648 and #649.
The prerequisite heads live in the contributor fork rather than as an upstream composition branch. This PR is therefore opened as a draft against
mainwhile those prerequisites remain open. GitHub's renderedmain...HEADview includes the prerequisite work as well as PR 5.Fresh pre-publication coordinates:
main:10c2822812add0ae07ed26ffcfff8d6cec202a4f356a5d3dd01c6c591077db4c1042ff8ae91d46589ce20516a52b5f5a992aecb1edfd341775b26329main...HEAD: 99 commits, 92 files, 14,756 additions, 642 deletions39bfd24f184b7f126c71c5b2e1b3fb2bfc6fc95caa069d796f559a5e366bebe0The independently attributable historical PR-5 implementation range is
64b601ea1c2e7238e171063f4a025630c5934a6e..fa65f856dab3a418b1cfa4cf8d72119871adaf99: 86 commits, 67 files, 8,953 additions, 274 deletions; binary patch SHA-256108dc9bfd31d63b6852d5f34afccff1f48312d94a9b4964fa6f0a559f36241e9.64b601ea..HEADis not a PR-5-only range after the branch integrated canonicalmain; it contains canonical bytes as well. After prerequisite PRs land, refreshing this draft may change source bytes. Any such change requires fresh exact-HEAD validation and both independent reviews again.Contract and implementation
One owner, bounded projections
ProjectMailStoreowns the one project-wide cache, accepted snapshot, scanner, scan mutex, refresh accounting, tick loop, and inventory view.ThreadStateowns only target-specific event/inquiry history, viewport, draft/pending editor state, and local generation. Ordinary activation rebinds the existing Mail presentation rather than constructing anotherMailModelor copying the global cache.Main uses
MainAggregateWriter; ordinary/direct/cold projections useNoPersist. The write gate is enforced inside the filesystem session cache, so caller intent cannot cause an ordinary projection to rewrite Main's aggregate session files.Fail-closed activation and publication
The rail is derived from accepted root inventory. Ordinary activation checks canonical directory, verified manifest address provenance, readability, accepted row identity, stale/phantom status, and existing path/PID safety before changing the active target. A stale accepted row schedules the existing root display-inventory refresh and preserves the prior thread/draft/focus/binding until a latest accepted replacement is installed.
Async completion is accepted only when its project/store, route, target, generation, source-cache identity, store version, and owner lifetime still match. Rejected work may settle its physical token, but cannot publish content or advance live/cached/durable unread state.
Layout and input
The root
LayoutBudgetremains the only horizontal partition owner. The 24-column rail is hidden when it would leave fewer than 60 chat columns:Render order and mouse hit-testing use the same partition. Keyboard and mouse share one activation path; paste remains chat-bound when chat owns focus; copy-mode keys/selections coexist with the rail; cross-project visits hide the home rail and cannot route rail input.
Durable unread
RailUnreadStorepersists exact max-timestamp ID sets so a new item at the same timestamp is still recognized after restart. Unread reconciliation runs only after accepted state publication. Stale completions, stale addresses, transient write failures, removal/re-add, hidden agents, and Mail re-entry preserve the last-good boundary instead of inventing success or resurrecting rejected content. All new status text is localized in en/zh/wen.Test-first and integration evidence
The committed history preserves real pre-implementation contract failures rather than syntax/import/environment failures. Representative boundaries include:
e7e5eca4before fix648c1169;f7e36515before fixcbad3539;fafad9c6before consolidation1cad3702;35b8e096before the original complete candidate54748f94;TestMainDoesNotOwnHumanLocationUpdateafter canonical integration3390033f, before the three-line ownership repair18a5ff3a.Coverage-only additions that passed on first semantically complete execution are recorded as coverage, not mislabeled as RED evidence.
Canonical integration and final release repairs
Canonical
mainadvanced while the original candidate was under review. The branch integrated it at3390033f; the real merged-tree normal suite then caught canonical startup's three-linefs.UpdateHumanLocationpath reintroducing a second updater outsideProjectMailStore. Commit18a5ff3aremoves exactly those three lines. Focused GREEN plus the coherent exact-head module gate established thatProjectMailStoreremains the sole production owner.The first exact-
18a5ff3aClaude review passed. Codex found no runtime defect but blocked release because two touched ANATOMY files still pointed locale/bootstrap/upgrade claims at semantically unrelated pre-launchertui/main.goranges. Commit356a5d3dchanges only:tui/ANATOMY.mdtui/internal/config/ANATOMY.mdThat delta is 15 additions / 15 deletions. Every non-document path and every other document path is byte-identical to fully tested
18a5ff3a. The corrected citations were checked semantically against current function and statement boundaries, not merely for numeric range validity.Validation
Compiled/tested candidate bytes at
18a5ff3agit diff --checkand clean merge-tree against canonicalmain;go test ./...;go test -race -p 1 ./...;go vet -p 1 ./...;go build ./...;All 15 TUI module packages passed normally and under the serial race detector. Empty diff/vet/build logs represent successful zero-output commands, not skipped checks.
Exact documentation HEAD
356a5d3d18a5ff3a..356a5d3ddelta: one commit, two Markdown files, 15 additions / 15 deletions;tui/main.gocitation occurrences in the two files (25 + 6) semantically audited;TestArchitectureEntryLinksPASS;git diff --checkPASS.A second full normal/race/vet/build run was intentionally not repeated after the docs-only commit: every compiled/tested input is byte-for-byte identical to the already gated
18a5ff3atree.Immediate pre-publication preflight
Canonical
mainwas fresh-fetched and remained exactly10c28228; the merge base remained canonicalmain, the merge-tree remained the candidate tree, issue #645 and prerequisite PRs remained open, the worktree remained clean, and no candidate branch or duplicate PR already existed remotely.Independent exact-HEAD reviews
sonnet/ high / plan-mode read-only:PASSat exact356a5d3d. It independently reproduced all coordinates/hashes and the two-file identity proof, audited every changed sentence and currenttui/main.gocitation against source, reran the architecture entry test, and found the previous documentation blocker resolved with no new runtime or navigation defect.gpt-5.6-sol/ high / read-only:PASSat exact356a5d3d. It independently reproduced all six controlling ranges and hashes, proved the exclusion diff empty, semantically audited all 31 citation occurrences and the location-update ownership seam, reran the architecture entry test, and found no critical/high/medium/release-blocking low issue.Any source or test byte change expires both verdicts.
Same-PR cleanup, bridges, and rollback
Removed in this PR:
MailModel;App.syncCurrentThreadFromMailand its reverse projection mirror;Planned bridges:
MainAggregateWriter: owner = the TUI: add a persistent per-project Agent switcher with isolated one-to-one chats #645 migration; reason = preserve safe aggregate Main while the first rail and durable unread establish the rollback boundary; expiry = PR 6;Rollback removes the rail and target switching and returns to one aggregate Main. PRs 1–4 may remain because they are behavior-preserving foundations. A failure in width/input, accepted-inventory activation, one-owner projection, or durable unread blocks PR 6.
Part of #645.