Skip to content

feat: Improve quality rounds#969

Merged
Henry-811 merged 7 commits intodev/v0.1.59from
improve_quality_rounds
Mar 4, 2026
Merged

feat: Improve quality rounds#969
Henry-811 merged 7 commits intodev/v0.1.59from
improve_quality_rounds

Conversation

@ncrispino
Copy link
Collaborator

@ncrispino ncrispino commented Mar 4, 2026

PR Title Format

Your PR title must follow the format: <type>: <brief description>

Valid types:

  • fix: - Bug fixes
  • feat: - New features
  • breaking: - Breaking changes
  • docs: - Documentation updates
  • refactor: - Code refactoring
  • test: - Test additions/modifications
  • chore: - Maintenance tasks
  • perf: - Performance improvements
  • style: - Code style changes
  • ci: - CI/CD configuration changes

Examples:

  • fix: resolve memory leak in data processing
  • feat: add export to CSV functionality
  • breaking: change API response format
  • docs: update installation guide

Description

Brief description of the changes in this PR

Type of change

  • Bug fix (fix:) - Non-breaking change which fixes an issue
  • New feature (feat:) - Non-breaking change which adds functionality
  • Breaking change (breaking:) - Fix or feature that would cause existing functionality to not work as expected
  • Documentation (docs:) - Documentation updates
  • Code refactoring (refactor:) - Code changes that neither fix a bug nor add a feature
  • Tests (test:) - Adding missing tests or correcting existing tests
  • Chore (chore:) - Maintenance tasks, dependency updates, etc.
  • Performance improvement (perf:) - Code changes that improve performance
  • Code style (style:) - Changes that do not affect the meaning of the code (formatting, missing semi-colons, etc.)
  • CI/CD (ci:) - Changes to CI/CD configuration files and scripts

Checklist

  • I have run pre-commit on my changed files and all checks pass
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Pre-commit status

# Paste the output of running pre-commit on your changed files:
# uv run pre-commit install
# git diff --name-only HEAD~1 | xargs uv run pre-commit run --files # for last commit
# git diff --name-only origin/<base branch>...HEAD | xargs uv run pre-commit run --files # for all commits in PR
# git add <your file> # if any fixes were applied
# git commit -m "chore: apply pre-commit fixes"
# git push origin <branch-name>

How to Test

Add test method for this PR.

Test CLI Command

Write down the test bash command. If there is pre-requests, please emphasize.

Expected Results

Description/screenshots of expected results.

Additional context

Add any other context about the PR here.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added 4x speed performance messaging across documentation and marketing materials.
    • Support for Claude Sonnet 4.6 model.
    • Enhanced coordination workflow configuration with new quality gates and capture modes.
    • Improved workspace privacy with path tokenization.
  • Improvements

    • Optimized provider prioritization in quickstart flows.
    • Enhanced Docker environment setup for browser automation tools.
    • Expanded quickstart reasoning profiles with improved model-specific handling.
    • Improved Node.js module resolution in containerized environments.
  • Documentation

    • Comprehensive coordination workflow documentation updates with backend-focused architecture details.
    • New user guide for coordination workflows.

@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

This PR introduces coordination workflow enhancements including new configuration fields for learning capture modes and quality improvement gates, provider prioritization in quickstart flows, workspace path tokenization for privacy, Docker setup improvements for Playwright, and marketing updates promoting "4x speed" messaging across documentation.

Changes

Cohort / File(s) Summary
Marketing and Documentation Headers
README.md, README_PYPI.md, docs/source/index.rst
Added "(4x speed)" tagline to README taglines and updated banner image alt text to reflect new messaging.
Coordination Workflow Documentation
docs/modules/coordination_workflow.md
Comprehensive reframe from user-facing to backend-oriented documentation; added Backend Module Map, Key Entry Points, Concrete Walkthrough, Core State Model sections; restructured Pre-Coordination Checks, Per-Agent Round Engine, and finalization flows; clarified injection/restart delivery semantics and workspace lifecycle handling.
Configuration Schema
massgen/agent_config.py
Added new fields improvements dict with validation, disable_final_only_round_capture_fallback flag, and expanded learning_capture_mode to include "verification_and_final_only" option; introduced _validate_improvements() validation method.
API Parameter Handling
massgen/api_params_handler/_api_params_handler_base.py, massgen/backend/base.py
Extended exclusion parameter sets with enable_quality_rethink_on_iteration, enable_novelty_on_iteration, improvements, and disable_final_only_round_capture_fallback; reordered learning_capture_mode reference.
Backend Capabilities
massgen/backend/capabilities.py
Added "claude-sonnet-4-6" model to both claude and claude_code backend capabilities.
Gemini Backend Tool Normalization
massgen/backend/gemini.py
Introduced _normalize_and_resolve_tool_name() method to handle tool name normalization and MCP alias resolution; updated stream_with_tools, tool_config_for_call, and stream continuation paths to use new normalization method.
CLI Planning Helpers
massgen/cli.py
Added helper functions _format_chunk_target_line() and should_include_quick_edit_hint() to centralize planning prompt generation; integrated new coordination config fields into _parse_coordination_config().
Quickstart Configuration
massgen/config_builder.py
Introduced sort_quickstart_provider_ids() and QUICKSTART_PROVIDER_PRIORITY constant to prioritize provider ordering; extended orchestrator and coordination config with voting_sensitivity, voting_threshold, and learning_capture_mode fields in generated quickstart configurations.
Configuration Validation
massgen/config_validator.py
Expanded VALID_LEARNING_CAPTURE_MODES to include "verification_and_final_only"; added orchestrator validation branches for enable_novelty_on_iteration, enable_quality_rethink_on_iteration, improvements dict constraints, and disable_final_only_round_capture_fallback.
Coordination Session Tokens
massgen/coordination_tracker.py
Added per-session path token storage via _path_tokens mapping and new public method get_path_token() for stable agent-specific token generation.
Docker Infrastructure
massgen/docker/Dockerfile.sudo
Enhanced Playwright installation with global npm installation and combined Python/Node browser setup; improved non-root user (massgen) setup with workspace ownership and sudo NOPASSWD entry.
Evaluation Criteria
massgen/evaluation_criteria_generator.py
Changed exclude_file_operation_mcps from True to False in subagent criteria generation configuration to enable file-operation MCPs during coordination.
Node.js Module Resolution
massgen/filesystem_manager/_docker_manager.py
Enhanced NODE_PATH environment variable setup to ensure globally installed Node modules (e.g., Playwright CLI) are resolvable in Docker container.
Workspace Path Tokenization
massgen/filesystem_manager/_filesystem_manager.py
Added optional workspace_token parameter to setup_orchestration_paths() to mask agent_id in temporary workspace paths; defaults to agent_id if not provided.
Frontend Provider Sorting
massgen/frontend/displays/textual_widgets/quickstart_wizard.py
Integrated sort_quickstart_provider_ids() for ordered provider iteration in ProviderModelStep and TabbedProviderModelStep; refactored reasoning input handling with placeholder defaults and improved state propagation.
Web Server Provider Configuration
massgen/frontend/web/server.py
Implemented provider sorting using sort_quickstart_provider_ids() based on availability and quickstart priority; added disable_final_only_round_capture_fallback parameter to coordination config construction.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • MassGen #903 — Overlapping changes to coordination configuration code (massgen/agent_config.py, config_validator.py) and workspace/token handling (coordination_tracker.py, filesystem_manager), indicating related coordination infrastructure updates.
  • MassGen #947 — Related updates to coordination workflow documentation and learning_capture_mode field extensions in CoordinationConfig.
  • MassGen #764 — Direct code-level overlap in massgen/backend/gemini.py regarding tool-name normalization helpers and function_call parsing logic.

