unbridled-41 opened a new issue, #4753:
URL: https://github.com/apache/rocketmq-dashboard/issues/4753

   ### Studio Version
   
   branch: rocketmq-studio
   git commit id: cd448e17f14b4bd6e6d4ade87300caf19ca91bc2
   
   ### Problem
   
   The AI conversation retention pass deletes the conversation, its runs and 
its events, but leaves the conversation's agent workspace on disk. The 
workspace holds the child's `HOME` 
(`home/.claude/projects/<cwd>/<session-id>.jsonl`), i.e. the full agent 
transcript, plus `rmqctl.yaml`, `mcp.json` and the appended system prompt; the 
on-request delete removes it, the retention pass does not, so "expired" 
conversations keep their transcript under an id nothing refers to any more.
   
   Chain:
   
   - 
`server/src/main/java/org/apache/rocketmq/studio/ops/ai/conversation/AiConversationService.java:509-515`
 (`deleteCascade`) deletes events, then runs, then the conversations - and 
nothing else; it is called only by `deleteExpiredConversations` (`:480-497`), 
reached from the scheduled `purgeExpired` (`:412-426`, 
`@Scheduled(fixedDelayString = 
"${studio.ai.conversation.cleanup-interval:PT24H}")`).
   - The on-request delete does remove it: `AiConversationService.java:290` 
(`workspace.delete(conversationId)`).
   - The workspace is documented as tied to the conversation's lifetime: 
`RmqctlWorkspace.java:212-216` ("while {@code home/} and whatever {@code 
claude} persisted inside it are left alone", i.e. they persist per 
conversation), the layout at `:61-70` (`home/  0700, the child's HOME, per 
conversation and persistent`), and `delete(long)` at `:277-299`, whose javadoc 
says it is "called by `DELETE /api/ai/conversations/{id}` after the rows are 
gone". Nothing else ever calls it - `AiConversationService.java:290` was the 
only production caller.
   
   Trigger (deterministic): set `studio.ai.conversation.retention-days=1` and 
`cleanup-interval=PT1M` (or wait out the 90-day default, 
`AiConversationProperties.java:37`), let a conversation with an agent run age 
out, and let the sweep run. The conversation disappears from the UI and its 
rows are gone, while 
`${studio.ai.conversation.workspace-dir}/conv-<id>/home/.claude/...` is still 
there.
   
   ### Evidence
   
   - Defect: `AiConversationService.java:509-515` (retention cascade without 
the workspace).
   - Contrast: `AiConversationService.java:290` (the delete path that does it) 
and the pinned order in 
`AiConversationServiceTest.deleteShouldCascadeChildrenFirstAndRemoveTheWorkspaceTest`,
 which asserts `workspace.delete(CONVERSATION_ID)` for that path.
   - Retention contract: `AiConversationProperties.java:37` (`retentionDays = 
90`), `server/src/main/resources/application.yml:119` (`workspace-dir: 
${STUDIO_AI_CONVERSATION_WORKSPACE_DIR:/tmp/rocketmq-studio-ai}`).
   - Regression test added with this report 
(`AiConversationServiceTest.retentionShouldRemoveTheWorkspaceOfEveryPurgedConversationTest`),
 failing on cd448e17:
   
   ```
   [ERROR] ...retentionShouldRemoveTheWorkspaceOfEveryPurgedConversationTest -- 
Time elapsed: 0.028 s <<< FAILURE!
   Wanted but not invoked:
   [ERROR] Tests run: 19, Failures: 1, Errors: 0, Skipped: 0
   ```
   
   ### Impact
   
   The retention setting is not honoured for the most sensitive artefact the 
feature writes: the agent transcript, which contains the operator's prompts, 
the tool arguments and the tool results, survives the purge. With the workspace 
on a persistent volume (what `STUDIO_AI_CONVERSATION_WORKSPACE_DIR` exists for) 
the directory accumulates without bound, one `conv-<id>` per purged 
conversation; with the default `/tmp` location it is only cleared by a 
container restart. Either way the two deletion paths disagree about what 
deleting a conversation means, and the retention job is the one that is 
supposed to run unattended.
   
   ### Expected behavior
   
   Purging an expired conversation removes its workspace as well, in the same 
order the on-request delete uses (rows first, then the directory), so a crash 
in between leaves a directory that is still reachable instead of a transcript 
removed under a conversation that is still visible.
   
   ### Related work
   
   - #4647/#4648 (open) — the same scheduler family: malformed 
snapshot-retention configuration.
   - The alert-silence/alert-event retention work (`AlertSilenceSchedule`, 
`NotificationOutboxService`) is unrelated to the AI subsystem.
   - The AI items open today (#4685, #4693, #4696, #4707, #4715, #4631, #4665, 
#4738, #4740) are all about the run/stream lifecycle in the browser or the CLI 
session, none about the workspace lifecycle.
   
   #
   
   ## PR
   
   Fix: #4754.
   
   This PR targets the development trunk `rocketmq-studio`. GitHub interprets 
closing keywords only for pull requests that target the repository default 
branch, and this repository default branch is still `master`, so merging the PR 
will not close this issue automatically — it needs to be closed by hand.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to