Repository navigation
feat(ai): list_maple_feedback, the Maple team's cross-org reader for agent feedback - #2330
Conversation
…agent feedback Agents file feedback through send_maple_feedback and POST /v2/agent_feedback, but nothing let the Maple team read it across orgs. AgentFeedbackService.triage reads every org's reports and refuses any caller org but MAPLE_INTERNAL_ORG_ID (fails closed when unset). The MCP tool also refuses Maple's own agents and the bot, so customer feedback text only reaches a person or API key on the /mcp transport.
This comment has been minimized.
This comment has been minimized.
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
|
Manual check done: |
🍁 Maple PR previewNote Preview resources were removed when the preview label came off. Final commit |
Preview check (pr-2330)A separate verification agent tested
Refusal text: The preview has no data from the internal org, so the positive read (internal org gets every org's reports) is covered by the tests here and gets checked in prod after merge. Traces (deployment.environment = pr-2330)
Span tree of one refused call (trace |
…riage # Conflicts: # apps/ai/src/mcp/tool-descriptors.generated.ts
This comment has been minimized.
This comment has been minimized.
…riage # Conflicts: # apps/ai/src/mcp/tool-descriptors.generated.ts
|
Merged #2334 resolves the "Authentication failed:" follow-up from the preview comment: the dispatcher now renders an |
Maple review🟢 Confidence 10/10 · safe to merge. Cross-org read gated by Adds
Before merge
Production impactOpen errors in the changed files (2)
After this merges, Maple checks whether they stop.
|
|
Merged with 1 step from "Before merge" still open. If it is done, tick it on the review comment; if not, now is the time.
|
Maple: after this shipped✅ Shipped clean. Nothing this change touches got worse in the hour after it deployed. Deployed to Errors in the changed files:
Maple looks once, an hour after the first deploy that carries the merge. |
Why
Agents send feedback about Maple through
send_maple_feedbackandPOST /v2/agent_feedbackinto theagent_feedbacktable. Nothing let the Maple team read it across orgs:GET /v2/agent_feedbacklists only the caller's own org, and traces record only argument names. 23 prod reports since 10-25 have never been read.What
AgentFeedbackService.triage(callerOrgId, filter): a cross-org read (.crossTenant()), newest first, with filters for kind, impact, start time,related_to(case-insensitive substring, LIKE-escaped), org and limit (max 200). It refuses any caller org exceptMAPLE_INTERNAL_ORG_ID, and it refuses everyone while that variable is unset (self-hosted, misconfigured). The check runs before the database is touched.list_maple_feedback(read-only). It renders a table plus each report's full reason and details. It also refuses callers whose audit actor issystemor missing, which covers Maple's own chat agents and the bot (they use the internal service token) and in-process calls. That way customer-written feedback text never reaches the bot's channels or the context of internal agents that hold write tools. Only a person (OAuth) or API key in Maple's org, on the public/mcptransport, can read it.MAPLE_INTERNAL_ORG_ID(already used by ingest, and set in Infisicalprodanddev) is now bound onmaple-aias an optional plain var and added toEnv.Owned by another session
apps/ai/src/mcp/tools/registry.ts(M3): only the import line and the registration line.list_maple_feedbackis listed for every MCP client even though it refuses them. Hiding it per org (or adding anmcp-only audience intools/types.ts) belongs to M3/M2. Proposed as a follow-up.Verification
AgentFeedbackService.test.ts, 6/6): the internal org reads every org newest first; each filter narrows, including a decoy row proving_is not a wildcard; any other org is refused, including one that has feedback of its own; every org is refused while the variable is unset.list-maple-feedback.test.ts): the internal org with an OAuth actor gets both orgs' rows and the full text. These callers are refused withinsufficient_scope: a customer org (even when filtering to itself), the internal org with asystemactor (agents and the bot), the internal org with no actor, and any org while the variable is unset.apps/aitools suite: 493/493. Typecheck passes forapps/ai,apps/api,packages/backendandpackages/domain.oxlint -c .oxlintrc.effect.jsonreports nothing on the changed files. Tool descriptors regenerated.The triage summary of the existing prod reports will be added once this is deployed.
🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.Summary by CodeRabbit