Suggested reviewers

  • a5507203
🚥 Pre-merge checks | ✅ 3 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Documentation Updated ⚠️ Warning PR fails multiple documentation requirements: missing Google-style docstrings, no YAML schema documentation for new parameters, incorrect default value in docstring, and README.md updated on non-release branch. Add complete Google-style docstrings to all new functions, create/update YAML schema documentation, correct learning_capture_mode default value, and revert README.md changes or confirm release PR status.
Title check ❓ Inconclusive The title 'feat: Improve quality rounds' is vague and does not clearly summarize the actual changes in the PR, which involve numerous feature additions including coordination workflow documentation, configuration improvements, quality gates, learning capture modes, provider prioritization, workspace tokenization, Playwright setup, and Gemini tool normalization. Provide a more specific title that captures the primary change, such as 'feat: Add quality gates and enhance coordination configuration' or break into multiple focused PRs with clearer, more descriptive titles.
Capabilities Registry Check ❓ Inconclusive Capabilities Registry Check cannot be completed due to infrastructure limitations preventing test execution and codebase verification. Retry capability check after infrastructure recovery; manually verify pricing configuration in token_manager.py and execute test suite to confirm model registration.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 81.48% which is sufficient. The required threshold is 80.00%.
Config Parameter Sync ✅ Passed Both files updated with identical four new exclusion parameters maintaining synchronization as required.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch improve_quality_rounds

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (5)
massgen/backend/gemini.py (1)

338-370: Add defensive checks and complete the Google-style docstring.

The method accesses self._mcp_functions and self._custom_tool_names without None guards, unlike similar code elsewhere (e.g., line 1324 uses self._custom_tool_names or set()). Additionally, the docstring is missing Args and Returns sections per Google-style conventions.

♻️ Suggested improvements
     def _normalize_and_resolve_tool_name(self, tool_name: str) -> str:
         """Normalize Gemini tool names and resolve MCP aliases.

         Gemini can emit tool calls in different forms:
         - API-prefixed names (for example, ``default_api:tool``)
         - Canonical MCP names (``mcp__server__tool``)
         - Bare server/tool MCP names (``server__tool``)

         We normalize provider-specific prefixes first, then map bare MCP names to
         their canonical ``mcp__...`` form when the canonical name is registered.
+
+        Args:
+            tool_name: The raw tool name from Gemini API response.
+
+        Returns:
+            Normalized tool name, potentially mapped to canonical MCP form.
         """
         normalized_name = _normalize_gemini_tool_name(tool_name or "")
         if not normalized_name:
             return normalized_name

+        mcp_functions = self._mcp_functions or {}
+        custom_tool_names = self._custom_tool_names or set()
+
         # Keep already-known names unchanged.
-        if normalized_name in self._mcp_functions:
+        if normalized_name in mcp_functions:
             return normalized_name
-        if normalized_name in self._custom_tool_names:
+        if normalized_name in custom_tool_names:
             return normalized_name

         # Preserve explicit namespace prefixes when present.
         if normalized_name.startswith("mcp__"):
             return normalized_name
         if normalized_name.startswith("custom_tool__"):
             return normalized_name

         # Gemini may emit MCP names without the mcp__ prefix.
         mcp_alias = f"mcp__{normalized_name}"
-        if mcp_alias in self._mcp_functions:
+        if mcp_alias in mcp_functions:
             return mcp_alias

         return normalized_name

