Skip to content

feat(hub-zero)!: T5c mailbox refs are tenants; invitable definitions walk ancestors (CL-8149) - #757

Merged
TheGreatAxios merged 4 commits into
mainfrom
cl-8149-hub-zero-t5c
Sep 17, 2026
Merged

TheGreatAxios merged 4 commits into
mainfrom
cl-8149-hub-zero-t5c

Conversation

@TheGreatAxios

@TheGreatAxios TheGreatAxios commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

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 resolveRefs stamps senderAuthorization.tenantId — the tenant authorizeSender already resolved from the sender run's address, and the tenant the principal_mail rows are scoped under anyway. Deleted with it: the ChatStore/RoomMessageStore seam, resolveWorkbenchIdForAgentFrame, the In-Reply-To/References header walk and the participant-scan fallback. The factory is now a plain hubMailboxResolveRefs function.

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, postRoomMessage had no call site left in apps/hub/src.

3. Two unresolvable chat-ui test imports fixed — ConnectGithubBlockData and ToolTracePart still pointed at @corbits/chat/blocks and @corbits/chat/parts after T5b moved the wire types into packages/chat-ui/src/wire. @corbits/chat is not a chat-ui dependency, so bun run typecheck was red on main before 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 listInvitableDefinitions reads the whole ancestor chain (getAncestorChain from @intx/db — the same walk credential and catalog resolution already perform) instead of the eq(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's echo shadows the root's; the root's researcher is 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/chat is 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:

module lines consumed by
platform-adapter.ts (createHubChatPlatform) 1645 sidecar mail redelivery, settleConnectedService (connections), artifact delivery, workflow-participant routes, idle-sleep lifecycle
chat-orchestrator.ts 1680 the hub's whole turn intake
agent-turns.ts, turn-queue.ts, turn-claims.ts, write-claims.ts, client-ids.ts, turn-mail-correlation.ts ~1500 turn execution, still writing chat.* tables
routes.ts (the actual chat HTTP surface) 4111 ${TENANT_PREFIX}/chat only

Beyond that, chatConditionRegistry (built from @intx/authz's timeWindowEvaluator in apps/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:

  • T5c-i (this PR): mailbox refs are tenants; dead imports; typecheck unbroken.
  • T5c-ii: move the non-chat machinery out of packages/chat — the platform adapter, orchestrator and turn stores into a package that is not named for the product surface, and chatConditionRegistry into the hub's own authz wiring. No behavior change.
  • T5c-iii: cut 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.
  • T5c-iv: delete packages/chat, forward-drop chat.*, clear db-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.ts actually 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 on main)
  • bun run lint — green (9 pre-existing warnings)
  • bun run check:structural — 0 fail
  • bun --cwd apps/web test — 919 pass, 0 fail
  • bun --cwd packages/chat-ui test — 909 pass, 0 fail
  • bun --cwd packages/chat test — 893 pass, 0 fail
  • Hub boot with HUB_DATA_DIR=$(mktemp -d) against Postgres — serves on port, migrations run
  • apps/web production build — green (via check: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 on 53300 sorry, too many clients already, including the fixture's own insert into tenant. CI runs it.

https://claude.ai/code/session_01RweuMUskU2nvcFhdckc7EG

@linear-code

linear-code Bot commented Sep 17, 2026

Copy link
Copy Markdown

CL-8149

@TheGreatAxios TheGreatAxios changed the title feat(hub-zero)!: T5c mailbox refs are tenants; packages/chat delete is not one slice (CL-8149) feat(hub-zero)!: T5c mailbox refs are tenants; invitable definitions walk ancestors (CL-8149) Sep 17, 2026
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
TheGreatAxios merged commit 8e853c7 into main Sep 17, 2026
20 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant