Skip to content

ci: retire blocking mutation workflow - #289

Merged
abiorh-claw merged 25 commits into
mainfrom
codex/ws-qual-001-05m1-declaration-mutation-fix
Aug 6, 2026
Merged

ci: retire blocking mutation workflow#289
abiorh-claw merged 25 commits into
mainfrom
codex/ws-qual-001-05m1-declaration-mutation-fix

Conversation

@Abiorh001

@Abiorh001 Abiorh001 commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Workstream PR Trust Bundle

Chunk

WS-QUAL-001-05M-R1 - Retire the blocking behavior-mutation workflow

Goal

Remove the self-blocking mutation workflow so AUTH and other backend work can proceed through the established semantic, coverage, lint, review, and human-merge gates.

Intent And Planning Context

  • Intent: The repository owner explicitly authorized removing this CI check after the protected callable-wide evaluator repeatedly blocked declaration-only work and could not safely evaluate its own correction.
  • Chunk contract: Narrow corrective retirement recorded in the WS-QUAL status and chunk map; mutation enforcement may return only through a fresh changed-line-aware plan.

What Changed

  • Deleted .github/workflows/mutation-pilot.yml.
  • Changed lightweight Agent Gates to assert that the retired workflow stays absent and Backend does not reference it.
  • Updated contributor guidance, mutation-claim guidance, backend testing operations, WS-QUAL status, and the chunk map.
  • Preserved mutation policy, claims, pinned dependencies, and historical evidence for future redesign.

Why It Changed

The callable-wide policy mutated unchanged executable lines whenever a small declaration or callable fragment changed. This produced large survivor sets that owning behavior tests could not eliminate without implementation snapshots, exemptions, or bypasses.

Design Chosen

Retire only the hosted mutation workflow and its active governance assertion. Keep the existing Backend semantic lanes, coverage floors, lint, docstring, service-contract, review, and human-merge gates unchanged.

Alternatives Rejected

  • Source or bytecode snapshot tests: rejected because they game mutation outcomes instead of proving behavior.
  • Survivor allowlists, exclusions, lowered thresholds, or mutation pragmas: rejected because they silently weaken evidence.
  • Continuing callable-wide enforcement: rejected because unchanged lines remained blocking.

Scope Control

Allowed Files Changed

  • .github/workflows/mutation-pilot.yml
  • scripts/test_lightweight_agent_gates.py
  • CONTRIBUTING.md
  • .ci/behavior-claims/README.md
  • docs/operations_backend_testing.md
  • .agent-loop/initiatives/WS-QUAL-001-backend-coverage-floor/STATUS.md
  • .agent-loop/initiatives/WS-QUAL-001-backend-coverage-floor/CHUNK_MAP.md

Files Outside Stated Scope

  • None

Product Behavior

  • No Workstream product behavior changed.
  • Product behavior changed and is explained here:

Evidence

Commands Run

python3 -m unittest -v scripts.test_lightweight_agent_gates
backend/.venv/bin/ruff check scripts/test_lightweight_agent_gates.py
python3 scripts/check_markdown_links.py
python3 scripts/check_stale_workstream_wording.py
git diff --check origin/main...HEAD
gh pr checks 289 --watch

Result Summary

Lightweight Agent Gates: 11 passed
Ruff: passed
Markdown links: passed
Stale wording: passed
All five hosted Backend semantic lanes: passed
Backend final evidence fan-in: passed
Agent Gates: passed

Acceptance Criteria Proof

  • The mutation workflow is absent from the exact head.
  • Lightweight Agent Gates require it to remain absent.
  • Backend does not reference the retired workflow.
  • Existing semantic lanes and coverage fan-in pass unchanged.
  • Active contributor and operations documentation no longer calls mutation evidence required.
  • Restart requires a fresh changed-line-aware plan.

Test Delta

Tests Added

  • None.

Tests Modified

  • Replaced the obsolete mutation-workflow-presence assertions with retirement assertions.

Tests Removed Or Skipped

  • Removed assertions about the deleted workflow's internal configuration; no product or Backend behavior test was removed or skipped.

Internal Reviewer Results

Reviewed code SHA: 1d8c45a90562587f718b1eac72b79ec9a6525965

