Per the docs Refresh Protocol (conductor/workflow.md), after a
reference/analysis track ships, the affected guides must be updated
to reflect new module structure or new conventions. The nagent_review
track (9cc51ca9) produced a deep-dive + 10 actionable takeaways that
named 3 documentation gaps in /docs. This commit fills them.
3 new guides (1,122 lines total):
1. guide_discussions.md (353 lines) — The Discussion system
- 23-operation matrix: A1-A7 per-entry + B1-B11 discussion-level
+ C1-C5 undo/redo
- Take naming convention (<base>_take_<n>), branching, promotion
- User-managed role list (app.disc_roles)
- Per-role filter linked to MMA persona focus
- _disc_entries_lock thread-safety contract
- Hook API session endpoints
- Persistence: _flush_to_project, _flush_disc_entries_to_project,
context_snapshot
- 9 file:line refs into gui_2.py:3770-4260 + history.py
2. guide_state_lifecycle.md (375 lines) — Undo/redo + reset + state
delegation
- HistoryManager + UISnapshot (13 captured fields, 100-snapshot
capacity, debounced change-detection at render frame)
- _handle_reset_session (clears 30+ fields, replaces project,
preserves active_project_path per the 2026-06-08 regression fix)
- App.__getattr__/__setattr__ state delegation to Controller
- 4-thread access pattern with 7 lock-protected regions
- State persistence: in-memory vs project TOML vs config TOML
- Hot-reload integration
- Hook API registries (_predefined_callbacks, _gettable_fields)
- 14 file:line refs into gui_2.py:1140-1170, history.py,
app_controller.py:3286-3356
3. guide_context_aggregation.md (394 lines) — The aggregate.py
pipeline
- 3 aggregation strategies (auto, summarize, full)
- 7 per-file view modes (full, summary, skeleton, outline,
masked, custom, none)
- Full FileItem schema (9 fields + __post_init__ normalizer)
at models.py:510-559
- ContextPreset schema and ContextPresetManager
- Tier 3 worker variant (build_tier3_context with FuzzyAnchor
re-resolution and focus-file handling)
- force_full / auto_aggregate short-circuits
- Cache strategy (static prefix + dynamic history)
- 23 file:line refs into aggregate.py:36-518 + models.py:909-937
8 existing guides cross-linked to the 3 new guides and to the
nagent_review track:
- guide_gui_2.md (+ See Also entries for discussions,
state lifecycle, context aggregation,
nagent_review report)
- guide_app_controller.md (+ See Also entries for discussions,
state lifecycle, context aggregation,
nagent_review report)
- guide_context_curation.md (+ new See Also section pointing to
context aggregation + nagent_review)
- guide_architecture.md (+ new See Also section listing all 10
guides + nagent_review report)
- guide_ai_client.md (+ See Also entries for state lifecycle,
context aggregation, nagent_review
pitfalls #2 and #4)
- guide_mma.md (+ new See Also section pointing to
context aggregation, discussions,
nagent_review report §9 + takeaways §3/§10
for SubConversationRunner priority)
- guide_models.md (+ See Also entries for context
aggregation, discussions, nagent_review
report §6 on FileItem as strongest
curation dimension)
- Readme.md (+ 3 new guide entries in the index
table, with one-line summaries)
No code modified. This is documentation only.
Why these 3 guides specifically:
- guide_discussions.md: The discussion system is the user's most
edited surface. nagent_review's report §3 enumerated 23 operations
(A1-C5) that previously existed only as scattered file:line refs
across gui_2.py. A dedicated guide makes the operation matrix
discoverable.
- guide_state_lifecycle.md: The undo/redo + reset + state delegation
machinery is architecturally load-bearing but scattered across 4
files. After nagent_review identified the provider-side history
divergence as Pitfall #4, the relationship between Manual Slop's
state and the provider's state needs explicit documentation.
- guide_context_aggregation.md: aggregate.py (518 lines) is the
most-touched module after ai_client.py but had no dedicated
guide. nagent_review confirmed it's Manual Slop's strongest
curation dimension. A dedicated guide makes the 7 view modes
and 3 strategies discoverable.
The 3 new guides total 1,122 lines and follow the existing
per-source-file deep-dive style (architectural, data-oriented,
state-management-focused).
11 KiB
Advanced Context Curation
Top | Context Aggregation | Architecture | Tools & IPC | MMA | Simulations
Overview
Phase 6 introduced three advanced context curation features that enhance the granularity and resilience of file-based context management:
- Granular AST Control — Per-symbol toggling between Definition, Signature, and Hidden states for C/C++ files
- Fuzzy Anchor Slices — Text slice definitions that survive file modifications via anchor-based resolution
- Interactive AST Tree Masking — GUI modal for inspecting and masking AST nodes
Granular AST Control
Purpose
For C/C++ files, instead of binary "include/exclude", each symbol (class, function, struct) can be set to one of three states:
| State | Description | Use Case |
|---|---|---|
full |
Include entire file content | Unknown structure, complex macros |
def |
Include function/class definitions only | Header inspection |
sig |
Include function signatures only | API surface review |
agg |
Auto-aggregate via summarization | Token budget management |
hide |
Exclude from context entirely | Irrelevant symbols |
Implementation
The ast_mask dictionary on file items tracks per-symbol state:
# src/gui_2.py:_render_context_composition_panel
if f_path.lower().endswith(('.c', '.cpp', '.h', '.hpp', '.cxx', '.cc')):
if hasattr(f_item, 'ast_mask'):
# Show AST state indicators
pass
File items expose these properties:
force_full: Override aggregation with full contentauto_aggregate: Use summarization pipelineast_signatures: Include signatures onlyast_definitions: Include definitions only
Data Structure
@dataclass
class FileItem:
path: str
force_full: bool = False
auto_aggregate: bool = False
ast_signatures: bool = False
ast_definitions: bool = False
ast_mask: dict[str, str] = field(default_factory=dict) # symbol_path -> state
Fuzzy Anchor Slices
Purpose
Text slices defined by line numbers become invalid when files are modified (lines inserted/deleted). Fuzzy Anchor slices use content hashing and anchor line matching to resolve the correct position after file changes.
Algorithm
-
Create Slice: When user defines a slice from
start_linetoend_line:- Capture content hash of the region
- Store surrounding context lines (before/after) as anchors
-
Resolve Slice: On file re-read after modification:
- Search for anchor content in modified file
- Calculate offset from anchor displacement
- Return new
start_line,end_line
Implementation
# src/fuzzy_anchor.py
class FuzzyAnchor:
@classmethod
def create_slice(cls, text: str, start_line: int, end_line: int) -> dict:
"""Returns slice_data with content_hash, anchor_lines, and positions."""
@classmethod
def resolve_slice(cls, text: str, slice_data: dict) -> Optional[Tuple[int, int]]:
"""Resolves slice position in modified text, returns (start, end) or None."""
Slice Data Structure
{
"start_line": 10, # 1-based original line
"end_line": 25, # 1-based original line
"content_hash": "abc123...", # SHA256 of region content
"start_context": [...], # Lines before start for anchor matching
"end_context": [...] # Lines after end for anchor matching
}
Anchor Matching Strategy
- Exact match: If anchors found at same positions, return original lines
- Shift detection: If anchors shifted, calculate delta and apply to slice bounds
- Mismatch: If anchors not found, return
None(slice definition invalid)
Interactive AST Tree Masking
Purpose
The AST Inspector modal allows visual inspection of a file's parsed structure and per-symbol state control.
Modal Flow
- User right-clicks a C/C++ file in Context Panel
- Selects "Inspect AST" from context menu
- Modal opens showing hierarchical tree of all symbols
- Per-symbol radio buttons (Def/Sig/Hide) control state
- Changes persist to
ast_maskdictionary
Implementation
# src/gui_2.py:_render_ast_inspector_modal
def _render_ast_inspector_modal(self) -> None:
expanded, opened = imgui.begin_popup_modal('AST Inspector', True, ...)
if expanded:
# Fetch outline via tree-sitter MCP tools
outline = mcp_client.ts_cpp_get_code_outline(f_path)
# Parse into hierarchical node list
for node in parsed_nodes:
# Render [Kind] Name with radio buttons
if imgui.radio_button("Def", current_mode == 'def'):
f_item.ast_mask[full_path] = 'def'
Node Display Format
[Struct] MyClass (Lines 10-50)
[Field] member1 (Lines 12-14)
[Method] init (Lines 20-30)
Radio buttons per node:
- Def: Include this symbol's definition
- Sig: Include this symbol's signature only
- Hide: Exclude this symbol entirely
Batch Operations
Shift-Click Range Selection
The Context Panel supports Shift-Click for range selection:
# src/gui_2.py:_render_context_composition_panel
if changed_sel:
if imgui.get_io().key_shift and self._last_selected_context_index != -1:
start = min(self._last_selected_context_index, i)
end = max(self._last_selected_context_index, i)
for idx in range(start, end + 1):
# Toggle selection state for range
pass
Batch Action Bar
Batch operations apply to all selected files:
| Button | Action |
|---|---|
| Full | Set force_full=True for all selected |
| Agg | Set auto_aggregate=True for all selected |
| Sig | Set ast_signatures=True for all selected |
| Def | Set ast_definitions=True for all selected |
| Remove | Remove selected files from context |
Context Snapshotting (Per-Take)
Purpose
When switching between discussion "takes", the context panel state is snapshotted and restored.
UISnapshot Structure
@dataclass
class UISnapshot:
ai_input: str
project_system_prompt: str
global_system_prompt: str
base_system_prompt: str
use_default_base_prompt: bool
temperature: float
top_p: float
max_tokens: int
auto_add_history: bool
disc_entries: list[dict]
files: list[dict]
screenshots: list[str]
HistoryManager Integration
class HistoryManager:
def push(self, state: Any, description: str) -> None: ...
def undo(self, current_state: Any, ...) -> Optional[HistoryEntry]: ...
def redo(self, current_state: Any, ...) -> Optional[HistoryEntry]: ...
def jump_to_undo(self, index: int, current_state: Any, ...) -> Optional[HistoryEntry]: ...
Aggregation Pipeline Integration
The context curation features integrate with the aggregation pipeline:
# src/aggregate.py
def _build_file_item_context(self, f_item: FileItem, ...) -> str:
if f_item.ast_mask:
# Apply AST masking before aggregation
masked_content = self._apply_ast_mask(content, f_item.ast_mask)
Mask Application Order
- Fetch file content
- Parse AST if C/C++ file
- Apply
ast_maskper symbol - Run through aggregation strategy (full/agg/sig/def/hide)
- Return masked, aggregated content
Testing
Unit Tests
tests/test_fuzzy_anchor.py— FuzzyAnchor.create_slice/resolve_slicetests/test_history_manager.py— HistoryManager undo/redo/snapshottests/test_ts_cpp_tools.py— C++ skeleton/outline/definition toolstests/test_ast_parser.py— ASTParser for Python/C/C++
Simulation Tests
tests/test_phase6_simulation.py— GUI integration tests- Batch operations shift-click
- AST Inspector modal
- Slice editor
Full Suite
uv run pytest tests/test_fuzzy_anchor.py tests/test_history_manager.py \
tests/test_ts_cpp_tools.py tests/test_ast_parser.py \
tests/test_phase6_simulation.py -v
Structural File Editor (Phase 7)
Phase 7 unified two previously separate modals — the AST Inspector and the Slice Editor — into a single Structural File Editor modal. This reduces modal-switching overhead when curating context for a file with both AST-masked symbols and fuzzy-anchored slices.
Unified Modal Flow
When the user clicks "Inspect" or "Slices" on a file item in the Context Panel:
- The Structural File Editor modal opens with two side-by-side panes:
- Left pane: Hierarchical AST tree (using
ts_*_get_code_outlinefor C/C++,py_get_code_outlinefor Python). Each node is a clickable target for AST masking. - Right pane: Slice list with line ranges. Each slice can be edited, deleted, or converted to a fuzzy anchor.
- Left pane: Hierarchical AST tree (using
- Selecting a node in the left pane shows its current mask state (
full/def/sig/agg/hide) and allows modification. - The slice list on the right updates in real time as fuzzy anchors are added or resolved.
Key Files
src/gui_2.py:_render_structural_file_editor_modal— The unified modal renderer.- The previously separate
_render_ast_inspector_modaland_render_slice_editor_modalfunctions are deprecated; their state is migrated to the unified editor on first open.
Behavioral Equivalence
The unified editor preserves the behavior of both predecessors:
- All AST mask operations (set/clear state per symbol) work identically.
- Fuzzy anchor slice operations (create, resolve, annotate) work identically.
- The "Apply" action writes the modified
ast_maskand slice list to the file item in a single transaction.
This is a UX consolidation, not a data model change. The underlying ast_mask: dict[str, str] and slice list structures are unchanged.
See Also
- guide_context_aggregation.md — The full
aggregate.pypipeline that consumes the FileItem schema documented here. Includes the 7view_modevalues (full,summary,skeleton,outline,masked,none,custom) and the 3aggregation_strategyvalues (auto,summarize,full) - guide_context_presets.md (planned) — The
ContextPresetschema (named, persisted set of FileItems) - guide_models.md — Full FileItem and ContextPreset dataclass definitions at
src/models.py:510andsrc/models.py:909 - guide_architecture.md — How the FileItem list is built up in
App.init_stateand how the aggregation pipeline consumes it - conductor/tracks/nagent_review_20260608/report.md §6 — Deep-dive on per-file memory; compares Manual Slop's curation dimension (this guide) to nagent's conversation-log dimension
- conductor/tracks/nagent_review_20260608/nagent_takeaways_20260608.md §4 — Actionable: add a
file_id: st_dev:st_inofield to FileItem for rename-safe identity