fix(analyze): clamp community/synthesizer kinds to the session workspace#210
Merged
Conversation
Community detection (clusters, concepts, suggest_boundaries) and synthesizer edge enumeration run a global graph algorithm over the whole index and filtered only by size / path prefix, so a workspace-bound caller saw clusters and synthesized edges whose members live in sibling workspaces — a breach of the workspace isolation boundary these kinds are documented to honour. Clamp each to the session workspace: communitiesInSessionScope returns a workspace-filtered copy of the cached partition (never mutating the cache), and AnalyzeSynthesizers gains a repo-scope option that drops edges whose source is outside the workspace and re-tallies its counts. Surface the scope disclosure in the response body (a `scope` block) rather than the _meta scope_note that several clients do not surface, and suppress the now-stale _meta note for these self-disclosing kinds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to the intent-based scoping in #202. While validating that change, the community / synthesizer
analyzekinds were found to cross the workspace isolation boundary: in a multi-repo workspace,analyze kind=clusters(andsynthesizers) returned members / edges from repos in other workspaces. The kinds are documented as "workspace-bound but not repo-narrowed in v1", but the implementation applied no workspace filter at all.Concretely, from a session bound to the
gortexworkspace,analyze kind=clusters repo:gortexreturned cluster members living invioportals/andrate_checkers_detector/— repos that an explicitrepo:arg is otherwise hard-rejected for as cross-workspace.Root cause
handleAnalyzeClusters/handleAnalyzeConcepts/handleSuggestBoundariesrun community detection over the wholes.graphand filtered results only bymin_size/path_prefix.handleAnalyzeSynthesizerssweptg.AllEdges()with no workspace filter.scope_note) rode in MCP_meta, which several clients (Claude Code among them) do not surface — so the leak was silent to an agent.Change
graph.RepoPrefixOfID+Server.communitiesInSessionScopereturn a workspace-filtered copy of the cached community partition (the shared cache is never mutated); applied to clusters / concepts / suggest_boundaries.AnalyzeSynthesizersgainsWithSynthesizerRepoScope, which drops edges whose source is outside the workspace and re-tallies counts / by-kind / samples.scopeblock now rides in the response body ({applied, note}) instead of the invisible_metanote, so an agent sees the applied workspace and — when a narrowing arg is passed — that the kind is workspace-bound but not repo/project-narrowed in v1._metascope_noteis suppressed for these self-disclosing kinds so the two signals don't contradict.Single-repo / unbound sessions are unaffected (no clamp, no scope block).
Testing
TestAnalyzeSynthesizers_RepoScope(analyzer) andTestAnalyzeScope_Clusters_WorkspaceClamp(mcp, bidirectional non-vacuous cross-workspace probe + body-disclosure assertion).TestAnalyzeScope_ScopeNote_BypassKindto the new body-disclosure behavior.go build ./...,go vet,go test ./internal/analyzer/ ./internal/graph/ ./internal/mcp/all pass, including-raceon the touched packages.