Auto-generate description labels and extend DEPENDENCIES schema#1133
Auto-generate description labels and extend DEPENDENCIES schema#1133sbryngelson merged 12 commits intoMFlowCode:masterfrom
Conversation
- Auto-append value_labels to descriptions in _r(), removing hardcoded label parentheticals from _SIMPLE_DESCS (7 entries) and DESCRIPTIONS (10 entries). Descriptions now stay in sync with CONSTRAINTS. - Add requires_value and when_value to DEPENDENCIES schema with full validation, error formatting, and dependency checking support. - Add DEPENDENCIES entries for bubbles_euler (requires model_eqns, riemann_solver, avg_state values) and model_eqns (when_value for models 2, 3, 4). - Extend docs_gen.py and gen_case_constraints_docs.py to render new schema keys with human-readable labels from get_value_label(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- validate.py: condition_label is Optional[str] (None for when_set) - definitions.py: add annotations to inner _validate_condition closure - docs_gen.py: use generic Dict/List types for _format_requires_value and _format_condition Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- __init__.py: re-export CONSTRAINTS, DEPENDENCIES, get_value_label from the params package (needed by gen_case_constraints_docs.py) - case_validator.py: replace hardcoded error hints with data-driven loop over CONSTRAINTS value_labels - CMakeLists.txt: add definitions.py to DEPENDS for doc generation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix _get_family() regex to match uppercase (chem_wrt_Y), eliminating spurious pattern view for the general family. Skip rendering value_labels in constraints since they are already in descriptions. Add 15 new DEPENDENCIES entries for stretch, body force, TENO, MUSCL, surface tension, MHD, relativity, schlieren, CFL, and integral parameters. Fix all pylint warnings to achieve 10.00/10. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a dedicated Constraints column to the full table view instead of stuffing dependency info into the Description parenthetically. Reformat dependency text with backtick-wrapped param names and leading action (e.g. 'Requires `a_x`, `x_a`, `x_b` when enabled'). Add value labels to when_value conditions for readability. Add range constraints for dt, t_stop, t_save, cfl_target, cfl_max, weno_eps, R0ref, sigma, nb, num_source, num_probes, num_integrals, t_step_save, t_step_print. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the AST analyzer (Rule, CaseValidatorAnalyzer, classify_message, etc.) from gen_case_constraints_docs.py into a shared module at params/ast_analyzer.py. Add f-string message extraction (106 previously invisible rules now captured, 333 total), trigger-param detection via method guards and condition analysis, and an analyze_case_validator() convenience function. docs_gen.py now reads constraints from AST-extracted rules instead of the manually maintained DEPENDENCIES dict, populating 61% of table rows with validator constraints. Parameter names in messages are wrapped in backticks with word-boundary matching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Alias map resolves boolean combination assignments (e.g. variable_dt = cfl_dt or cfl_adap_dt) so prohibit rules using those aliases attribute constraints to the underlying params. If-guard enrichment adds enclosing if-condition params (perturb_flow, down_sample, etc.) to rules within the block. Tag-based fallback labels output flags and DEPENDENCIES info when no other constraints exist. Coverage rises from 64% to 83%. Fix Doxygen rendering: compound param names (bub_pp%mu_g, x_output%beg) wrapped in backticks as a unit, snake_case identifiers backticked even when not in registry, bare % escaped outside code spans, and % no longer double-escaped inside backtick code spans. Fix description priority so hand-curated DESCRIPTIONS dict takes precedence over auto-generated text. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Validator: add 5 prohibit() statements for previously unchecked params: - igr_pres_lim requires igr - int_comp requires recon_type = 2 (MUSCL) - pre_stress requires hyperelasticity - sigR/sigV require qbmm Docs: extend _format_tag_annotation with reverse dependency lookup, feature tag labels, and prefix-group labels to cover params with no AST rules or schema constraints. Coverage 83% → 97% of general-family. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend doc generator with compound-name attribute annotation maps for indexed parameter families. Covers bc_x/y/z sub-params (GRCBC inflow/ outflow, boundary velocities), patch_bc geometry attributes, simplex perturbation params, and fluid_pp EOS properties. BC families: 5% → 100%, simplex_params: 0% → 100%, fluid_pp: 69% → 100%. Overall pattern-row coverage: 89.4%. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move hard-coded annotation dicts (BC, patch_bc, simplex, fluid_pp, tag labels, prefix labels) from docs_gen.py into definitions.py as HINTS, TAG_DISPLAY_NAMES, and PREFIX_HINTS. Add `hint` field to ParamDef and auto-populate it at registration time via _lookup_hint(), so new params get documented without editing the doc generator. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughRefactors docs generation to a schema- and AST-driven pipeline: adds an AST analyzer for CaseValidator, exposes CONSTRAINTS/DEPENDENCIES/value-label helpers, enhances parameter schema/hints and validation checks, and updates CMake docs dependencies to include new Python sources for doc generation. Changes
Sequence DiagramsequenceDiagram
participant Build as Build (CMake)
participant DocsGen as Docs Generator
participant AST as AST Analyzer
participant Validator as CaseValidator
participant Schema as Constraint Schema
Build->>DocsGen: trigger doc build
DocsGen->>AST: analyze_case_validator(case_validator.py)
AST->>Validator: parse logic & extract rules
AST->>Schema: map rules to CONSTRAINTS/DEPENDENCIES
DocsGen->>Schema: load CONSTRAINTS/DEPENDENCIES/get_value_label
DocsGen->>DocsGen: render markdown using analyzer + schema
DocsGen-->>Build: write generated docs
Validator->>Schema: import CONSTRAINTS/DEPENDENCIES
Validator->>Validator: perform validation checks (new gates)
Validator->>Schema: format errors using schema hints
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
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. Comment |
There was a problem hiding this comment.
Pull request overview
This pull request enhances the MFC parameter system with auto-generated documentation labels and extends the DEPENDENCIES schema to support value-specific constraints. The changes improve maintainability and reduce code duplication while making parameter documentation more data-driven.
Changes:
- Introduces a new AST analyzer module (
ast_analyzer.py) that extracts validation rules fromcase_validator.pyfor use in documentation generation - Extends the DEPENDENCIES schema with
when_value(value-specific conditions) andrequires_value(required specific values) capabilities - Adds
value_labelsto CONSTRAINTS for human-readable labels on integer choice parameters - Implements data-driven documentation generation using schema information and AST-extracted rules
- Refactors
gen_case_constraints_docs.pyto use shared AST analyzer instead of duplicated parsing logic
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| toolchain/mfc/params/ast_analyzer.py | New module for AST analysis of case_validator.py, extracts prohibit rules with trigger detection and f-string handling |
| toolchain/mfc/params/definitions.py | Extends CONSTRAINTS with value_labels, adds when_value/requires_value to DEPENDENCIES, adds HINTS and TAG_DISPLAY_NAMES dicts |
| toolchain/mfc/params/validate.py | Adds _check_condition helper, implements when_value validation and requires_value error checking |
| toolchain/mfc/params/errors.py | Adds dependency_value_error function for value-mismatch error messages |
| toolchain/mfc/params/generators/docs_gen.py | Implements backtick param wrapping, tag annotations, and AST rule formatting for documentation |
| toolchain/mfc/params/descriptions.py | Changes priority order: hand-curated > patterns > auto-generated > inferred |
| toolchain/mfc/params/schema.py | Adds hint field to ParamDef dataclass |
| toolchain/mfc/params/init.py | Exports CONSTRAINTS, DEPENDENCIES, and get_value_label |
| toolchain/mfc/case_validator.py | Adds new constraint checks, uses CONSTRAINTS for auto-generated error hints |
| toolchain/mfc/gen_case_constraints_docs.py | Refactored to use shared AST analyzer, data-driven model/solver documentation |
| CMakeLists.txt | Adds case_validator.py as dependency for parameters.md generation |
There was a problem hiding this comment.
1 issue found across 11 files
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="toolchain/mfc/params/ast_analyzer.py">
<violation number="1" location="toolchain/mfc/params/ast_analyzer.py:402">
P2: Trigger selection relies on ast.walk, which doesn’t preserve left‑to‑right source order, so the “first parameter” can be incorrect. Use a deterministic pre‑order traversal over iter_child_nodes to match source order.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
This is the final PR Bugbot will review for you during this billing cycle
Your free Bugbot reviews will reset on March 8
Details
You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
toolchain/mfc/params/definitions.py (2)
456-495:⚠️ Potential issue | 🟠 MajorTRY004 (type error handling) is enforced; use
TypeErrorfor type validation.The
ruff.tomlenables theTRYrule set (which includes TRY003/TRY004). Per TRY004, type validation errors should raiseTypeError, notValueError. The raises at lines 456-495 (in_validate_constraint) and 513-561 (in_validate_condition) that checkisinstance()conditions should be changed fromValueErrortoTypeError, or suppressed locally with# noqa: TRY004ifValueErrorsemantics are intentional.
590-679:⚠️ Potential issue | 🔴 CriticalFix constraint definitions to match validator semantics.
The CONSTRAINTS dict has two critical inconsistencies with actual validation logic:
weno_ordershould not include0in choices. The validator prohibits it (only allows[1, 3, 5, 7]), Fortran code never handles it, and tests treat it as an invalid mutation. Remove this value unless it's truly valid for MUSCL-mode scenarios.
num_source,num_probes, andnum_integralsmin constraints are too strict. These should allow0when their respective features are disabled:
num_sourceshould allow 0 whenacoustic_source=Fnum_probesshould allow 0 whenprobe_wrt=Fnum_integralsshould allow 0 whenintegral_wrt=FCurrently the CONSTRAINTS specify unconditional
{"min": 1}, but the validator only enforces the requirement conditionally (or not at all for probes/integrals). Either update CONSTRAINTS to reflect conditional semantics or add explicit validator checks.
🤖 Fix all issues with AI agents
In `@toolchain/mfc/gen_case_constraints_docs.py`:
- Line 696: Replace the f-string with a plain string where the f prefix is
unnecessary: change the lines.append call that currently reads
lines.append(f"\n<details>") to use a normal string
(lines.append("\n<details>")) so there are no stray f-strings; locate the call
to lines.append in gen_case_constraints_docs.py (the append call around the
"<details>" literal) and remove the leading f.
In `@toolchain/mfc/params/__init__.py`:
- Around line 28-33: The __all__ export list is unsorted which triggers Ruff
RUF022; reorder the entries in the __all__ list alphabetically (e.g.,
CONSTRAINTS, DEPENDENCIES, GET_VALUE_LABEL as appropriate casing—use the exact
names present: CONSTRAINTS, DEPENDENCIES, REGISTRY, RegistryFrozenError,
ParamDef, ParamType, get_value_label) so the list is sorted, or alternatively
add a targeted noqa for RUF022; update the __all__ declaration in this module to
the sorted order.
In `@toolchain/mfc/params/generators/docs_gen.py`:
- Around line 273-275: The signature of _format_validator_rules uses the Python
3.10 `|` union syntax (Dict[str, list] | None) which will break on Python <3.10
unless you enable postponed evaluation of annotations; update the file to either
replace the union with typing.Optional (e.g., Optional[Dict[str, list]] and add
Optional to the typing imports) or add from __future__ import annotations at the
top of the module so the existing signature remains valid; make the change
around the _format_validator_rules definition and the module imports (adjusting
the import line that currently brings in Dict/list types).
🧹 Nitpick comments (10)
toolchain/mfc/params/errors.py (1)
121-149: Makedependency_value_errorsignature + output formatting consistent with the other helpers.Minor polish: give
conditiona default (None), and consider formattingexpected_valuesviaformat_valueso string values don’t rely on Python’s raw list repr.Proposed tweak (signature + expected value formatting)
-def dependency_value_error( - param: str, - condition: Optional[str], - required_param: str, - expected_values: list, - got: Any, -) -> str: +def dependency_value_error( + param: str, + required_param: str, + expected_values: List[Any], + got: Any, + condition: Optional[str] = None, +) -> str: @@ - if condition: - return ( - f"{format_param(param)}{condition} requires {format_param(required_param)} " - f"to be one of {expected_values}, got {format_value(got)}" - ) + expected = "[" + ", ".join(format_value(v) for v in expected_values) + "]" + if condition: + return ( + f"{format_param(param)}{condition} requires {format_param(required_param)} " + f"to be one of {expected}, got {format_value(got)}" + ) return ( f"{format_param(param)} requires {format_param(required_param)} " - f"to be one of {expected_values}, got {format_value(got)}" + f"to be one of {expected}, got {format_value(got)}" )toolchain/mfc/params/validate.py (1)
30-38: Nice consolidation in_check_condition; consider treatingNonevalues as “unset”.Right now dependency presence checks use
key in params. If callers ever include{"foo": None}you’ll emit “got None” value-mismatch errors instead of a clearer “must be set”. Usingparams.get(key) is Nonealigns better with the “to be set” wording.Proposed tweak (treat None as missing)
def _check_condition( # pylint: disable=too-many-arguments,too-many-positional-arguments @@ """Check a single condition dict (requires, recommends, requires_value).""" if "requires" in condition: for req in condition["requires"]: - if req not in params: + if params.get(req) is None: errors.append(dependency_error(name, req, condition_label)) @@ if "recommends" in condition: for rec in condition["recommends"]: - if rec not in params: + if params.get(rec) is None: warnings.append(dependency_recommendation(name, rec, condition_label)) @@ if "requires_value" in condition: for req_param, expected_vals in condition["requires_value"].items(): - if req_param not in params: + if params.get(req_param) is None: errors.append(dependency_error(name, req_param, condition_label)) else: got = params[req_param] if got not in expected_vals:Also applies to: 99-167
toolchain/mfc/case_validator.py (2)
20-21: Consider mirroring these simple cross-param checks intoparams/DEPENDENCIESas well.The new guards (
igr_pres_lim → igr,int_comp → recon_type==2,sigR/sigV → qbmm,pre_stress → hyperelasticity) are the kind of relationships that seem reusable by the generic dependency checker too (especially now thatrequires_valueexists). That would give consistent errors whether users runparams/validate.pyorcase_validator.py.Also applies to: 145-152, 195-202, 392-398, 1216-1222
1929-1953: Dynamic value-label hints are helpful; matching by substring is a bit fuzzy.
if param_name not in err_lowercan attach hints for the “wrong” param when an error mentions multiple params (e.g., bothriemann_solverandwave_speeds). Not a blocker, but if you see mis-hints in practice, consider extracting the “primary” param from the error prefix instead of scanning all constraints.toolchain/mfc/params/definitions.py (2)
349-449: HINTS/_lookup_hint: guardre.match(...).group(0)to avoid a hard crash on unexpected names.This is low-risk, but right now a non-matching prefix/attr would raise
AttributeErrorduring registry init (hard to debug given the import-time freeze).Proposed hardening
-def _lookup_hint(name): +def _lookup_hint(name: str) -> str: @@ family = re.sub(r'[_(].*', '', prefix) # "bc_x" → "bc", "patch_bc" stays if family not in HINTS: # Try with underscore-joined prefix: "simplex_params" stays - family = re.match(r'^[a-zA-Z_]+', prefix).group(0) + m = re.match(r'^[a-zA-Z_]+', prefix) + if not m: + return "" + family = m.group(0) @@ # Strip index from attr: "vel_in(1)" → "vel_in" - attr = re.match(r'^[a-zA-Z_0-9]+', attr_full).group(0) + m = re.match(r'^[a-zA-Z_0-9]+', attr_full) + if not m: + return "" + attr = m.group(0) return HINTS[family].get(attr, "")
812-831:_r(..., hint=...)plumbing and value-label suffixing make sense—watch for double-rendering in docs.Now that
descriptionmay include a(1=..., 2=...)suffix and docs also havevalue_labels, ensure docs generation doesn’t show both formats redundantly.toolchain/mfc/gen_case_constraints_docs.py (1)
669-690:_render_cond_partscloses overdep_partswithout binding it as a parameter.This nested function captures
dep_partsfrom the enclosing scope by reference. It works correctly today because the function is called immediately within the same loop iteration, but it's fragile — if the function were ever stored and called later, it would silently use the wrong list. Passingdep_partsas an explicit argument removes the ambiguity.♻️ Suggested fix
- def _render_cond_parts(trigger_str, cond_dict): - """Render a condition dict into dep_parts entries.""" + def _render_cond_parts(trigger_str, cond_dict, dep_parts=dep_parts): + """Render a condition dict into dep_parts entries."""Or, more explicitly, pass
dep_partsas a regular argument at each call site:- def _render_cond_parts(trigger_str, cond_dict): + def _render_cond_parts(trigger_str, cond_dict, dep_parts): """Render a condition dict into dep_parts entries.""" ... - _render_cond_parts(trigger, cond) + _render_cond_parts(trigger, cond, dep_parts) ... - _render_cond_parts(f"= {wv_val}", wv_cond) + _render_cond_parts(f"= {wv_val}", wv_cond, dep_parts)toolchain/mfc/params/ast_analyzer.py (3)
115-150:self.in_case_validatoris set but never read — dead code.The attribute is assigned at lines 140 and 148 but no code path ever checks its value.
♻️ Suggested removal
def __init__(self): super().__init__() - self.in_case_validator = False self.current_method: str | None = None ... def visit_ClassDef(self, node: ast.ClassDef): if node.name == "CaseValidator": - self.in_case_validator = True # collect methods for item in node.body: ... # now analyze all methods for method in self.methods.values(): self._analyze_method(method) - self.in_case_validator = False else: self.generic_visit(node)
54-57: BareExceptioncatches in AST unparsing fallbacks.Both
_extract_message(line 56) and_resolve_fstring(line 77) catch all exceptions fromast.unparse. Whileast.unparsecan fail in various ways, catching the broadExceptioncould mask unexpected bugs. Consider narrowing to(ValueError, TypeError, AttributeError)— the same set used incoverage.py's_extract_message.♻️ Suggested narrowing
- except Exception: # pylint: disable=broad-except + except (ValueError, TypeError, AttributeError):Also applies to: 75-78
1-7: Consider refactoringcoverage.pyto use this shared analyzer.The relevant code snippets show that
toolchain/mfc/params_tests/coverage.pyhas its own AST parsing (extract_constraints_from_validator,extract_check_methods) that performs a subset of what this new module does. Once this lands,coverage.pycould delegate toanalyze_case_validator()to eliminate the duplicated AST traversal logic.Not blocking for this PR — just a follow-up opportunity.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@toolchain/mfc/case_validator.py`:
- Around line 1938-1953: The current loop over CONSTRAINTS uses a substring
check ("param_name not in err_lower") which false-matches short names like "m"
or "n"; change the match to look for the parameter quoted or as a whole word
instead (e.g., check for f"'{param_name}'" and f'"{param_name}"' and/or use a
regex word-boundary search for rf"\b{re.escape(param_name)}\b") before
proceeding to build the hint; update the check around the for-loop variables
(param_name, err_lower) accordingly so only true parameter mentions trigger the
value_labels hint appended to lines.
In `@toolchain/mfc/params/ast_analyzer.py`:
- Around line 667-683: The substring check `"must be 1" in text` can over-match
(e.g., "must be 10"); replace it with a word-boundary regex check (e.g., use
re.search(r'\bmust be 1\b', text)) and import re if not present, and apply the
same precise matching approach for any similar exact-value checks in the
conditional block that returns "range" so the function in
toolchain/mfc/params/ast_analyzer.py only classifies exact "must be 1" messages
as range constraints.
In `@toolchain/mfc/params/definitions.py`:
- Around line 429-448: The inline comment in _lookup_hint incorrectly states
that "patch_bc" stays unchanged by the regex r'[_(].*' — update the comment to
accurately describe that the regex strips from the first '_' or '(' (so
"patch_bc" becomes "patch", not unchanged), and note that the subsequent
fallback using re.match and HINTS lookup recovers compound prefixes when needed;
reference _lookup_hint, PREFIX_HINTS, HINTS, and the regex r'[_(].*' when making
the clarification.
- Around line 652-666: Update the min constraints for the time-stepping and
physics parameters in the parameter definitions so they match the stricter
checks in case_validator.py: change "dt", "t_stop", "t_save", "weno_eps", and
"R0ref" from {"min": 0} to a small positive value (e.g. {"min": 1e-16}) and
tighten "cfl_target" from {"min": 0} to {"min": 1e-16} or an appropriate (0,1]
enforcing lower bound; keep "t_step_save" as is. Modify the entries for the keys
dt, t_stop, t_save, cfl_target, weno_eps, and R0ref in the same definitions
block so schema validation aligns with the validator’s strictly positive
requirements.
In `@toolchain/mfc/params/generators/docs_gen.py`:
- Around line 273-274: The function signature for _format_validator_rules uses
PEP 604 union syntax (Dict[str, list] | None) which will fail on Python <3.10;
either add from __future__ import annotations at the top of this file to enable
PEP 604 compat like other modules, or change the annotation to
Optional[Dict[str, list]] and add Optional to the typing imports so
_format_validator_rules and any other annotations in this module are compatible
with older Python versions.
🧹 Nitpick comments (8)
toolchain/mfc/params/errors.py (1)
121-149: Minor type annotation inconsistency:listvsList.The
expected_valuesparameter uses barelistwhile the rest of the file usesList[str]fromtyping(e.g.,mutual_exclusion_errorat line 168). For consistency within this file, consider usingList[Any].This is purely cosmetic since bare
listis valid in Python 3.9+.toolchain/mfc/params/generators/docs_gen.py (2)
142-166:_backtick_params: split-by-backtick assumes paired backticks.Steps 2 and 3 (lines 155–164) process every other segment after splitting on
`. If an input message has an odd number of backticks (e.g., from step 1 producing an unpaired backtick due to overlapping matches), a text segment inside a code span could get double-wrapped.This is unlikely with well-formed generated messages, but worth a defensive note if external/user-facing strings ever flow through here.
15-16: Unusednoqadirective on line 16.Ruff correctly identifies that
# noqa: F401is not needed here since the rule isn't enabled. Thepylint: disable=unused-importcomment is still useful if pylint is run separately — consider removing only thenoqa: F401part.toolchain/mfc/params/ast_analyzer.py (1)
562-588: Minor: simplify key-existence + truthiness check.Line 575 can be simplified to avoid the redundant key check flagged by Ruff (RUF019).
♻️ Suggested simplification
- if node.id in alias_map and alias_map[node.id]: - return alias_map[node.id][0] + alias_sources = alias_map.get(node.id) + if alias_sources: + return alias_sources[0]toolchain/mfc/gen_case_constraints_docs.py (4)
26-35: Remove unusednoqadirectives.Ruff reports the
noqa: E402directives at Lines 31 and 32 are unused (E402 is not enabled). These can be cleaned up.♻️ Suggested cleanup
-from mfc.params import CONSTRAINTS, DEPENDENCIES, get_value_label # noqa: E402 pylint: disable=wrong-import-position -from mfc.params.ast_analyzer import ( # noqa: E402 pylint: disable=wrong-import-position +from mfc.params import CONSTRAINTS, DEPENDENCIES, get_value_label # pylint: disable=wrong-import-position +from mfc.params.ast_analyzer import ( # pylint: disable=wrong-import-position
667-691: Move_render_cond_partsoutside the loop or passdep_partsas an argument.Ruff flags B023 because
_render_cond_partscapturesdep_partsvia closure without binding it as a parameter. While this works correctly here (the function is called immediately within the same iteration), redefining the function on every loop iteration is wasteful and the closure pattern is fragile — a future refactor could easily introduce a deferred-call bug.♻️ Suggested fix: pass dep_parts as a parameter
- dep_parts = [] - - def _render_cond_parts(trigger_str, cond_dict): - """Render a condition dict into dep_parts entries.""" - if "requires" in cond_dict: - dep_parts.append(f"When {trigger_str}, requires: {', '.join(f'`{r}`' for r in cond_dict['requires'])}") + dep_parts = [] + + def _render_cond_parts(trigger_str, cond_dict, parts): + """Render a condition dict into parts entries.""" + if "requires" in cond_dict: + parts.append(f"When {trigger_str}, requires: {', '.join(f'`{r}`' for r in cond_dict['requires'])}") if "requires_value" in cond_dict: rv_items = [] for rv_p, rv_vs in cond_dict["requires_value"].items(): labeled = [f"`{v}` ({get_value_label(rv_p, v)})" for v in rv_vs] rv_items.append(f"`{rv_p}` = {' or '.join(labeled)}") - dep_parts.append(f"When {trigger_str}, requires {', '.join(rv_items)}") + parts.append(f"When {trigger_str}, requires {', '.join(rv_items)}") if "recommends" in cond_dict: - dep_parts.append(f"When {trigger_str}, recommends: {', '.join(f'`{r}`' for r in cond_dict['recommends'])}") + parts.append(f"When {trigger_str}, recommends: {', '.join(f'`{r}`' for r in cond_dict['recommends'])}") for cond_key in ["when_true", "when_set"]: cond = dep.get(cond_key, {}) if cond: trigger = "enabled" if cond_key == "when_true" else "set" - _render_cond_parts(trigger, cond) + _render_cond_parts(trigger, cond, dep_parts) if "when_value" in dep: for wv_val, wv_cond in dep["when_value"].items(): - _render_cond_parts(f"= {wv_val}", wv_cond) + _render_cond_parts(f"= {wv_val}", wv_cond, dep_parts)Better yet, define
_render_cond_partsonce before the loop (outside thefor param in quick_ref_params:loop).
696-697: Remove extraneousfprefix (F541).Line 696 has an f-string with no placeholders.
♻️ Fix
- lines.append(f"\n<details>") + lines.append("\n<details>")
611-618: Euler-Lagrange section is hardcoded while Euler-Euler is data-driven.The Euler-Euler section above (Lines 583-609) reads requirements from
DEPENDENCIES, but the Euler-Lagrange section here remains hardcoded. Consider making this consistent by sourcing from the schema as well, or leave a TODO for follow-up.
- docs_gen.py: Render value_labels in Constraints column instead of skipping them, fixing 12 params that lost valid-value info - case_validator.py: Use word-boundary regex for CONSTRAINTS hint matching to prevent false matches on short param names - ast_analyzer.py: Use word-boundary regex for 'must be 1' pattern to avoid matching 'must be 10', 'must be 100', etc. - definitions.py: Fix misleading comment in _lookup_hint() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
CodeAnt AI is reviewing your PR. Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
|
CodeAnt AI finished reviewing your PR. |
- Remove overly strict sigR/sigV qbmm checks that broke all test cases (BASE_CFG defaults sigR/sigV to 0.1 regardless of qbmm) - Lowercase constraint keys before matching against lowered error strings - Guard re.match() calls in _lookup_hint against None returns - Add Python 3.10-3.14 matrix CI workflow for toolchain compatibility Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1133 +/- ##
=======================================
Coverage 44.03% 44.03%
=======================================
Files 70 70
Lines 20649 20649
Branches 2053 2053
=======================================
Hits 9093 9093
Misses 10368 10368
Partials 1188 1188 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
/improve |
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] |
There was a problem hiding this comment.
Suggestion: Remove the unreleased Python version 3.14 from the CI matrix to prevent workflow failures. [possible issue, importance: 6]
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13'] |
There was a problem hiding this comment.
Python 3.14 is available in actions/setup-python and passes in CI — all 5 matrix versions (3.10–3.14) are green. No change needed.
There was a problem hiding this comment.
Question:
Python 3.14 is available in actions/setup-python and passes in CI — all 5 matrix versions (3.10–3.14) are green. No change needed.
Answer:
This is a “speculative CI hygiene” suggestion (it assumed 3.14 is unreleased / unsupported), and you can reduce this kind of noise by tightening /improve guidance and/or filtering mid-score suggestions.
Recommended config (reduce speculative CI-matrix/version suggestions unless there’s evidence of failure):
[pr_code_suggestions]
extra_instructions = """\
- Do not suggest changing CI matrices / supported language versions (e.g., Python/Node) unless the PR diff or PR checks show an actual failure/incompatibility.
- Avoid claims like “unreleased/unsupported version” unless you can point to concrete evidence in the PR context.
- If CI is green, do not propose removing versions purely as a preventative measure.
"""Optional: filter out this class of mid-importance suggestions (the example was importance 6):
[pr_code_suggestions]
suggestions_score_threshold = 7(This will drop suggestions scored below 7; use carefully since it can also hide other useful items.)
If you prefer to exclude CI/workflow files from suggestions altogether:
[pr_code_suggestions]
extra_instructions = """\
- Ignore changes in CI/workflow files (e.g., .github/workflows/*).
"""or globally:
[ignore]
glob = [".github/workflows/*"]If you share which tool produced the comment (/improve vs /review) and your git provider (GitHub/GitLab/etc.), I can tailor the exact config snippet to the right section.
Relevant Sources:
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#extra-instructions-and-best-practices
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#configuration-options
- https://docs.qodo.ai/qodo-documentation/qodo-merge/usage-guide/additional_configurations#ignoring-files-from-analysis
- https://docs.qodo.ai/qodo-documentation/qodo-merge/faq/index#-note-"q:-i-received-an-incorrect-or-irrelevant-suggestion-why"
| def _extract_trigger_from_condition(condition: ast.AST, local_param_map: Dict[str, str], | ||
| alias_map: Optional[Dict[str, List[str]]] = None) -> Optional[str]: | ||
| """ | ||
| Fallback trigger detection: walk the condition AST left-to-right, | ||
| return the first parameter name found. Resolves aliases to their first source param. | ||
| """ | ||
| if alias_map is None: | ||
| alias_map = {} | ||
| # Walk in source order (left-to-right in boolean expressions) | ||
| for node in ast.walk(condition): | ||
| if isinstance(node, ast.Name): | ||
| if node.id in local_param_map: | ||
| return local_param_map[node.id] | ||
| if node.id in alias_map and alias_map[node.id]: | ||
| return alias_map[node.id][0] | ||
| if isinstance(node, ast.Call): | ||
| if ( # pylint: disable=too-many-boolean-expressions | ||
| isinstance(node.func, ast.Attribute) | ||
| and isinstance(node.func.value, ast.Name) | ||
| and node.func.value.id == "self" | ||
| and node.func.attr == "get" | ||
| and node.args | ||
| and isinstance(node.args[0], ast.Constant) | ||
| and isinstance(node.args[0].value, str) | ||
| ): | ||
| return node.args[0].value | ||
| return None |
There was a problem hiding this comment.
Suggestion: Replace ast.walk() with a deterministic, recursive traversal in _extract_trigger_from_condition to ensure consistent trigger parameter selection for documentation grouping. [possible issue, importance: 8]
| def _extract_trigger_from_condition(condition: ast.AST, local_param_map: Dict[str, str], | |
| alias_map: Optional[Dict[str, List[str]]] = None) -> Optional[str]: | |
| """ | |
| Fallback trigger detection: walk the condition AST left-to-right, | |
| return the first parameter name found. Resolves aliases to their first source param. | |
| """ | |
| if alias_map is None: | |
| alias_map = {} | |
| # Walk in source order (left-to-right in boolean expressions) | |
| for node in ast.walk(condition): | |
| if isinstance(node, ast.Name): | |
| if node.id in local_param_map: | |
| return local_param_map[node.id] | |
| if node.id in alias_map and alias_map[node.id]: | |
| return alias_map[node.id][0] | |
| if isinstance(node, ast.Call): | |
| if ( # pylint: disable=too-many-boolean-expressions | |
| isinstance(node.func, ast.Attribute) | |
| and isinstance(node.func.value, ast.Name) | |
| and node.func.value.id == "self" | |
| and node.func.attr == "get" | |
| and node.args | |
| and isinstance(node.args[0], ast.Constant) | |
| and isinstance(node.args[0].value, str) | |
| ): | |
| return node.args[0].value | |
| return None | |
| def _extract_trigger_from_condition(condition: ast.AST, local_param_map: Dict[str, str], | |
| alias_map: Optional[Dict[str, List[str]]] = None) -> Optional[str]: | |
| """ | |
| Fallback trigger detection: traverse the condition in a deterministic | |
| left-to-right, source-like order and return the first parameter name found. | |
| """ | |
| if alias_map is None: | |
| alias_map = {} | |
| def _first_param(node: ast.AST) -> Optional[str]: | |
| if isinstance(node, ast.Name): | |
| if node.id in local_param_map: | |
| return local_param_map[node.id] | |
| if node.id in alias_map and alias_map[node.id]: | |
| return alias_map[node.id][0] | |
| return None | |
| if isinstance(node, ast.Call): | |
| if (isinstance(node.func, ast.Attribute) | |
| and isinstance(node.func.value, ast.Name) | |
| and node.func.value.id == "self" | |
| and node.func.attr == "get" | |
| and node.args | |
| and isinstance(node.args[0], ast.Constant) | |
| and isinstance(node.args[0].value, str)): | |
| return node.args[0].value | |
| for arg in node.args: | |
| hit = _first_param(arg) | |
| if hit: | |
| return hit | |
| return None | |
| if isinstance(node, ast.BoolOp): | |
| for v in node.values: # preserves written order | |
| hit = _first_param(v) | |
| if hit: | |
| return hit | |
| return None | |
| if isinstance(node, ast.UnaryOp): | |
| return _first_param(node.operand) | |
| if isinstance(node, ast.Compare): | |
| hit = _first_param(node.left) | |
| if hit: | |
| return hit | |
| for comp in node.comparators: | |
| hit = _first_param(comp) | |
| if hit: | |
| return hit | |
| return None | |
| for child in ast.iter_child_nodes(node): | |
| hit = _first_param(child) | |
| if hit: | |
| return hit | |
| return None | |
| return _first_param(condition) |
There was a problem hiding this comment.
ast.walk() is deterministic (BFS) for a given AST — the result is stable even if not documented as source-order. Rewriting as a recursive traversal adds complexity for no practical benefit.
There was a problem hiding this comment.
Question:
ast.walk() is deterministic (BFS) for a given AST — the result is stable even if not documented as source-order. Rewriting as a recursive traversal adds complexity for no practical benefit.
Answer:
You can reduce “refactor for theoretical determinism” suggestions by tightening the /improve guidance via pr_code_suggestions.extra_instructions—e.g., require a concrete, user-visible bug or failing test before proposing non-trivial traversal/algorithm rewrites, and prefer minimal changes over speculative robustness improvements.
Add something like this to your repo .pr_agent.toml (or the wiki .pr_agent.toml page in Qodo Merge):
[pr_code_suggestions]
extra_instructions = """\
- Prefer minimal, high-signal fixes. Avoid speculative refactors.
- Do NOT suggest rewriting algorithms/APIs (e.g., replacing ast.walk with custom traversals) unless there is clear evidence of a real bug or instability in this codebase (repro steps, failing test, or documented requirement).
- If the concern is ordering/determinism, first verify whether the current approach is already deterministic for the given input; if yes, do not propose a rewrite—at most suggest adding a clarifying comment or a small test.
- When proposing changes, justify the practical impact (user-visible behavior, correctness, performance, security). If impact is uncertain, skip the suggestion.
"""If you still get too many medium-value suggestions, you can additionally filter by score, but use it carefully because high thresholds can hide useful findings:
[pr_code_suggestions]
suggestions_score_threshold = 8Relevant Sources:
| if "when_value" in deps: | ||
| for trigger_val, condition in deps["when_value"].items(): | ||
| if value == trigger_val: | ||
| _check_condition( | ||
| name, condition, f"={trigger_val}", params, errors, warnings, | ||
| ) |
There was a problem hiding this comment.
Suggestion: In check_dependencies, normalize the parameter value and the when_value trigger value to strings before comparison to prevent silent failures due to type mismatches. [possible issue, importance: 8]
| if "when_value" in deps: | |
| for trigger_val, condition in deps["when_value"].items(): | |
| if value == trigger_val: | |
| _check_condition( | |
| name, condition, f"={trigger_val}", params, errors, warnings, | |
| ) | |
| if "when_value" in deps: | |
| value_norm = str(value) | |
| for trigger_val, condition in deps["when_value"].items(): | |
| if value_norm == str(trigger_val): | |
| _check_condition( | |
| name, condition, f"={trigger_val}", params, errors, warnings, | |
| ) |
There was a problem hiding this comment.
Both the when_value keys and the parameter values come from Python source dicts where types match naturally (int literals are ints). Adding str() conversions would mask real bugs if types ever did mismatch. No change needed.
There was a problem hiding this comment.
Question:
Both the when_value keys and the parameter values come from Python source dicts where types match naturally (int literals are ints). Adding str() conversions would mask real bugs if types ever did mismatch. No change needed.
Answer:
You can steer /improve away from “defensive type normalization” suggestions (like adding str() around comparisons) by adding a targeted instruction for code suggestions.
Add this to your repo (or wiki/global) .pr_agent.toml:
[pr_code_suggestions]
extra_instructions = """\
- Do not suggest coercing values to strings (e.g., str(...)) or otherwise normalizing types just to make equality comparisons pass.
- Assume compared values come from typed Python structures where types are intended to match (e.g., dict literals / parsed config).
- Only suggest type conversions when the PR diff shows mixed-type sources or an explicit, documented requirement for string-only comparison.
- Prefer surfacing type mismatches as errors (or adding validation/assertions) rather than masking them via coercion.
"""If this kind of suggestion still appears too often, consider raising filtering slightly, but be careful not to hide real issues:
[pr_code_suggestions]
suggestions_score_threshold = 1Relevant Sources:
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#extra-instructions-and-best-practices
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#extra-instructions
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#configuration-options
- https://docs.qodo.ai/qodo-documentation/qodo-merge/faq/index#faq
| if "requires_value" in condition: | ||
| for req_param, expected_vals in condition["requires_value"].items(): | ||
| if req_param not in params: | ||
| errors.append(dependency_error(name, req_param, condition_label)) | ||
| else: | ||
| got = params[req_param] | ||
| if got not in expected_vals: | ||
| errors.append(dependency_value_error( | ||
| name, condition_label, req_param, expected_vals, got, | ||
| )) |
There was a problem hiding this comment.
Suggestion: In _check_condition, normalize the parameter value and the expected values in requires_value to strings before comparison to prevent silent failures due to type mismatches. [possible issue, importance: 8]
| if "requires_value" in condition: | |
| for req_param, expected_vals in condition["requires_value"].items(): | |
| if req_param not in params: | |
| errors.append(dependency_error(name, req_param, condition_label)) | |
| else: | |
| got = params[req_param] | |
| if got not in expected_vals: | |
| errors.append(dependency_value_error( | |
| name, condition_label, req_param, expected_vals, got, | |
| )) | |
| if "requires_value" in condition: | |
| for req_param, expected_vals in condition["requires_value"].items(): | |
| if req_param not in params: | |
| errors.append(dependency_error(name, req_param, condition_label)) | |
| else: | |
| got = params[req_param] | |
| got_norm = str(got) | |
| expected_norm = [str(v) for v in expected_vals] | |
| if got_norm not in expected_norm: | |
| errors.append(dependency_value_error( | |
| name, condition_label, req_param, expected_vals, got, | |
| )) |
There was a problem hiding this comment.
Same reasoning as above — types match naturally from Python source. str() normalization is unnecessary.
There was a problem hiding this comment.
Question:
Same reasoning as above — types match naturally from Python source. str() normalization is unnecessary.
Answer:
Add a repo-level instruction for /improve to avoid “defensive type-normalization” suggestions (like str()-casting) when values originate from in-process Python objects and types are expected to be consistent.
[pr_code_suggestions]
extra_instructions = """\
- Assume Python types are intentionally preserved when values originate from internal code (not user input / serialization).
- Do NOT suggest normalizing values via str()/repr() (or similar coercions) just to “avoid type mismatches”.
- Only suggest type conversions if the PR explicitly introduces mixed-type comparisons or data crosses a boundary (CLI/env vars, JSON/YAML, HTTP, DB, etc.).
- Prefer catching true mismatches with explicit validation (type checks) rather than silent coercion.
"""If you want this guidance to apply more broadly as an organizational rule, place it in your best-practices guidance (local best_practices.md or global best practices) so the model treats it as a consistent convention.
Relevant Sources:
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#extra-instructions-and-best-practices
- https://docs.qodo.ai/qodo-documentation/qodo-merge/faq/index#-note-"q:-i-received-an-incorrect-or-irrelevant-suggestion-why"
- https://docs.qodo.ai/qodo-documentation/qodo-merge/usage-guide/configuration_options#local-configuration-file
| # Time stepping (must be positive) | ||
| "dt": {"min": 0}, | ||
| "t_stop": {"min": 0}, | ||
| "t_save": {"min": 0}, | ||
| "t_step_save": {"min": 1}, | ||
| "t_step_print": {"min": 1}, | ||
| "cfl_target": {"min": 0}, | ||
| "cfl_max": {"min": 0}, |
There was a problem hiding this comment.
Suggestion: Update the minimum values for time-stepping parameters like dt and t_stop from 0 to a small positive number to enforce that they are strictly positive, matching the comment's intent. [general, importance: 7]
| # Time stepping (must be positive) | |
| "dt": {"min": 0}, | |
| "t_stop": {"min": 0}, | |
| "t_save": {"min": 0}, | |
| "t_step_save": {"min": 1}, | |
| "t_step_print": {"min": 1}, | |
| "cfl_target": {"min": 0}, | |
| "cfl_max": {"min": 0}, | |
| # Time stepping (must be positive) | |
| "dt": {"min": 1e-16}, | |
| "t_stop": {"min": 1e-16}, | |
| "t_save": {"min": 0}, | |
| "t_step_save": {"min": 1}, | |
| "t_step_print": {"min": 1}, | |
| "cfl_target": {"min": 1e-16}, | |
| "cfl_max": {"min": 1e-16}, |
There was a problem hiding this comment.
The CONSTRAINTS dict serves as documentation/hints — the actual enforcement is in case_validator.py. Using min: 1e-16 is an arbitrary approximation of "strictly positive" that doesn't truly represent the constraint. The validator is the source of truth.
There was a problem hiding this comment.
Question:
The CONSTRAINTS dict serves as documentation/hints — the actual enforcement is in case_validator.py. Using min: 1e-16 is an arbitrary approximation of strictly positive that doesn't truly represent the constraint. The validator is the source of truth.
Answer:
Add a repo-level instruction to stop the /improve suggestions from “enforcing” semantics in documentation-only dicts (like CONSTRAINTS) by inventing sentinel values (e.g., 1e-16) and to treat the validator as the source of truth.
[pr_code_suggestions]
extra_instructions = """\
- When you see configuration/constraints dictionaries that serve as documentation or hints (e.g., CONSTRAINTS), do NOT propose changing numeric bounds to approximate concepts like “strictly positive” (avoid sentinel values like 1e-16).
- Prefer suggesting: (a) align comments/docs with actual enforcement, or (b) update the real validation/enforcement code (e.g., case_validator.py) if behavior should change.
- If enforcement differs from docs, explicitly ask to confirm which is the source of truth before recommending code changes.
"""If you only want this behavior for automated runs, apply it only in your auto-command (example for GitHub App):
[github_app]
pr_commands = [
"/improve --pr_code_suggestions.extra_instructions='When constraints dicts are doc-only, do not suggest sentinel min values; prefer changing validator or docs.'",
]Relevant Sources:
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#extra-instructions-and-best-practices
- https://docs.qodo.ai/qodo-documentation/qodo-merge/tools/improve#configuration-options
- https://docs.qodo.ai/qodo-documentation/qodo-merge/usage-guide/automations_and_usage#github-app-automatic-tools-when-a-new-pr-is-opened
- https://docs.qodo.ai/qodo-documentation/qodo-merge/faq/index#-note-"q:-i-received-an-incorrect-or-irrelevant-suggestion-why"
User description
Note
Medium Risk
Touches core parameter validation and documentation generation logic, so mistakes could reject valid cases or mislead users with incorrect constraints/hints. Scope is contained to tooling/validation (not solver runtime), but behavior changes are user-facing and broad.
Overview
Makes parameter docs and constraint hints schema-driven by extending
CONSTRAINTSwithvalue_labels, adding richerDEPENDENCIES(requires_valueandwhen_value), and surfacing these viaget_value_labeland newParamDef.hintsupport.Centralizes
case_validator.pyrule extraction into a new sharedparams/ast_analyzer.py, then updates bothgen_case_constraints_docs.pyandparams/generators/docs_gen.pyto use it, producing docs that automatically include validator rules, dependency summaries, and labeled enumerations.Tightens runtime validation by enforcing value-specific dependencies in
params/validate.py, improvescase_validator.pyerror formatting to auto-suggest valid values fromCONSTRAINTS, and adds several new explicit constraint checks (e.g.,igr_pres_lim↔igr, THINCint_comp↔recon_type,sigR/sigV↔qbmm,pre_stress↔hyperelasticity). Build-system doc targets now depend oncase_validator.py/definitions.pyas needed to keep generated docs up to date.Written by Cursor Bugbot for commit 13010c8. Configure here.
Summary by CodeRabbit
New Features
Improvements
Chores
CodeAnt-AI Description
Use schema-driven value labels and enforce value-specific dependencies; surface both in docs and validation
What Changed
Impact
✅ Clearer validation hints for invalid choices✅ Richer parameter reference with labeled choices and dependency summaries✅ Fewer undetected value-specific dependency violations💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.