As per coding guidelines: "For new or changed functions, include Google-style docstrings".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/backend/gemini.py` around lines 338 - 370, The
_normalize_and_resolve_tool_name method lacks None-guards for
self._mcp_functions and self._custom_tool_names and its docstring is missing
Google-style Args/Returns; update the docstring to include short description
plus Args (tool_name: str) and Returns (str) sections, and add defensive checks
using e.g. local variables like mcp_funcs = self._mcp_functions or {} and
custom_names = self._custom_tool_names or set() and then replace direct accesses
to self._mcp_functions/_custom_tool_names with those locals so the function
safely handles None values while preserving existing resolution logic (including
checks for "mcp__" and "custom_tool__" prefixes and the mcp_alias lookup).
massgen/evaluation_criteria_generator.py (1)

849-864: Update the stale “pure LLM reasoning” comment.

Line 849 says this path uses “no tools,” but Line 863 explicitly keeps file-operation MCPs enabled. Please align the comment with actual behavior to avoid future misconfiguration.

✏️ Suggested comment-only cleanup
-            # Simplified agent configs (no tools, pure LLM reasoning)
+            # Simplified agent configs (no command-line/code-based tools).
+            # Keep file-operation MCPs available so subagents can still write criteria.json.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/evaluation_criteria_generator.py` around lines 849 - 864, The comment
"Simplified agent configs (no tools, pure LLM reasoning)" above the loop that
builds simplified from agent_configs is stale because the backend dict sets
"exclude_file_operation_mcps": False, so file-operation MCPs remain enabled;
update that comment to accurately describe the behavior (e.g., "Simplified agent
configs (no external tools/command-line MCPs; file-operation MCPs retained)")
and ensure it references the code that sets enable_mcp_command_line,
enable_code_based_tools, and exclude_file_operation_mcps in the simplified
backend.
massgen/frontend/web/server.py (1)

4871-4874: LGTM - consider extracting shared CoordinationConfig construction.

The parameter is correctly added here as well. However, the CoordinationConfig construction is now duplicated across run_coordination (lines 4838-4884) and run_coordination_with_history (lines 4417-4463). This makes it easy for future changes to update one location but miss the other.

Consider extracting a helper function like _build_coordination_config(coord_cfg: dict) -> CoordinationConfig to centralize this logic.
,

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/frontend/web/server.py` around lines 4871 - 4874, The
CoordinationConfig construction is duplicated in run_coordination and
run_coordination_with_history; extract a helper function named
_build_coordination_config(coord_cfg: dict) -> CoordinationConfig that
encapsulates the current construction logic (including
disable_final_only_round_capture_fallback and all other fields used in both
locations) and replace the inline builds in run_coordination and
run_coordination_with_history with calls to
_build_coordination_config(coord_cfg) so both functions use the single shared
factory.
massgen/agent_config.py (1)

317-330: Reject unknown improvements keys to prevent silent quality-gate misconfiguration.

Current validation checks known keys when present, but typos/unknown keys are silently accepted.

♻️ Proposed fix
@@
         if not isinstance(self.improvements, dict):
             raise ValueError(
                 "improvements must be a dictionary",
             )
 
-        for key in ("min_transformative", "min_structural", "min_non_incremental"):
+        allowed_keys = {"min_transformative", "min_structural", "min_non_incremental"}
+        unknown_keys = set(self.improvements) - allowed_keys
+        if unknown_keys:
+            raise ValueError(
+                "improvements contains unknown keys: "
+                f"{sorted(unknown_keys)}. Allowed keys: {sorted(allowed_keys)}",
+            )
+
+        for key in allowed_keys:
             if key not in self.improvements:
                 continue
             value = self.improvements[key]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/agent_config.py` around lines 317 - 330, The validation for
self.improvements currently only checks known keys but silently accepts unknown
ones; update the validation in the same block that references self.improvements
and the keys ("min_transformative", "min_structural", "min_non_incremental") to
detect any keys outside this allowed set and raise a ValueError listing the
invalid keys (or a clear message) so typos/unknown config entries are rejected
rather than ignored.
massgen/frontend/displays/textual_widgets/quickstart_wizard.py (1)

313-317: Validate default_effort against available choices before persisting it.

At Line [315] and Line [595], selected_effort is set directly from default_effort. If profile defaults drift from available choices, state can retain an invalid value.

♻️ Proposed hardening
@@
         choices = profile.get("choices", [])
         default_effort = profile.get("default_effort", "medium")
-        selected_effort = default_effort
+        choice_values = {
+            choice[1] if isinstance(choice, tuple) and len(choice) > 1 else choice
+            for choice in choices
+        }
+        selected_effort = (
+            default_effort
+            if default_effort in choice_values
+            else next(iter(choice_values), None)
+        )
+        if selected_effort is None:
+            self._current_reasoning_effort = None
+            self._set_reasoning_visibility(False)
+            return

Also applies to: 593-597

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/frontend/displays/textual_widgets/quickstart_wizard.py` around lines
313 - 317, Validate that profile["default_effort"] exists in the
profile["choices"] before assigning it to state: obtain choices =
profile.get("choices", []), get default_effort = profile.get("default_effort",
"medium"), then set selected_effort = default_effort if default_effort in
choices else (choices[0] if choices else "medium"); finally assign
self._current_reasoning_effort = selected_effort. Apply the same validation
logic wherever selected_effort/default_effort is used (e.g., the other
occurrence assigning self._current_reasoning_effort) to avoid persisting an
invalid value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@massgen/agent_config.py`:
- Around line 87-93: The docstring describing the learning_capture_mode options
is stale: it claims "final_only" is the default but the actual default value for
learning_capture_mode is "verification_and_final_only"; update the docstring
text near the learning_capture_mode description to state that
"verification_and_final_only" is the default (and adjust any explanatory bullets
if needed to match that default behavior), referencing the learning_capture_mode
setting so you change the documented default to align with the runtime default.
- Around line 311-313: Add a Google-style docstring to the newly introduced
_validate_improvements method to describe its purpose and contract; include a
short one-line summary ("Validate improvements quality-gate configuration."), an
Args section documenting self, a Returns section stating None, and a Raises
section noting the exception type raised on invalid configuration (e.g.,
ValueError) so callers know what to expect; place this docstring immediately
under the def _validate_improvements(self): signature in
massgen/agent_config.py.

In `@massgen/cli.py`:
- Around line 462-473: Update the docstrings for _format_chunk_target_line and
should_include_quick_edit_hint to use Google-style format: add an Args section
describing the parameter (target_chunks: int | None for
_format_chunk_target_line, planning_turn_mode: str | None for
should_include_quick_edit_hint) and a Returns section describing the return type
and meaning (str for both; describe the exact string semantics). Keep the
existing one-line summary, then append the Args and Returns blocks following
Google-style conventions.

In `@massgen/coordination_tracker.py`:
- Around line 267-275: get_path_token currently returns a freshly generated
token for unknown agent_ids without persisting it, so repeated calls can return
different tokens; modify get_path_token to generate a token with
secrets.token_hex(4) only when agent_id is not present in self._path_tokens,
store that token into self._path_tokens[agent_id], and then return it (keep the
existing behavior for registered agent_ids); reference: get_path_token and the
_path_tokens mapping.

In `@massgen/filesystem_manager/_filesystem_manager.py`:
- Around line 429-440: The code uses workspace_token directly in filesystem
paths (used in _setup_workspace and when building
snapshot_storage/agent_temporary_workspace), which allows absolute paths or
path-traversal; add a validation/sanitization step (e.g., a new helper
validate_or_sanitize_workspace_token(token)) and call it before assigning
self.workspace_token or passing it into _setup_workspace or Path concatenation;
the validator should reject/normalize absolute paths, strip path separators,
forbid '..' segments, and permit only a safe whitelist (e.g., alphanumeric,
dash, underscore) or replace invalid tokens with a safe fallback (UUID/hex);
update usage sites (workspace_token assignment and the _setup_workspace call
that constructs self.agent_temporary_workspace from
self.agent_temporary_workspace_parent / self.workspace_token) to use the
validated token and raise/log an error if validation fails.

In `@massgen/frontend/displays/textual_widgets/quickstart_wizard.py`:
- Around line 459-464: Replace the empty bare-except blocks that swallow errors
when restoring reasoning state (the try/except around assigning
self._reasoning_select.value and setting self._current_reasoning_effort) with
explicit exception handling that logs the exception; e.g., catch Exception as e
and call an appropriate logger (self._logger.exception(...) if available,
otherwise use the logging module via logging.exception(...)) with a clear
message like "failed to restore reasoning effort" and include the saved value,
and keep this change in both places where the silent except appears so failures
are visible for debugging.
- Line 1815: The new step-branching logic (the skip_condition lambda using
state.get("agent_count", 3) and state.get("setup_mode"), plus the dynamic
insertion behavior around lines 1890-1923) needs explicit regression tests: add
unit/integration tests that exercise the quickstart wizard flow for (a)
agent_count == 1, (b) agent_count > 1 with setup_mode == "same", and (c)
agent_count > 1 with setup_mode == "different", asserting the expected steps are
skipped or inserted accordingly; in tests call the same entry points that drive
the wizard (the quickstart wizard handler/orchestrator entry used in this diff)
and manipulate state["agent_count"] and state["setup_mode"] to verify
skip_condition and the dynamic insertion paths, failing the PR if any of the
three scenarios diverge.

---

Nitpick comments:
In `@massgen/agent_config.py`:
- Around line 317-330: The validation for self.improvements currently only
checks known keys but silently accepts unknown ones; update the validation in
the same block that references self.improvements and the keys
("min_transformative", "min_structural", "min_non_incremental") to detect any
keys outside this allowed set and raise a ValueError listing the invalid keys
(or a clear message) so typos/unknown config entries are rejected rather than
ignored.

In `@massgen/backend/gemini.py`:
- Around line 338-370: The _normalize_and_resolve_tool_name method lacks
None-guards for self._mcp_functions and self._custom_tool_names and its
docstring is missing Google-style Args/Returns; update the docstring to include
short description plus Args (tool_name: str) and Returns (str) sections, and add
defensive checks using e.g. local variables like mcp_funcs = self._mcp_functions
or {} and custom_names = self._custom_tool_names or set() and then replace
direct accesses to self._mcp_functions/_custom_tool_names with those locals so
the function safely handles None values while preserving existing resolution
logic (including checks for "mcp__" and "custom_tool__" prefixes and the
mcp_alias lookup).

In `@massgen/evaluation_criteria_generator.py`:
- Around line 849-864: The comment "Simplified agent configs (no tools, pure LLM
reasoning)" above the loop that builds simplified from agent_configs is stale
because the backend dict sets "exclude_file_operation_mcps": False, so
file-operation MCPs remain enabled; update that comment to accurately describe
the behavior (e.g., "Simplified agent configs (no external tools/command-line
MCPs; file-operation MCPs retained)") and ensure it references the code that
sets enable_mcp_command_line, enable_code_based_tools, and
exclude_file_operation_mcps in the simplified backend.

