| 1 | package main |
| 2 | |
| 3 | import "reasonix/desktop/internal/workspacestate" |
| 4 | |
| 5 | // A completed chat-file catalog cannot represent metadata-only placeholders. |
| 6 | // Keep those explicit indexed objects visible, but never resurrect a hidden |
| 7 | // recovery lineage or an adopted/archived formal session from its old metadata. |
| 8 | func (a *App) withRemovablePlaceholderTopics(req ProjectTopicPageRequest, state workspacestate.State, nodes []ProjectNode, adopted map[string]bool) []ProjectNode { |
| 9 | seen := make(map[string]bool, len(nodes)) |
| 10 | for _, node := range nodes { |
| 11 | seen[node.TopicID] = true |
| 12 | } |
| 13 | file, err := readTopicRemovalProjects() |
| 14 | if err != nil { |
| 15 | return nodes |
| 16 | } |
| 17 | for _, node := range a.metadataProjectTopics(req.Scope, req.WorkspaceRoot) { |
| 18 | if seen[node.TopicID] || adopted[node.TopicID] || node.RuntimeOnly { |
| 19 | continue |
| 20 | } |
| 21 | if catalog := a.sessionCatalog.Load(); catalog != nil && catalog.TopicFolded(a.bootContext(), req.Scope, req.WorkspaceRoot, node.TopicID) { |
| 22 | continue |
| 23 | } |
| 24 | item, err := topicRemovalCandidate(state, file, TopicRemovalTarget{TopicID: node.TopicID}) |
| 25 | if err != nil || item.Topic.Scope != req.Scope || (req.Scope == "project" && !sameDesktopPath(item.Topic.WorkspaceRoot, req.WorkspaceRoot)) { |
| 26 | continue |
| 27 | } |
| 28 | // Partial discovery cannot prove emptiness. Listing must not scan sources |
| 29 | // or transcripts for removability; InspectTopicRemoval owns that proof |
| 30 | // when the user explicitly requests the management action. |
| 31 | node.TurnsState = "unknown" |
| 32 | node.Health = "metadata_pending" |
| 33 | nodes = append(nodes, node) |
| 34 | seen[node.TopicID] = true |
| 35 | } |
| 36 | return nodes |
| 37 | } |
| 38 |