feat(asks): an ask raised during a Workspace chat turn attaches to that chat (ent#734) - #3137
Merged
Merged
Conversation
…at chat (Abilityai/trinity-enterprise#734) Every addressed ask was filed under the pair's Main chat because nothing at raise time knew which execution raised it. The native raise now hands the platform-injected execution id (#2392, validated as the agent's own) to `_workspace_thread_for`; `client_portal.service.chat_for_execution` returns that turn's chat iff the row is a Workspace chat turn (`triggered_by="public"`, `source_channel="portal"`) of the same agent and addressee and the session belongs to that pair. The link is the one both portal creation sites already stamp (ent#457/#2426), so no column and no migration. Everything else keeps Main, unchanged: schedules (including one delivering into the Workspace, which carries the portal stamp), loops, rooms, delegated children, gate raises, no/unknown/foreign executions, another addressee's chat, and every file-ingested ask (an agent-cited execution id is never read). Fail-soft: a lookup failure attaches to Main with a warning. The ent#429 strip of an agent-authored workspace_session_id stays. Data half only (AC 1, 4, 5); the chat tile and the ended marker (AC 2/3) belong to #3101.
…#734 review r1) cso/review r1: the X-Trinity-Execution-Id header is platform-set, but the agent's own process holds its key and can send any of its executions' ids. chat_for_execution accepted any of them, so a finished turn of another chat (same addressee) could file an ask there. It now requires the turn to be RUNNING. The remaining bound — another live turn of the same agent for the same addressee — is the #2392 trust level turn_audience already accepts, and the docstrings/requirement no longer claim more than that. An archived (reset) Main is deliberately NOT excluded: it stays listed, readable and resumable, and Reset is refused mid-turn, so a running turn there is a person talking in a chat they can see. Pinned, with the email-case match (both mutation-checked).
… ask (ent#734 r2) After ent#734 a chat-turn ask raised in MAIN and a background ask (schedule / loop / gate) both carry chat_id = Main, but the ent#610 amendment draws the first as a tile in Main and the second in no chat, so #3101 could not tell them apart. The row now carries one more platform-written fact, context.workspace_raised_in_turn = true, written only when the raising turn's chat matched (`_workspace_attachment` returns `(chat, raised_in_turn)`; `_workspace_thread_for` stays as the file path's no-turn view). The client projection names it as WorkspaceAsk.raised_in_turn (only a literal true counts). Both workspace keys are now `_PLATFORM_CONTEXT_KEYS`: stripped from agent-authored context on the native and the file path, and ignored by the replay `differs` and the #2915 file-sync comparison, so a planted flag is neither honoured nor read as a rewrite. 8 named mutations, each red.
AndriiPasternak31
added a commit
that referenced
this pull request
Sep 30, 2026
…ent610-a2 (ent#610 PR A2 stacks on ent#734) # Conflicts: # docs/memory/feature-flows/workspace-agents-at-the-centre.md
…no frontend reads raised_in_turn yet, drop a repeated clause, _comparable_context docstring names both platform keys
AndriiPasternak31
added a commit
that referenced
this pull request
Sep 30, 2026
…hread; nothing sits above the composer (ent#610 PR A2, 09-30 ruling item 1) The ruling as amended the same day, on ent#734's data (#3137): an ask with raised_in_turn === true is drawn in the chat its chat_id names, as a row of the thread placed by time among the messages (portalChatAsks.placeAsksInThread: before the first row strictly newer than the ask; a row with no time of its own is a reply just received, so the newest; the person's own message is stamped as it is sent). While it waits it is the one PortalAsks card, answerable in place (thread link off: it IS in its chat). An ask seen waiting on this visit keeps its card after it ends (the ent#468 confirmation); any other ended ask is one muted history row: kind · title · ending with who · when. It stays for as long as the asks read returns it (7 days). A background ask (raised_in_turn false: schedule, loop, gate) draws in no chat, Main included; an unattached ask no longer falls to Main. Removed: the pinned splitChatAsks box above the composer and the "N more asks" line (principle 30), with splitChatAsks / pinnedAskIds / chatAsksLabel / chatAsksElsewhere. Their specs are rewritten for the new homes (round 4 §4, round 5, #3115 strip, B1 residual, single-source, agent-page-ux), not deleted. Mutations, each run once and restored from a scratch copy: M1 raised_in_turn truthy instead of === true -> 1 red M2 a tie places the ask before the row -> 1 red M3 an undated row is the oldest, not newest -> 1 red M4 seen-waiting ignored (ended = row at once) -> 3 red M5 the tile keeps "Open the conversation" -> 1 red M6 history rows lose their persisted time -> 2 red FE unit 4375/4375.
AndriiPasternak31
added a commit
that referenced
this pull request
Sep 30, 2026
…riiPasternak31/ent610-a2
AndriiPasternak31
marked this pull request as ready for review
September 30, 2026 22:11
Contributor
|
merge-train (#3143): on this train, merging second, right after #3054. /validate-pr and /review came back READY with no criticals. The tests run the real Edited for you: the |
# Conflicts: # docs/memory/feature-flows/workspace-agents-at-the-centre.md
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.
Refs abilityai/trinity-enterprise#734
Refs abilityai/trinity-enterprise#610
Data half of ent#734; the chat tile is drawn by #3101, which lands with or after this. Covers AC 1 (record the raising chat), AC 4 (platform-written, never agent-named) and AC 5 (the backend test). AC 2/3 (tile answerable in place, ended marker) are #3101's.
No migration taken. The execution↔chat link already exists: both portal turn-creation sites (and
portal_chat's cold retry) stampsource_channel="portal",source_channel_chat_idandsource_channel_clienton the execution row at creation (ent#457/#2426). No column, no Alembic revision, and no interaction with #3021's pending 0083.What changes
client_portal.service.chat_for_execution(agent, email, execution_id)(new): returns the turn's chat only if the row is this agent's running Workspace chat turn (triggered_by="public"+source_channel="portal"), its client is the addressee (case-insensitive), and the session belongs to that pair.operator_queue_service._workspace_thread_for(..., execution_id=None): tries that first, then falls back to the pair's Main, as before. Fail-soft: a lookup failure logs a warning taggedent#734and never raises (the bug: operator-queue create path has no rate limit or size caps — flooding/operator-fatigue surface (blocking pull default-ON) #1632 contract).chat_id = Main, but the ent#610 amendment draws the first as a tile in Main and the second in no chat. The row therefore also carriescontext.workspace_raised_in_turn = true, written only when the raising turn's chat matched._workspace_attachmentreturns(chat, raised_in_turn), and the flag is projected asWorkspaceAsk.raised_in_turn(only a literaltruecounts). This is the fact feat(workspace): Inbox asks UI + an ask's context (ent#610 PR A2: §3g L6 + L7) #3101 draws a tile from. Bothworkspace_*keys are_PLATFORM_CONTEXT_KEYS: they are stripped from agent-authored context on both paths and ignored by the replaydiffersand the bug(operator-queue): a pending approval can sit unseen for days — the human's card goes stale while the container↔platform sync stays silent #2915 file-sync comparison.ask_service.raise_ask: passes the platform turn (X-Trinity-Execution-Id, feat(pull): platform-injected execution id for the side-effect guard — Tier-6 T6.3, blocks default-ON for side-effect agents #2392) only forraised_by="agent". A gate raise keeps Main.triggered_byis checked);context.execution_idis never read);workspace_session_id.Trust bound (review r1)
The header is set by the platform, but the agent's own process holds its key and can send any of its executions' ids. After r1, the most a forged id can do is move an ask into another running turn of the same agent for the same addressee. That is the #2392 trust level
turn_audiencealready accepts. It can never reach another person's chat, another agent's chat, or a finished turn. The docstrings and §26.12 now say exactly this and no more. An archived (reset) Main is deliberately not excluded: it stays listed and resumable, and Reset is refused mid-turn.Tests
tests/unit/test_ent734_ask_raising_chat.py: 31 tests, written red-first.true; claim in-turn on the Main fallback.lint_sys_modulesis at its baseline.test_ent611_native_ask.py: the fixture now stubs_workspace_attachment, the new core.Docs