In `@massgen/frontend/displays/textual_widgets/quickstart_wizard.py`:
- Around line 313-317: Validate that profile["default_effort"] exists in the
profile["choices"] before assigning it to state: obtain choices =
profile.get("choices", []), get default_effort = profile.get("default_effort",
"medium"), then set selected_effort = default_effort if default_effort in
choices else (choices[0] if choices else "medium"); finally assign
self._current_reasoning_effort = selected_effort. Apply the same validation
logic wherever selected_effort/default_effort is used (e.g., the other
occurrence assigning self._current_reasoning_effort) to avoid persisting an
invalid value.

In `@massgen/frontend/web/server.py`:
- Around line 4871-4874: The CoordinationConfig construction is duplicated in
run_coordination and run_coordination_with_history; extract a helper function
named _build_coordination_config(coord_cfg: dict) -> CoordinationConfig that
encapsulates the current construction logic (including
disable_final_only_round_capture_fallback and all other fields used in both
locations) and replace the inline builds in run_coordination and
run_coordination_with_history with calls to
_build_coordination_config(coord_cfg) so both functions use the single shared
factory.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9ed033a5-affe-40a2-b986-890112cabe2b

📥 Commits

Reviewing files that changed from the base of the PR and between 93a79ff and 623ee52.

⛔ Files ignored due to path filters (106)
  • docs/source/_static/images/readme.gif is excluded by !**/*.gif, !**/*.gif
  • massgen/frontend/web/static/assets/_baseUniq-AVQuLNgG.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/_baseUniq-AVQuLNgG.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/arc-DPg5OnLA.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/arc-DPg5OnLA.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/architectureDiagram-VXUJARFQ-D3lxBS0w.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/architectureDiagram-VXUJARFQ-D3lxBS0w.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/base-80a1f760-BjKqezyN.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/base-80a1f760-BjKqezyN.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/blockDiagram-VD42YOAC-Df0BbuW_.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/blockDiagram-VD42YOAC-Df0BbuW_.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/c4Diagram-YG6GDRKO-CAQ4nRHx.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/c4Diagram-YG6GDRKO-CAQ4nRHx.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/channel-BhzQJK09.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/channel-BhzQJK09.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/channel-D0pBKfCz.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-4BX2VUAB-B20LnYuB.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-4BX2VUAB-B20LnYuB.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-55IACEB6-BWGMW8Vm.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-55IACEB6-BWGMW8Vm.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-B4BG7PRW-ClZ5TgR0.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-B4BG7PRW-ClZ5TgR0.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-DI55MBZ5-Dc2ha-30.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-DI55MBZ5-Dc2ha-30.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-FMBD7UC4-yiugaJUa.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-FMBD7UC4-yiugaJUa.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-QN33PNHL-CIcC1sfw.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-QN33PNHL-CIcC1sfw.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-QZHKN3VN-CuDZpdaD.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-QZHKN3VN-CuDZpdaD.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/chunk-TZMSLE5B-D655xVqH.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/chunk-TZMSLE5B-D655xVqH.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/classDiagram-2ON5EDUG-B8iqM3hs.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/classDiagram-2ON5EDUG-XgpY-eTv.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/classDiagram-2ON5EDUG-XgpY-eTv.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/classDiagram-v2-WZHVMYZB-B8iqM3hs.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/classDiagram-v2-WZHVMYZB-XgpY-eTv.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/classDiagram-v2-WZHVMYZB-XgpY-eTv.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/clone-DSpvyh0c.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/clone-DSpvyh0c.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/clone-dVHY6V2C.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/consoleHook-59e792cb-KmOPYMUg.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/consoleHook-59e792cb-KmOPYMUg.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/cose-bilkent-S5V4N54A-Dq3BKwwh.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/cose-bilkent-S5V4N54A-Dq3BKwwh.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/dagre-6UL2VRFP-CmrIRMzL.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/dagre-6UL2VRFP-CmrIRMzL.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/diagram-PSM6KHXK-BQgucv5d.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/diagram-PSM6KHXK-BQgucv5d.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/diagram-QEK2KX5R-Catj1rLJ.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/diagram-QEK2KX5R-Catj1rLJ.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/diagram-S2PKOQOG-VXJN1JaO.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/diagram-S2PKOQOG-VXJN1JaO.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/erDiagram-Q2GNP2WA-CPGS8tEN.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/erDiagram-Q2GNP2WA-CPGS8tEN.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/flowDiagram-NV44I4VS-hAegpCjE.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/flowDiagram-NV44I4VS-hAegpCjE.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/ganttDiagram-JELNMOA3-C-7qBc2P.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/ganttDiagram-JELNMOA3-C-7qBc2P.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/gitGraphDiagram-NY62KEGX-D9qnlshv.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/gitGraphDiagram-NY62KEGX-D9qnlshv.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/graph-B6okqyVZ.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/graph-B6okqyVZ.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/index-599aeaf7-JXrsLrix.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/index-599aeaf7-JXrsLrix.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/index-BOesCYHe.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/index-BOesCYHe.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/index-C5CsgCb4.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/index-C5CsgCb4.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/index-D2vUXYM2.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/index-D2vUXYM2.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/infoDiagram-WHAUD3N6-B_3Q_RkO.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/infoDiagram-WHAUD3N6-B_3Q_RkO.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/journeyDiagram-XKPGCS4Q-CeNyXUtm.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/journeyDiagram-XKPGCS4Q-CeNyXUtm.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/kanban-definition-3W4ZIXB7-103x-s8b.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/kanban-definition-3W4ZIXB7-103x-s8b.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/layout-GkxW5DBM.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/layout-GkxW5DBM.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/linear-BSHJYnL5.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/linear-BSHJYnL5.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/min-CRnWvUj0.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/min-CRnWvUj0.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/mindmap-definition-VGOIOE7T-0_XShANc.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/mindmap-definition-VGOIOE7T-0_XShANc.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/pieDiagram-ADFJNKIX-_2PFyUu6.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/pieDiagram-ADFJNKIX-_2PFyUu6.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/quadrantDiagram-AYHSOK5B-vw--f_Dw.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/quadrantDiagram-AYHSOK5B-vw--f_Dw.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/requirementDiagram-UZGBJVZJ-9aYMn9Fu.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/requirementDiagram-UZGBJVZJ-9aYMn9Fu.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/sankeyDiagram-TZEHDZUN-3I1RkOCW.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/sankeyDiagram-TZEHDZUN-3I1RkOCW.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/sequenceDiagram-WL72ISMW-BEwD3Anh.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/sequenceDiagram-WL72ISMW-BEwD3Anh.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/stateDiagram-FKZM4ZOC-Dmc3fwx3.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/stateDiagram-FKZM4ZOC-Dmc3fwx3.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/stateDiagram-v2-4FDKWEC3-Cwy05MBx.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/stateDiagram-v2-4FDKWEC3-Cwy05MBx.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/stateDiagram-v2-4FDKWEC3-DTF_pzMQ.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/timeline-definition-IT6M3QCI-DlU2EEc7.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/timeline-definition-IT6M3QCI-DlU2EEc7.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/treemap-KMMF4GRG-1GASY6Y-.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/treemap-KMMF4GRG-1GASY6Y-.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
  • massgen/frontend/web/static/assets/xychartDiagram-PRI3JC2R-CaJQ0NZo.js is excluded by !massgen/frontend/web/static/assets/**
  • massgen/frontend/web/static/assets/xychartDiagram-PRI3JC2R-CaJQ0NZo.js.map is excluded by !**/*.map, !massgen/frontend/web/static/assets/**, !**/*.map
