Commit f28cc95
fix: enforceable Agent writes plus non-blocking save bubbles (#75)
<!-- CURSOR_AGENT_PR_BODY_BEGIN -->
## Problem
Agent chat answered a metric, then offered **“Should I save this as a
shared DeepSQL brain note?”** A user without `canManageContent` clicked
Yes and got a 403. The offer itself is the bug.
Admins still need a way to persist a useful definition — without the
Agent asking, without blocking chat, and without creating a second note
that overlaps an existing brain note or business rule. Chips must stay
**quiet** when the Agent already got it right.
## Fix
**Capability gating**
- Stamp `callerCapabilities` (including `doNotOffer` and
`canWriteSharedBrainNotes`) on `get_brain_context`, `list_connections`,
`list_brain_recommendations`, and `get_current_user`.
- `save_brain_note` fail-closes **before** `POST /brain/notes` when
`canManageContent` is false.
- `SOUL.md` / `bi-query` skill: never volunteer a write listed in
`doNotOffer`.
**Suggestion bubbles — only after correction or teaching**
- A clean first-turn answer never gets a chip, even if it looks like a
definition.
- “Thanks, that’s right” after a good answer also stays quiet.
- A chip appears only when the user follows up with a
correction/teaching phrase (`that's wrong`, `always filter`, `remember
this`, …) after a prior Agent reply.
- Clicking the chip opens an excerpt of the shared brain note that would
be created, plus **Save to brain** / **Merge and save**.
- Propose/accept never blocks the composer.
- One unsaved chip at a time; dismissed/saved targets stay suppressed
for the session.
- Overlaps with existing notes or business rules merge into one intent.
- `schema.table` extraction is a linear scan (no ReDoS regex).
## Verify
- `cd backend && ./mvnw test
-Dtest=BrainNoteIntentServiceTest,BrainControllerAuthorizationSafetyTest`
- `node --test
src/components/AgentChat/shouldOfferBrainSuggestion.test.js
src/components/AgentChat/AgentRecommendationBubbles.test.js`
- Live `POST /brain/notes/propose`: first-turn and thanks → `204`;
correction with `priorAnswer` → `200` `NEW` / `MERGE`
[Suggestion chip opens an excerpt of the brain
note](https://cursor.com/agents/bc-019fe687-99b1-76fd-80fa-dd213aecc497/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fbubble_excerpt_card.webp)
[After save the chip is gone and the composer stays
usable](https://cursor.com/agents/bc-019fe687-99b1-76fd-80fa-dd213aecc497/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fbubble_after_save.webp)
[brain_note_suggestion_bubble.mp4](https://cursor.com/agents/bc-019fe687-99b1-76fd-80fa-dd213aecc497/artifacts?path=%2Fopt%2Fcursor%2Fartifacts%2Fbrain_note_suggestion_bubble.mp4)
<sub>To show artifacts inline, <a
href="https://cursor.com/dashboard/cloud-agents#my-pull-requests">enable</a>
in settings.</sub>
<!-- CURSOR_AGENT_PR_BODY_END -->
<div><a
href="https://cursor.com/agents/bc-019fe687-99b1-76fd-80fa-dd213aecc497?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-web-light.png"><img
alt="Open in Web" width="114" height="28"
src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a
href="https://cursor.com/background-agent?bcId=bc-019fe687-99b1-76fd-80fa-dd213aecc497&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source
media="(prefers-color-scheme: light)"
srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img
alt="Open in Cursor" width="131" height="28"
src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>1 parent b4d62d2 commit f28cc95
24 files changed
Lines changed: 1514 additions & 49 deletions
File tree
- agent
- skills/bi-query
- backend/src
- main/java/com/dbaagent
- controller
- dto
- service/brain/core
- test/java/com/dbaagent/service/brain/core
- docs/public
- mcp
- skills
- src
- components
- AgentChat
- sections
- lib/api
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
269 | 269 | | |
270 | 270 | | |
271 | 271 | | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
272 | 281 | | |
273 | 282 | | |
274 | 283 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
5 | | - | |
| 5 | + | |
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
27 | 35 | | |
28 | 36 | | |
29 | | - | |
| 37 | + | |
| 38 | + | |
30 | 39 | | |
31 | 40 | | |
32 | 41 | | |
33 | 42 | | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
39 | 48 | | |
40 | 49 | | |
41 | 50 | | |
42 | 51 | | |
43 | 52 | | |
44 | | - | |
45 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
46 | 56 | | |
47 | 57 | | |
48 | 58 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
| 30 | + | |
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| |||
Lines changed: 49 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
31 | 34 | | |
32 | 35 | | |
33 | 36 | | |
| |||
94 | 97 | | |
95 | 98 | | |
96 | 99 | | |
| 100 | + | |
97 | 101 | | |
98 | 102 | | |
99 | 103 | | |
| |||
240 | 244 | | |
241 | 245 | | |
242 | 246 | | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
243 | 292 | | |
244 | 293 | | |
245 | 294 | | |
| |||
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
0 commit comments