Reviewed at: 2026-08-05

Reviewer run IDs: qual05m1_arch_review, qual05m1_ci_review, qual05m1_docs_review

Reviewer Result Blocking Findings Notes
Senior engineering N/A - with approved reason None Narrow CI retirement reviewed by architecture and CI-integrity specialists.
QA/test N/A - with approved reason None No product behavior changed; hosted Backend suite and focused gate tests passed.
Security/auth N/A - with approved reason None No authentication, authorization, data, secret, or runtime product path changed.
Product/ops N/A - with approved reason None No Workstream lifecycle behavior changed.
Architecture PASS None Final exact-head retirement boundaries and chunk disposition are aligned.
CI integrity PASS WITH LOW RISKS None All non-mutation CI gates and coverage floors remain unchanged.
Docs PASS None Contributor, operations, status, and claim guidance consistently mark the gate retired.
Reuse/dedup N/A - with approved reason None No production abstraction or duplicate implementation introduced.
Test delta N/A - with approved reason None One obsolete workflow-presence assertion was replaced by the exact retirement invariant.

External Review

Source Status Notes
CodeRabbit Finding addressed The reactivation guard now appears consistently in all three contributor-facing guides; exact-head rereview was rate limited.
GitHub checks PASS Agent Gates, five Backend lanes, and final Backend fan-in passed.

CI And Gate Integrity

  • No workflow weakening. The repository owner explicitly authorized retiring the defective mutation workflow; this is the sole intentional gate removal.
  • No lint/test/docstring gate weakening.
  • No coverage threshold weakening.
  • No package script weakening.
  • No unpinned new GitHub Action.
  • Checkout credential persistence disabled where checkout is used.

Remaining Risks

  • Behavior mutation is no longer a hosted required check. Existing policy artifacts remain historical only.
  • If Behavior Mutation Gate / pilot was configured as an external branch-protection requirement, a repository administrator must remove that stale required-check setting.

Follow-Up Work

  • Design mutation enforcement later as a separate changed-line-aware initiative with proof that unchanged executable lines cannot block declaration-only changes.

Human Review Focus

Please inspect:

  • the intentional workflow deletion;
  • preservation of all existing Backend gates and coverage floors;
  • the lightweight invariant preventing accidental partial reactivation;
  • the explicit future-plan boundary.

Human Merge Ownership

  • I can explain what changed.
  • I can explain why it changed.
  • I know what could break.
  • I accept the remaining risks.
  • The user explicitly approved this specific PR for merge.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Abiorh001, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c1397059-310d-4b26-8549-cece98a3c103

📥 Commits

Reviewing files that changed from the base of the PR and between 54cd358 and e48fb9e.

📒 Files selected for processing (4)
  • .agent-loop/initiatives/WS-QUAL-001-backend-coverage-floor/reviews/WS-QUAL-001-05M-external-review-response.md
  • .ci/behavior-claims/README.md
  • CONTRIBUTING.md
  • docs/operations_backend_testing.md
📝 Walkthrough

Walkthrough

The pull request retires the behavior mutation workflow and removes its required CI role. Documentation and planning records now describe the design as historical. A lightweight regression test confirms that the workflow is absent and not referenced by backend CI.

Changes

Behavior mutation gate retirement