📒 Files selected for processing (67)
  • README.md
  • README_PYPI.md
  • docs/modules/coordination_workflow.md
  • docs/source/index.rst
  • massgen/agent_config.py
  • massgen/api_params_handler/_api_params_handler_base.py
  • massgen/backend/base.py
  • massgen/backend/capabilities.py
  • massgen/backend/gemini.py
  • massgen/cli.py
  • massgen/config_builder.py
  • massgen/config_validator.py
  • massgen/coordination_tracker.py
  • massgen/docker/Dockerfile.sudo
  • massgen/evaluation_criteria_generator.py
  • massgen/filesystem_manager/_docker_manager.py
  • massgen/filesystem_manager/_filesystem_manager.py
  • massgen/frontend/displays/textual_widgets/quickstart_wizard.py
  • massgen/frontend/web/server.py
  • massgen/frontend/web/static/index.html
  • massgen/mcp_tools/checklist_tools_server.py
  • massgen/mcp_tools/custom_tools_server.py
  • massgen/mcp_tools/planning/_planning_mcp_server.py
  • massgen/mcp_tools/planning/planning_dataclasses.py
  • massgen/orchestrator.py
  • massgen/skills/video-generation/SKILL.md
  • massgen/skills/video-generation/references/production.md
  • massgen/subagent/manager.py
  • massgen/subagent_types/builder/SUBAGENT.md
  • massgen/subagent_types/evaluator/SUBAGENT.md
  • massgen/subagent_types/novelty/SUBAGENT.md
  • massgen/subagent_types/quality_rethinking/SUBAGENT.md
  • massgen/system_message_builder.py
  • massgen/system_prompt_sections.py
  • massgen/tests/frontend/test_quickstart_wizard_config_filename.py
  • massgen/tests/test_answer_count_increment.py
  • massgen/tests/test_api_params_exclusion.py
  • massgen/tests/test_backend_capabilities.py
  • massgen/tests/test_changedoc_system_prompt.py
  • massgen/tests/test_checklist_tools_server.py
  • massgen/tests/test_concurrent_logging_sessions.py
  • massgen/tests/test_config_builder.py
  • massgen/tests/test_config_validator.py
  • massgen/tests/test_convergence_novelty.py
  • massgen/tests/test_coordination_improvements_config.py
  • massgen/tests/test_custom_tools_server_background.py
  • massgen/tests/test_docker_skills_write_access.py
  • massgen/tests/test_evaluation_criteria_generator.py
  • massgen/tests/test_filesystem_manager_workspace_token.py
  • massgen/tests/test_gemini_tool_name_normalization.py
  • massgen/tests/test_novelty_injection.py
  • massgen/tests/test_plan_mode_chunk_defaults.py
  • massgen/tests/test_plan_review_prompt_refinement.py
  • massgen/tests/test_planning_injection.py
  • massgen/tests/test_planning_tools.py
  • massgen/tests/test_read_media_analysis.py
  • massgen/tests/test_refinement_quality.py
  • massgen/tests/test_specialized_subagents.py
  • massgen/tests/test_subagent_docker_logs.py
  • massgen/tests/test_subagent_manager.py
  • massgen/tests/test_system_message_builder_phases.py
  • massgen/tests/test_system_prompt_sections.py
  • massgen/tests/unit/test_coordination_tracker.py
  • massgen/tool/_multimodal_tools/backend_selector.py
  • massgen/tool/_multimodal_tools/read_media.py
  • massgen/tool/_multimodal_tools/understand_video.py
  • webui/src/stores/wizardStore.ts

