Repository navigation
feat(hub-zero)!: T5c mailbox refs are tenants; invitable definitions walk ancestors (CL-8149) - #757
Merged
Merged
Conversation
Two chat-ui test files still imported `ConnectGithubBlockData` and `ToolTracePart` from `@corbits/chat` subpaths after the wire types moved into `packages/chat-ui/src/wire`. `@corbits/chat` is not a chat-ui dependency, so both imports were unresolvable and typecheck failed. Claude-Session: https://claude.ai/code/session_01RweuMUskU2nvcFhdckc7EG
A workbench is a plain tenant, so the workbench a mail frame belongs to is exactly the tenant `authorizeSender` already resolved from the sender run's address. `resolveRefs` no longer chases a second id: the chat-store and room-message lookups, the `In-Reply-To`/`References` header walk and the participant-scan fallback behind them are all gone, and the seam is a plain function rather than a factory over two stores. The tests for the retired shape (no-participation stamps no ref, a header disambiguating two workbenches) go with it; the remaining suite asserts the tenant ref on every row. Also drops three imports the hub no longer uses at all: `localPartOf`, `parseParticipants` and `postRoomMessage`. Claude-Session: https://claude.ai/code/session_01RweuMUskU2nvcFhdckc7EG
A workflow definition deployed in a parent tenant is invitable from a child workbench like a plugin, so `listInvitableDefinitions` reads the whole ancestor chain — the same walk credential and catalog resolution already perform — instead of the workbench's own tenant alone. When an ancestor and a descendant both expose a definition of the same name, the descendant shadows the ancestor, matching how asset and catalog resolution already resolve a name across the chain. Visibility is all that is inherited. A grant is not: every participant and permission check stays scoped to the workbench tenant itself. Claude-Session: https://claude.ai/code/session_01RweuMUskU2nvcFhdckc7EG
TheGreatAxios
force-pushed
the
cl-8149-hub-zero-t5c
branch
from
September 17, 2026 17:46
beba7ee to
1de36dc
Compare
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.
What landed
1. The outbound frame's workbench ref is its own tenant (
apps/hub/src/mailbox-persist.ts)A workbench is a plain tenant, so
resolveRefsstampssenderAuthorization.tenantId— the tenantauthorizeSenderalready resolved from the sender run's address, and the tenant theprincipal_mailrows are scoped under anyway. Deleted with it: theChatStore/RoomMessageStoreseam,resolveWorkbenchIdForAgentFrame, theIn-Reply-To/Referencesheader walk and the participant-scan fallback. The factory is now a plainhubMailboxResolveRefsfunction.Tests of the retired shape are deleted (no-participation stamps no ref; a header disambiguating two workbenches). The rest of the suite asserts the tenant ref.
2. Three dead hub imports removed —
localPartOf,parseParticipants,postRoomMessagehad no call site left inapps/hub/src.3. Two unresolvable chat-ui test imports fixed —
ConnectGithubBlockDataandToolTracePartstill pointed at@corbits/chat/blocksand@corbits/chat/partsafter T5b moved the wire types intopackages/chat-ui/src/wire.@corbits/chatis not a chat-ui dependency, sobun run typecheckwas red onmainbefore this PR. It is green now.4. Invitable definitions walk the tenant ancestor chain (
packages/chat/src/platform-adapter.ts)Per the owner ruling: a definition deployed in a root/parent tenant is invitable from a child workbench like a plugin, so
listInvitableDefinitionsreads the whole ancestor chain (getAncestorChainfrom@intx/db— the same walk credential and catalog resolution already perform) instead of theeq(workflowDefinition.tenantId, tenantId)own-tenant filter it had. When an ancestor and a descendant both expose a definition of the same name, the descendant shadows the ancestor, matching asset and catalog resolution.Visibility is all that is inherited: grants are not. Every participant and permission check stays scoped to the workbench tenant itself — untouched by this change.
Covered by a new red/green case in
packages/chat/test/platform-adapter.test.ts(a child'sechoshadows the root's; the root'sresearcheris still invitable).What did NOT land, and why
The ticket asks to delete
packages/chat(27k lines) and forward-drop its tables. That is not one slice, and shipping a half-done version would take the agent runtime down.packages/chatis not only the chat product surface — it is where most of the hub's agent-run machinery currently lives, consumed by packages that have nothing to do with chat:platform-adapter.ts(createHubChatPlatform)settleConnectedService(connections), artifact delivery, workflow-participant routes, idle-sleep lifecyclechat-orchestrator.tsagent-turns.ts,turn-queue.ts,turn-claims.ts,write-claims.ts,client-ids.ts,turn-mail-correlation.tschat.*tablesroutes.ts(the actual chat HTTP surface)${TENANT_PREFIX}/chatonlyBeyond that,
chatConditionRegistry(built from@intx/authz'stimeWindowEvaluatorinapps/hub/src/index.ts) is threaded into ~20 non-chat route mounts — insights, webhooks, evals, inference-catalog, access-tools, credential sweeps. It is named for chat but owned by nothing chat-specific; it needs a home before the name can go.So the honest sequencing is:
packages/chat— the platform adapter, orchestrator and turn stores into a package that is not named for the product surface, andchatConditionRegistryinto the hub's own authz wiring. No behavior change.packages/chat-ui/src/api.ts(1400 lines, 100 exported functions, 105 source files, ~25 endpoint families) over to native mailbox reads, add the thread-list / thread-read / thread-SSE routes the mailbox mount is missing, drop the features with no native concept.packages/chat, forward-dropchat.*, cleardb-setup.ts/no-product-tenancy/ baseline / tsconfig refs / docs.Mapping table: still to implement in T5c-iii
The decided mapping is unchanged and none of it is implemented here. Note it is also incomplete — it does not cover five endpoint families that
chat-ui/src/api.tsactually calls:/stream(SSE),/presence,/turns+/turns/cancel, per-workbench/settings(chat/kind|name|purpose|pinned|contextWindow), and/bench/settings. Those need rulings before T5c-iii can be finished.Mailbox library asks (for
@corbits/mailbox)The mailbox mount has no thread-list, thread-read or per-thread SSE route. The timeline cutover needs all three; they belong on the mailbox mount, which is the one Workbench-owned surface that stays.
Verification run
bun run typecheck— green (was red onmain)bun run lint— green (9 pre-existing warnings)bun run check:structural—0 failbun --cwd apps/web test— 919 pass, 0 failbun --cwd packages/chat-ui test— 909 pass, 0 failbun --cwd packages/chat test— 893 pass, 0 failHUB_DATA_DIR=$(mktemp -d)against Postgres — serves on port, migrations runapps/webproduction build — green (viacheck:web-utilities, which builds it)apps/hub/test/mailbox-persist.test.ts(DB-gated) — not verified locally: the only reachable Postgres is shared with parallel agents and every run died on53300 sorry, too many clients already, including the fixture's owninsert into tenant. CI runs it.https://claude.ai/code/session_01RweuMUskU2nvcFhdckc7EG