Layer / File(s) Summary
Retirement records and contribution guidance
.agent-loop/initiatives/WS-QUAL-001-backend-coverage-floor/*, .ci/behavior-claims/README.md, CONTRIBUTING.md, docs/operations_backend_testing.md
Planning, status, contribution, and operations documentation record the retired mutation gate. Existing coverage, backend, lint, review, and approval requirements remain active.
Required CI retirement guard
scripts/test_lightweight_agent_gates.py
The regression test verifies that mutation-pilot.yml is absent and that the backend workflow does not reference it.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: abiorh-claw

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the main change: retiring the blocking mutation workflow.
Description check ✅ Passed The description follows the required trust-bundle structure and documents scope, rationale, evidence, risks, tests, reviews, and follow-up work.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/ws-qual-001-05m1-declaration-mutation-fix

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
backend/tests/test_mutation_policy.py (1)

167-205: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Replace the boolean loop with pytest.mark.parametrize.

The loop runs two distinct scenarios inside one test. If the first scenario fails, the second never runs, and the report does not name the failing case. The file already uses parametrization elsewhere.

♻️ Proposed refactor
-    def test_empty_callables_cannot_hide_changed_or_claim_only_behavior(self) -> None:
-        for change_target in (True, False):
+    `@pytest.mark.parametrize`("change_target", (True, False))
+    def test_empty_callables_cannot_hide_changed_or_claim_only_behavior(
+        self, change_target: bool
+    ) -> None:
+        if True:
             with tempfile.TemporaryDirectory() as temporary:

Adjust the indentation of the body rather than keeping the placeholder if True: block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/tests/test_mutation_policy.py` around lines 167 - 205, Refactor
test_empty_callables_cannot_hide_changed_or_claim_only_behavior to use
pytest.mark.parametrize for the two change_target scenarios, with descriptive
parameter IDs. Remove the boolean loop and any placeholder conditional, then
adjust the test body indentation while preserving each scenario’s file mutation
and expected error assertion.
backend/scripts/mutation_policy.py (1)

484-492: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Reuse the already computed spans instead of parsing the source a third time.

_map_changed_lines parses current_source at line 458 and line 484 parses it again through _callable_spans. Lines 477-481 parse it a third time with ast.parse. For large targets this triples AST work. Consider computing the spans and the class set once and passing them to the helpers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/scripts/mutation_policy.py` around lines 484 - 492, Update
_map_changed_lines to reuse the spans and class information already computed
from current_source instead of invoking _callable_spans and ast.parse again near
the available/derived logic. Compute these values once and pass them into the
relevant helpers, preserving the existing unmapped, removed, and
declaration_changed behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/scripts/mutation_policy.py`:
- Around line 817-820: Validate the mutation target list in the
selection/config-writing flow before constructing or persisting mutmut settings:
when build_selection yields an empty mutation_targets list, raise
MutationPolicyError with the "zero_mutation_targets" reason (or otherwise fail
closed) and do not write an empty mutation scope. Preserve normal relative
target processing for non-empty selections.
- Around line 401-410: Update the ClassDef handling in _callable_spans to
compute the span end from the latest explicit end_lineno among the class
decorators, bases, and keyword values, rather than always using node.lineno. Use
that header end when appending the class span, while preserving the existing
start, validation, destination selection, and body traversal behavior.

---

Nitpick comments:
In `@backend/scripts/mutation_policy.py`:
- Around line 484-492: Update _map_changed_lines to reuse the spans and class
information already computed from current_source instead of invoking
_callable_spans and ast.parse again near the available/derived logic. Compute
these values once and pass them into the relevant helpers, preserving the
existing unmapped, removed, and declaration_changed behavior.

In `@backend/tests/test_mutation_policy.py`:
- Around line 167-205: Refactor
test_empty_callables_cannot_hide_changed_or_claim_only_behavior to use
pytest.mark.parametrize for the two change_target scenarios, with descriptive
parameter IDs. Remove the boolean loop and any placeholder conditional, then
adjust the test body indentation while preserving each scenario’s file mutation
and expected error assertion.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 486b21ce-75b9-4c86-a827-80031711509f

📥 Commits

Reviewing files that changed from the base of the PR and between 0ddc0f0 and 30bc80f.

📒 Files selected for processing (7)
  • .ci/behavior-claims/README.md
  • .ci/behavior-claims/WS-QUAL-001-05M.json
  • CONTRIBUTING.md
  • backend/scripts/mutation_policy.py
  • backend/tests/test_mutation_policy.py
  • docs/operations_backend_testing.md
  • scripts/behavior-claim.schema.json

Comment on lines 401 to 410
elif isinstance(node, ast.ClassDef):
start = min([node.lineno, *[item.lineno for item in node.decorator_list]])
executable.append((start, node.lineno))
decorators_valid = all(valid_dataclass_decorator(item) for item in node.decorator_list)
bases_valid = all(
declaration_value(item, class_scope=True)
for item in (*node.bases, *(item.value for item in node.keywords))
)
destination = declarations if decorators_valid and bases_valid else executable
destination.append((start, node.lineno))
visit(node.body, (*parents, node.name))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check whether any test covers a multi-line class header change in mutation policy ownership analysis.
rg -n -C5 'class_scope=True|bases_valid|node.bases' backend/scripts/mutation_policy.py
rg -n -C8 'class .*\(\s*$' backend/tests/test_mutation_policy.py

Repository: Flow-Research/workstream

Length of output: 1180


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant files =="
git ls-files backend/scripts/mutation_policy.py backend/tests/test_mutation_policy.py backend/scripts | sed -n '1,80p'

echo
echo "== mutation_policy.py outline =="
ast-grep outline backend/scripts/mutation_policy.py 2>/dev/null | sed -n '1,200p' || true

echo
echo "== relevant script section =="
sed -n '320,450p' backend/scripts/mutation_policy.py

echo
echo "== tests around changed ownership if present =="
if [ -f backend/tests/test_mutation_policy.py ]; then
  wc -l backend/tests/test_mutation_policy.py
  rg -n -C5 'changed|ownership|zero_changed|unmapped|declaration' backend/tests/test_mutation_policy.py || true
else
  echo "backend/tests/test_mutation_policy.py not found"
fi

echo
echo "== deterministic AST probe for class header and mapping logic shape =="
python3 - <<'PY'
import ast, pathlib, textwrap
p = pathlib.Path('backend/scripts/mutation_policy.py')
src = p.read_text()
print('has _map_changed_lines:', '_map_changed_lines' in src)
print('has declaration_changed unmerged/unmapped markers in script:', any(s in src for s in ('declaration_changed', 'unmapped', 'zero_changed_ownership')))
# Model the exact class span expression for representative multi-line headers.
class SourceLines(src):
    def visit_ClassDef(self, node):
        start = min([node.lineno, *[item.lineno for item in node.decorator_list]])
        span = (start, node.lineno)
        header_end = max(
            [node.lineno]
            + [getattr(item, "end_lineno", item.lineno) for item in (*node.bases, *(item.value for item in node.keywords))]
            + ([node.body[0].lineno - 1] if node.body else [])
        )
        return span, header_end

class SourceLinesTexts:
    pass
for i, body in enumerate([
    textwrap.dedent('''\
        `@dataclasses.dataclass`
        class A(Base): pass
    '''),
    textwrap.dedent('''\
        `@decorator1`
        `@decorator2`
        class A(Base):
            x=1
    '''),
    textwrap.dedent('''\
        `@decorator1`
        class A(
            Base,
            Other
        ):
            x=1
    '''),
    textwrap.dedent('''\
        class A(
            Base
        ): pass
    '''),
    textwrap.dedent('''\
        class A[
            Type,
        ]: pass
    '''),
], str, i):
    tree = ast.parse(body)
    node = next(n for n in ast.walk(tree) if isinstance(n, ast.ClassDef))
    s = SourceLines(body.splitlines(keepends=True))
    print(f'case {i}:', body.split()[1], 'lineno', node.lineno, 'ast end_lineno getattr', getattr(node,"end_lineno",None), 'span', s.visit_ClassDef(node))
PY

Repository: Flow-Research/workstream

Length of output: 25953


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== changed target ownership implementation =="
sed -n '434,505p' backend/scripts/mutation_policy.py

echo
echo "== deterministic class header probe =="
python3 - <<'PY'
import ast, textwrap
for i, body in enumerate([
    textwrap.dedent('''\
        `@dataclasses.dataclass`
        class A(Base): pass
    '''),
    textwrap.dedent('''\
        `@decorator1`
        `@decorator2`
        class A(Base):
            x=1
    '''),
    textwrap.dedent('''\
        `@decorator1`
        class A(
            Base,
            Other
        ):
            x=1
    '''),
    textwrap.dedent('''\
        class A(
            Base
        ): pass
    '''),
    textwrap.dedent('''\
        class A[
            Type,
        ]: pass
    '''),
], str, i):
    tree = ast.parse(body)
    node = next(n for n in ast.walk(tree) if isinstance(n, ast.ClassDef))
    current_end = node.lineno
    header_end = max(
        [node.lineno]
        + [getattr(item, "end_lineno", item.lineno) for item in (*node.bases, *(item.value for item in node.keywords))]
        + ([node.body[0].lineno - 1] if node.body else [])
    )
    print(f"case {i}:")
    print(body.strip().replace("\n", "\\n"))
    print("  lineno", node.lineno, "ast end_lineno", getattr(node, "end_lineno", None), "current span end", current_end, "header_end", header_end)
PY

Repository: Flow-Research/workstream

Length of output: 3623


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deterministic class header probe =="
python3 - <<'PY'
import ast, textwrap

for case, body in enumerate([
    textwrap.dedent('''\
        `@dataclasses.dataclass`
        class A(Base): pass
    '''),
    textwrap.dedent('''\
        `@decorator1`
        `@decorator2`
        class A(Base):
            x=1
    '''),
    textwrap.dedent('''\
        `@decorator1`
        class A(
            Base,
            Other
        ):
            x=1
    '''),
    textwrap.dedent('''\
        class A(
            Base
        ): pass
    '''),
    textwrap.dedent('''\
        class A[
            Type,
        ]: pass
    '''),
], str):
    tree = ast.parse(body)
    node = next(n for n in ast.walk(tree) if isinstance(n, ast.ClassDef))
    current_end = node.lineno
    header_end = max(
        [node.lineno]
        + [getattr(item, "end_lineno", item.lineno) for item in (*node.bases, *(item.value for item in node.keywords))]
        + ([node.body[0].lineno - 1] if node.body else [])
    )
    print(f"case {case}:")
    print(body.strip().replace("\n", "\\n"))
    print("  lineno", node.lineno, "ast end_lineno", getattr(node, "end_lineno", None), "current span end", current_end, "header_end", header_end)

def _map_changed_lines(source: str, module: str, lines: set[int]) -> tuple[set[str], bool, bool]:
    callables, declarations, executable = [], [], []
    tree = ast.parse(source)
    def visit(nodes: list, parents: tuple = ()):
        for node in nodes:
            end = getattr(node, "end_lineno", node.lineno)
            if isinstance(node, ast.ClassDef):
                start = min([node.lineno, *[item.lineno for item in node.decorator_list]])
                destination = declarations
                destination.append((start, node.lineno))
                visit(node.body, (*parents, node.name))
            elif getattr(node, "lineno", None):
                destination = declarations if isinstance(node, ast.Assign) else executable
                destination.append((node.lineno, end))
    visit(tree.body)
    owners = set()
    for line in lines:
        matches = [item for item in callables if item[0] <= line <= item[1]]
        if matches:
            owners.add(min(matches, key=lambda item: item[1] - item[0])[2])
        elif any(start <= line <= end for start, end in declarations):
            pass
        elif any(start <= line <= end for start, end in executable):
            pass
    return owners, any(any(start <= line <= end for start, end in declarations) for line in lines), any(any(start <= line <= end for start, end in executable) for line in lines)

print(_map_changed_lines(textwrap.dedent('''\
    class A(
        Base
    ): x=1
'''), "mod", {2, 3}))
PY

Repository: Flow-Research/workstream

Length of output: 335


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deterministic class header probe =="
python3 - <<'PY'
import ast, textwrap

for case, body in enumerate([
    textwrap.dedent('''\
        `@dataclasses.dataclass`
        class A(Base): pass
    '''),
    textwrap.dedent('''\
        `@decorator1`
        `@decorator2`
        class A(Base):
            x=1
    '''),
    textwrap.dedent('''\
        `@decorator1`
        class A(
            Base,
            Other
        ):
            x=1
    '''),
    textwrap.dedent('''\
        class A(
            Base
        ): pass
    '''),
    textwrap.dedent('''\
        class A[
            Type,
        ]: pass
    '''),
], 0):
    tree = ast.parse(body)
    node = next(n for n in ast.walk(tree) if isinstance(n, ast.ClassDef))
    current_end = node.lineno
    header_end = max(
        [node.lineno]
        + [getattr(item, "end_lineno", item.lineno) for item in (*node.bases, *(item.value for item in node.keywords))]
        + ([node.body[0].lineno - 1] if node.body else [])
    )
    print(f"case {case}:")
    print(body.strip().replace("\n", "\\n"))
    print("  lineno", node.lineno, "ast end_lineno", getattr(node, "end_lineno", None), "current span end", current_end, "header_end", header_end)

PY

Repository: Flow-Research/workstream

Length of output: 913


Include the rest of the class header in the class span.

_callable_spans ends the class declaration at node.lineno, but _map_changed_lines uses the current head source when class bodies are changed. A changed base class or header continuation line can fall outside every span and be treated as unmapped despite being owned by the class header. Record the latest explicit end_lineno from decorators, bases, and keywords (before visiting the class body) so class-header changes stay within one span.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/scripts/mutation_policy.py` around lines 401 - 410, Update the
ClassDef handling in _callable_spans to compute the span end from the latest
explicit end_lineno among the class decorators, bases, and keyword values,
rather than always using node.lineno. Use that header end when appending the
class span, while preserving the existing start, validation, destination
selection, and body traversal behavior.

Comment thread backend/scripts/mutation_policy.py Outdated
@Abiorh001 Abiorh001 changed the title fix(ci): support declaration-owned mutation evidence ci: retire blocking mutation workflow Aug 5, 2026
@Abiorh001

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
scripts/test_lightweight_agent_gates.py (1)

127-130: 🩺 Stability & Availability | 🔵 Trivial

Verify the stale required-check configuration before merge.

This test proves only that .github/workflows/mutation-pilot.yml is absent and that backend.yml has no mutation-pilot reference. It cannot inspect GitHub branch protection or repository rulesets. If Behavior Mutation Gate remains required, the retired workflow can still block merges even when this test passes. Remove the stale requirement or record administrator verification.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/test_lightweight_agent_gates.py` around lines 127 - 130, Update
test_retired_behavior_mutation_gate_stays_out_of_required_ci to verify or
document that the repository’s branch protection/rulesets no longer require
“Behavior Mutation Gate,” rather than only checking workflow-file absence.
Remove the stale required-check configuration, or add an explicit
administrator-verification record alongside the existing assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CONTRIBUTING.md`:
- Around line 75-82: Apply the same reactivation guard across all three
documented sites: in CONTRIBUTING.md lines 75-82, add that behavior-mutation
enforcement must not resume until a fresh changed-line-aware plan is approved;
add the equivalent guard to docs/operations_backend_testing.md lines 174-186;
and in .ci/behavior-claims/README.md lines 18-33, label the claim-discovery and
fail-closed rules as historical only and place the changed-line-aware plan
requirement before any reactivation.

---

Nitpick comments:
In `@scripts/test_lightweight_agent_gates.py`:
- Around line 127-130: Update
test_retired_behavior_mutation_gate_stays_out_of_required_ci to verify or
document that the repository’s branch protection/rulesets no longer require
“Behavior Mutation Gate,” rather than only checking workflow-file absence.
Remove the stale required-check configuration, or add an explicit
administrator-verification record alongside the existing assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16fa9419-4e19-4859-b3e3-66c8737bca1c

📥 Commits

Reviewing files that changed from the base of the PR and between 30bc80f and 54cd358.

📒 Files selected for processing (7)
  • .agent-loop/initiatives/WS-QUAL-001-backend-coverage-floor/CHUNK_MAP.md
  • .agent-loop/initiatives/WS-QUAL-001-backend-coverage-floor/STATUS.md
  • .ci/behavior-claims/README.md
  • .github/workflows/mutation-pilot.yml
  • CONTRIBUTING.md
  • docs/operations_backend_testing.md
  • scripts/test_lightweight_agent_gates.py
💤 Files with no reviewable changes (1)
  • .github/workflows/mutation-pilot.yml

Comment thread CONTRIBUTING.md
@abiorh-claw
abiorh-claw self-requested a review August 6, 2026 04:40
@abiorh-claw
abiorh-claw merged commit 6f29d41 into main Aug 6, 2026
9 checks passed
@abiorh-claw
abiorh-claw deleted the codex/ws-qual-001-05m1-declaration-mutation-fix branch August 6, 2026 04:41
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