Comment on lines +87 to 93
- "round": full round-time capture (evolving skills + memory reminders/tasks)
- "verification_and_final_only": round-time verification replay memo only;
full consolidation remains presenter/final-time
- "final_only": defer all learning capture to presenter/final-time
- "round": Existing behavior. Capture can be produced in coordination rounds.
- "final_only" (default): Keep changedoc behavior, but defer evolving-skill + memory production
to the final presenter stage. Coordination rounds remain read-focused.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix the learning_capture_mode default documented in the docstring.

Lines [91-93] still describe "final_only" as default, but Line [181] sets "verification_and_final_only" as default.

📝 Proposed doc fix
@@
-        learning_capture_mode: Controls when evolving-skill + memory capture is produced.
-            - "round": full round-time capture (evolving skills + memory reminders/tasks)
-            - "verification_and_final_only": round-time verification replay memo only;
-              full consolidation remains presenter/final-time
-            - "final_only": defer all learning capture to presenter/final-time
-                              - "round": Existing behavior. Capture can be produced in coordination rounds.
-                              - "final_only" (default): Keep changedoc behavior, but defer evolving-skill + memory production
-                                to the final presenter stage. Coordination rounds remain read-focused.
+        learning_capture_mode: Controls when evolving-skill + memory capture is produced.
+            - "round": Existing behavior. Capture can be produced in coordination rounds.
+            - "verification_and_final_only" (default): round-time verification replay memo only;
+              full consolidation remains presenter/final-time.
+            - "final_only": defer all learning capture to presenter/final-time.

