fix(agents): derive conversation scope from trusted group facts#99816
Conversation
Scope fell back to caller-supplied groupId/groupChannel/groupSpace when chatType was unknown, while the profile publishes those same fields trust-checked (null when dropped). A dropped caller group could classify an unknown-audience conversation as shared for downstream audience and credential decisions. Scope now classifies only from live chat type, server-derived session keys (new sessionKeyNamesGroupConversation), and trust-checked group facts; dropped groups resolve to unknown.
|
Codex review: needs real behavior proof before merge. Reviewed July 4, 2026, 1:12 AM ET / 05:12 UTC. Summary PR surface: Source +35, Tests +54. Total +89 across 3 files. Reproducibility: yes. from source inspection: a DM session with caller-supplied group facts is trust-dropped for published group fields, while current main still lets raw group fields make Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land this narrow central profile fix if maintainers agree with the trust precedence, then let the dependent identity and credential PRs consume the corrected scope semantics. Do we have a high-confidence way to reproduce the issue? Yes from source inspection: a DM session with caller-supplied group facts is trust-dropped for published group fields, while current main still lets raw group fields make Is this the best way to solve the issue? Yes: centralizing masked group facts and session-key precedence inside the capability profile is the narrowest maintainable fix. Per-caller fixes would duplicate the trust check and are more likely to drift. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 8822b66952b7. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +35, Tests +54. Total +89 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…claw#99816) Scope fell back to caller-supplied groupId/groupChannel/groupSpace when chatType was unknown, while the profile publishes those same fields trust-checked (null when dropped). A dropped caller group could classify an unknown-audience conversation as shared for downstream audience and credential decisions. Scope now classifies only from live chat type, server-derived session keys (new sessionKeyNamesGroupConversation), and trust-checked group facts; dropped groups resolve to unknown.
Summary
ResolvedConversationCapabilityProfile.conversation.scopenow classifies the conversation audience exclusively from server-verified or trust-checked inputs, in this precedence:direct->direct;group/channel->shared.runSessionKeyorsessionKeynames a group/channel conversation (newsessionKeyNamesGroupConversationhelper insrc/agents/agent-tools.policy.ts), scope issharedeven without a live chat type. This also covers runs whose policy key is a sandbox alias while the live run session is a group.resolveTrustedGroupIdvouched for them. When the trust check dropped the caller group id, scope resolvesunknowninstead ofshared.Previously the fallback branch (no usable chat type) read the raw caller-supplied
groupId/groupChannel/groupSpaceparams, while the same profile published those fields trust-checked (nullwhen dropped). An unvouched caller-controlled group value could therefore classify an unknown-audience conversation assharedin the exact field that conversation identity modes (#98542) and scoped brokered credentials (#98549 / #98707) are specified to consume for audience and credential decisions. The profile also now computes the maskedgroupChannel/groupSpaceonce and reuses them for group-policy resolution, the published conversation fields, and scope, so the three can no longer diverge.conversation.scopehas zero consumers on current main (verified by grep acrosssrc/,extensions/,packages/), so the semantics change is contract-safe now and becomes the guaranteed baseline before the first consumers land.Proof (local)
pnpm tsgoclean.pnpm vitest run src/agents/conversation-capability-profile.test.ts— 6 passed, including new regressions:scope: "unknown", published group fieldsnull;shared;shared;shared,dropped: false.oxfmt --checkclean on touched files.Non-goals
resolveTrustedGroupIdsemantics; only scope classification and shared computation of the already-masked fields.sessionKeyNamesGroupConversationis an internal helper.