Also applies to: 181-181

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/agent_config.py` around lines 87 - 93, The docstring describing the
learning_capture_mode options is stale: it claims "final_only" is the default
but the actual default value for learning_capture_mode is
"verification_and_final_only"; update the docstring text near the
learning_capture_mode description to state that "verification_and_final_only" is
the default (and adjust any explanatory bullets if needed to match that default
behavior), referencing the learning_capture_mode setting so you change the
documented default to align with the runtime default.

Comment on lines +311 to +313
def _validate_improvements(self):
"""Validate improvements quality-gate configuration."""
if self.improvements is None:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add a Google-style docstring for the new validator.

_validate_improvements is newly introduced but does not use a Google-style docstring.

📝 Proposed docstring shape
@@
     def _validate_improvements(self):
-        """Validate improvements quality-gate configuration."""
+        """Validate improvements quality-gate configuration.
+
+        Raises:
+            ValueError: If `improvements` is not a dict, contains unknown keys,
+                or has invalid threshold values.
+        """

As per coding guidelines "**/*.py: For new or changed functions, include Google-style docstrings"

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _validate_improvements(self):
"""Validate improvements quality-gate configuration."""
if self.improvements is None:
def _validate_improvements(self):
"""Validate improvements quality-gate configuration.
Raises:
ValueError: If `improvements` is not a dict, contains unknown keys,
or has invalid threshold values.
"""
if self.improvements is None:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/agent_config.py` around lines 311 - 313, Add a Google-style docstring
to the newly introduced _validate_improvements method to describe its purpose
and contract; include a short one-line summary ("Validate improvements
quality-gate configuration."), an Args section documenting self, a Returns
section stating None, and a Raises section noting the exception type raised on
invalid configuration (e.g., ValueError) so callers know what to expect; place
this docstring immediately under the def _validate_improvements(self): signature
in massgen/agent_config.py.

Comment on lines +462 to +473
def _format_chunk_target_line(target_chunks: int | None) -> str:
"""Return chunk guidance text for planning/spec prompts."""
if target_chunks == 1 or target_chunks is None:
return "- Target chunks: exactly 1"
if target_chunks > 1:
return f"- Target chunks: around {target_chunks}"
return "- Target chunks: exactly 1"


def should_include_quick_edit_hint(planning_turn_mode: str | None) -> bool:
"""Show quick-edit hint only for explicit single-turn refinement mode."""
return planning_turn_mode == "single"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use Google-style docstrings for the new helper functions.

Line 462 and Line 471 add new functions, but their docstrings omit Google-style Args/Returns sections required for changed Python functions in this repo.

✍️ Proposed docstring update
 def _format_chunk_target_line(target_chunks: int | None) -> str:
-    """Return chunk guidance text for planning/spec prompts."""
+    """Return chunk guidance text for planning/spec prompts.
+
+    Args:
+        target_chunks: Desired number of chunks, or None for default behavior.
+
+    Returns:
+        Chunk guidance line formatted for inclusion in prompts.
+    """
@@
 def should_include_quick_edit_hint(planning_turn_mode: str | None) -> bool:
-    """Show quick-edit hint only for explicit single-turn refinement mode."""
+    """Determine whether to include the quick-edit hint.
+
+    Args:
+        planning_turn_mode: Planning turn mode string, if set.
+
+    Returns:
+        True when quick-edit hint should be included; otherwise False.
+    """
     return planning_turn_mode == "single"

As per coding guidelines: **/*.py: For new or changed functions, include Google-style docstrings.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/cli.py` around lines 462 - 473, Update the docstrings for
_format_chunk_target_line and should_include_quick_edit_hint to use Google-style
format: add an Args section describing the parameter (target_chunks: int | None
for _format_chunk_target_line, planning_turn_mode: str | None for
should_include_quick_edit_hint) and a Returns section describing the return type
and meaning (str for both; describe the exact string semantics). Keep the
existing one-line summary, then append the Args and Returns blocks following
Google-style conventions.

Comment on lines +267 to +275
def get_path_token(self, agent_id: str) -> str:
"""Get stable anonymous path token for this agent's workspace directories.

Returns an 8-character hex string that is stable within a session but
does not reveal the real agent_id. Falls back to generating a new token
if the agent_id was not registered at session initialization.
"""
return self._path_tokens.get(agent_id, secrets.token_hex(4))

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Persist fallback tokens to keep path mapping stable.

Line 274 generates a new token for unknown agents but does not store it, so repeated calls can return different values for the same agent_id.

🔧 Suggested fix
     def get_path_token(self, agent_id: str) -> str:
@@
-        return self._path_tokens.get(agent_id, secrets.token_hex(4))
+        token = self._path_tokens.get(agent_id)
+        if token is None:
+            token = secrets.token_hex(4)
+            self._path_tokens[agent_id] = token
+        return token
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_path_token(self, agent_id: str) -> str:
"""Get stable anonymous path token for this agent's workspace directories.
Returns an 8-character hex string that is stable within a session but
does not reveal the real agent_id. Falls back to generating a new token
if the agent_id was not registered at session initialization.
"""
return self._path_tokens.get(agent_id, secrets.token_hex(4))
def get_path_token(self, agent_id: str) -> str:
"""Get stable anonymous path token for this agent's workspace directories.
Returns an 8-character hex string that is stable within a session but
does not reveal the real agent_id. Falls back to generating a new token
if the agent_id was not registered at session initialization.
"""
token = self._path_tokens.get(agent_id)
if token is None:
token = secrets.token_hex(4)
self._path_tokens[agent_id] = token
return token
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/coordination_tracker.py` around lines 267 - 275, get_path_token
currently returns a freshly generated token for unknown agent_ids without
persisting it, so repeated calls can return different tokens; modify
get_path_token to generate a token with secrets.token_hex(4) only when agent_id
is not present in self._path_tokens, store that token into
self._path_tokens[agent_id], and then return it (keep the existing behavior for
registered agent_ids); reference: get_path_token and the _path_tokens mapping.

Comment on lines +429 to 440
# Use token for temp workspace path to avoid leaking real agent_id (MAS-338)
self.workspace_token = workspace_token or agent_id

# Setup snapshot storage if provided
if snapshot_storage and self.agent_id:
self.snapshot_storage = Path(snapshot_storage) / self.agent_id
self.snapshot_storage.mkdir(parents=True, exist_ok=True)

# Setup temporary workspace for context sharing
# Setup temporary workspace for context sharing (uses token to hide real agent_id)
if agent_temporary_workspace and self.agent_id:
self.agent_temporary_workspace = self._setup_workspace(self.agent_temporary_workspace_parent / self.agent_id)
self.agent_temporary_workspace = self._setup_workspace(self.agent_temporary_workspace_parent / self.workspace_token)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Validate workspace_token before using it in filesystem paths.

Line 430 accepts arbitrary token text, and Line 439 feeds it into _setup_workspace(), which clears directory contents. A malformed token (e.g., absolute path or traversal segments) can target unintended directories.

🛡️ Proposed hardening
         self.agent_id = agent_id
-        # Use token for temp workspace path to avoid leaking real agent_id (MAS-338)
-        self.workspace_token = workspace_token or agent_id
+        # Use token for temp workspace path to avoid leaking real agent_id (MAS-338)
+        token = (workspace_token or agent_id).strip()
+        token_path = Path(token)
+        if not token or token_path.is_absolute() or len(token_path.parts) != 1 or token in {".", ".."}:
+            raise ValueError(f"Invalid workspace_token: {workspace_token!r}")
+        self.workspace_token = token
@@
         # Setup temporary workspace for context sharing (uses token to hide real agent_id)
         if agent_temporary_workspace and self.agent_id:
-            self.agent_temporary_workspace = self._setup_workspace(self.agent_temporary_workspace_parent / self.workspace_token)
+            if not self.agent_temporary_workspace_parent:
+                raise ValueError("agent_temporary_workspace_parent must be configured when temp workspace is enabled")
+            temp_parent = Path(self.agent_temporary_workspace_parent).resolve()
+            temp_workspace_path = (temp_parent / self.workspace_token).resolve()
+            try:
+                temp_workspace_path.relative_to(temp_parent)
+            except ValueError as exc:
+                raise ValueError(
+                    f"workspace_token escapes temp workspace parent: {self.workspace_token!r}",
+                ) from exc
+            self.agent_temporary_workspace = self._setup_workspace(str(temp_workspace_path))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/filesystem_manager/_filesystem_manager.py` around lines 429 - 440,
The code uses workspace_token directly in filesystem paths (used in
_setup_workspace and when building snapshot_storage/agent_temporary_workspace),
which allows absolute paths or path-traversal; add a validation/sanitization
step (e.g., a new helper validate_or_sanitize_workspace_token(token)) and call
it before assigning self.workspace_token or passing it into _setup_workspace or
Path concatenation; the validator should reject/normalize absolute paths, strip
path separators, forbid '..' segments, and permit only a safe whitelist (e.g.,
alphanumeric, dash, underscore) or replace invalid tokens with a safe fallback
(UUID/hex); update usage sites (workspace_token assignment and the
_setup_workspace call that constructs self.agent_temporary_workspace from
self.agent_temporary_workspace_parent / self.workspace_token) to use the
validated token and raise/log an error if validation fails.

Comment on lines +459 to +464
if saved_reasoning_effort and self._reasoning_select:
try:
self._reasoning_select.value = saved_reasoning_effort
self._current_reasoning_effort = saved_reasoning_effort
except Exception:
pass
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stop swallowing reasoning-restore errors silently.

At Line [463] and Line [770], exceptions are ignored, which makes state-restore failures invisible and hard to debug.

🛠️ Proposed fix
@@
             if saved_reasoning_effort and self._reasoning_select:
                 try:
                     self._reasoning_select.value = saved_reasoning_effort
                     self._current_reasoning_effort = saved_reasoning_effort
-                except Exception:
-                    pass
+                except Exception as e:
+                    _quickstart_log(
+                        "ProviderModelStep.set_value: failed to restore "
+                        f"reasoning_effort={saved_reasoning_effort!r}: {e}"
+                    )
@@
                 if reasoning_select and reasoning_effort:
                     try:
                         reasoning_select.value = reasoning_effort
                         self._tab_selections[agent_key]["reasoning_effort"] = reasoning_effort
-                    except Exception:
-                        pass
+                    except Exception as e:
+                        _quickstart_log(
+                            "TabbedProviderModelStep.set_value: failed to restore "
+                            f"agent={agent_key} reasoning_effort={reasoning_effort!r}: {e}"
+                        )

Also applies to: 765-771

🧰 Tools
🪛 Ruff (0.15.2)

[error] 463-464: try-except-pass detected, consider logging the exception

(S110)


[warning] 463-463: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/frontend/displays/textual_widgets/quickstart_wizard.py` around lines
459 - 464, Replace the empty bare-except blocks that swallow errors when
restoring reasoning state (the try/except around assigning
self._reasoning_select.value and setting self._current_reasoning_effort) with
explicit exception handling that logs the exception; e.g., catch Exception as e
and call an appropriate logger (self._logger.exception(...) if available,
otherwise use the logging module via logging.exception(...)) with a clear
message like "failed to restore reasoning effort" and include the saved value,
and keep this change in both places where the silent except appears so failures
are visible for debugging.

description="Choose your AI provider and model",
component_class=ProviderModelStep,
skip_condition=lambda state: state.get("setup_mode") == "different",
skip_condition=lambda state: state.get("agent_count", 3) > 1 and state.get("setup_mode") == "different",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add regression tests for the new step-branching behavior before merge.

Lines [1815] and [1890-1923] materially change navigation flow (agent_count × setup_mode × dynamic insertion). Please add explicit coverage for:

  • 1 agent
  • multi-agent + same
  • multi-agent + different

Based on learnings: "Any change touching orchestrator.py, chat_agent.py, backend/*.py, mcp_tools/, or coordination_tracker.py is always non-trivial and requires TDD. Any change to TUI widgets, content handlers, or event processing is always non-trivial. Any change to system prompts, config validation, or YAML parsing is always non-trivial"

Also applies to: 1890-1923

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@massgen/frontend/displays/textual_widgets/quickstart_wizard.py` at line 1815,
The new step-branching logic (the skip_condition lambda using
state.get("agent_count", 3) and state.get("setup_mode"), plus the dynamic
insertion behavior around lines 1890-1923) needs explicit regression tests: add
unit/integration tests that exercise the quickstart wizard flow for (a)
agent_count == 1, (b) agent_count > 1 with setup_mode == "same", and (c)
agent_count > 1 with setup_mode == "different", asserting the expected steps are
skipped or inserted accordingly; in tests call the same entry points that drive
the wizard (the quickstart wizard handler/orchestrator entry used in this diff)
and manipulate state["agent_count"] and state["setup_mode"] to verify
skip_condition and the dynamic insertion paths, failing the PR if any of the
three scenarios diverge.

@Henry-811 Henry-811 changed the base branch from main to dev/v0.1.59 March 4, 2026 17:08
@Henry-811 Henry-811 merged commit 05b345c into dev/v0.1.59 Mar 4, 2026
20 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants