Repository: jackdewinter/pymarkdown

Issue:
Rule Md027 fires incorrectly on md031_final_bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_thematics
## Prerequisites

* [X] Are you running the latest version of this application?
* [X] Have you checked the [Frequently Asked Questions](https://pymarkdown.readthedocs.io/en/latest/faq) document?
* [X] Have you simplified the bug report to the essential details?
  * [X] Do you have a distinct command line to report?
  * [X] Can you clearly state the configuration for this bug report?
  * [X] Do you have a minimal document that highlights this bug?
  * [X] Are any required files (configuration or Markdown document) attached to the issue?
* [X] Did you perform a cursory search of other issues to look for related issues?

## Bug Report

Please replace any of `[these areas]` in the paragraphs below with the requested information.

### Bug Type

* [X] Scan/Rule not working as expected

### Description

Newly added test case `md031_final_bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_thematics` fires incorrectly.  When examining the firing of the rule, it looks like a calculation is off and `>    >{space}` is compared to `>    >` and is found to be different.  

### Specifics

What operating system and version are you running into this behavior on?

Win11

What version are you seeing this behavior in? (Run `pip list` or `pipenv run pip list` and look for the entry beside `pymarkdownlnt`.)

latest, main

Are there any extra steps that need to be taken before executing the application?

No

What is the command line you invoke to get this behavior?

md031_final_bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_thematics

Are you using a configuration file? Either on the command line or one of the implicit configuration files? If so, attach that file to this issue.

No

What Markdown document causes this behavior to manifest?  Attach that file to this issue.

```
> + > -----
>   > > block 1
>   > > block 2
>   > -----
>   >
>   > ```block
>   > A code block
>   > ```
>   >
>   > -----
> + another list
```

### Actual Behavior

The two blanks lines around the code block are flagged as not being as expected.

### Expected Behavior

Visually, those lines do not have any extra whitespace, and should not trigger this rule.

Discussion:
sourcery-ai[bot]: <!-- Generated by sourcery-ai[bot]: start review_guide -->

🧙 Sourcery is reviewing your pull request!

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/jackdewinter/pymarkdown/pull/1216?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 100.00%. Comparing base [(`e5fd5af`)](https://app.codecov.io/gh/jackdewinter/pymarkdown/commit/e5fd5af63e8d17ae83610da34896b5d783c454e6?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) to head [(`68c539c`)](https://app.codecov.io/gh/jackdewinter/pymarkdown/commit/68c539c03d7b4aba1d7088eaf3f19ef745292910?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff            @@
##              main     #1216   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          190       191    +1     
  Lines        20941     20983   +42     
  Branches      2679      2678    -1     
=========================================
+ Hits         20941     20983   +42     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/jackdewinter/pymarkdown/pull/1216?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


Patch:
diff --git a/newdocs/src/changelog.md b/newdocs/src/changelog.md
index 95f78627..d8749466 100644
--- a/newdocs/src/changelog.md
+++ b/newdocs/src/changelog.md
@@ -38,11 +38,13 @@
     - parser issue with fenced code block closing right away
 - [Issue 1204](https://github.com/jackdewinter/pymarkdown/issues/1204)
     - rehydration/fix issue with blank lines causing off by one error
+- [Issue 1209](https://github.com/jackdewinter/pymarkdown/issues/1209)
+    - detection code for MD027 was not using the right container index
 
 <!--- pyml disable-next-line no-duplicate-heading-->
 ### Changed
 
-- None
+- Started to pull common code from MD031 for use in Md027
 
 ## Version 0.9.23 - Date: 2024-09-04
 
diff --git a/publish/coverage.json b/publish/coverage.json
index 66b479a8..a3b9de82 100644
--- a/publish/coverage.json
+++ b/publish/coverage.json
@@ -2,12 +2,12 @@
     "projectName": "pymarkdown",
     "reportSource": "pytest",
     "branchLevel": {
-        "totalMeasured": 5359,
-        "totalCovered": 5359
+        "totalMeasured": 5357,
+        "totalCovered": 5357
     },
     "lineLevel": {
-        "totalMeasured": 20941,
-        "totalCovered": 20941
+        "totalMeasured": 20983,
+        "totalCovered": 20983
     }
 }
 
diff --git a/publish/pylint_suppression.json b/publish/pylint_suppression.json
index 99914502..49efbcd8 100644
--- a/publish/pylint_suppression.json
+++ b/publish/pylint_suppression.json
@@ -354,6 +354,7 @@
         "pymarkdown/plugins/rule_pml_100.py": {},
         "pymarkdown/plugins/rule_pml_101.py": {},
         "pymarkdown/plugins/utils/container_token_manager.py": {},
+        "pymarkdown/plugins/utils/leading_space_index_tracker.py": {},
         "pymarkdown/plugins/utils/list_tracker.py": {},
         "pymarkdown/return_code_helper.py": {},
         "pymarkdown/tokens/atx_heading_markdown_token.py": {
diff --git a/pymarkdown/block_quotes/block_quote_non_fenced_helper.py b/pymarkdown/block_quotes/block_quote_non_fenced_helper.py
index ca1cf00a..acbc86b1 100644
--- a/pymarkdown/block_quotes/block_quote_non_fenced_helper.py
+++ b/pymarkdown/block_quotes/block_quote_non_fenced_helper.py
@@ -632,26 +632,23 @@ class BlockQuoteNonFencedHelper:
             and not parser_state.token_stack[search_index].is_block_quote
         ):
             search_index -= 1
-        if search_index and search_index + 1 == stack_index:
+        if search_index:  # and search_index + 1 == stack_index:
             search_token = parser_state.token_stack[
                 search_index
             ].matching_markdown_token
             assert search_token is not None
-            if search_token.line_number != block_quote_token.line_number:
-                found_token = parser_state.token_stack[
-                    search_index
-                ].matching_markdown_token
-                assert found_token is not None
-                bq_token = cast(BlockQuoteMarkdownToken, found_token)
-                assert bq_token.bleading_spaces is not None
-                split_spaces = bq_token.bleading_spaces.split("\n")
-                if len(split_spaces) > 1:
-                    last_split_space = split_spaces[-1]
-                    if (
-                        adjusted_removed_text != last_split_space
-                        and adjusted_removed_text.startswith(last_split_space)
-                    ):
-                        block_quote_token.weird_kludge_six = True
+            found_token = parser_state.token_stack[search_index].matching_markdown_token
+            assert found_token is not None
+            bq_token = cast(BlockQuoteMarkdownToken, found_token)
+            assert bq_token.bleading_spaces is not None
+            split_spaces = bq_token.bleading_spaces.split("\n")
+            if len(split_spaces) > 1:
+                last_split_space = split_spaces[-1]
+                if (
+                    adjusted_removed_text != last_split_space
+                    and adjusted_removed_text.startswith(last_split_space)
+                ):
+                    block_quote_token.weird_kludge_six = True
 
     @staticmethod
     def __check_for_kludge(
diff --git a/pymarkdown/block_quotes/block_quote_processor.py b/pymarkdown/block_quotes/block_quote_processor.py
index 02ec1223..ed324197 100644
--- a/pymarkdown/block_quotes/block_quote_processor.py
+++ b/pymarkdown/block_quotes/block_quote_processor.py
@@ -700,12 +700,12 @@ class BlockQuoteProcessor:
         character_after_block_quote = parser_state.original_line_to_parse[
             last_block_quote_index
         ]
-        assert character_after_block_quote == " ", "below covered in disabled test"
+        assert character_after_block_quote == " "
         # if character_after_block_quote == " ":
         last_block_quote_index += 1
-        #     character_after_block_quote = parser_state.original_line_to_parse[
-        #         last_block_quote_index
-        #     ]
+        character_after_block_quote = parser_state.original_line_to_parse[
+            last_block_quote_index
+        ]
 
         text_removed_by_container = parser_state.original_line_to_parse[
             :last_block_quote_index
diff --git a/pymarkdown/plugins/rule_md_027.py b/pymarkdown/plugins/rule_md_027.py
index 2a7640e5..582addda 100644
--- a/pymarkdown/plugins/rule_md_027.py
+++ b/pymarkdown/plugins/rule_md_027.py
@@ -8,6 +8,9 @@ from pymarkdown.general.parser_helper import ParserHelper
 from pymarkdown.plugin_manager.plugin_details import PluginDetailsV2
 from pymarkdown.plugin_manager.plugin_scan_context import PluginScanContext
 from pymarkdown.plugin_manager.rule_plugin import RulePlugin
+from pymarkdown.plugins.utils.leading_space_index_tracker import (
+    LeadingSpaceIndexTracker,
+)
 from pymarkdown.plugins.utils.list_tracker import ListTracker
 from pymarkdown.tokens.blank_line_markdown_token import BlankLineMarkdownToken
 from pymarkdown.tokens.block_quote_markdown_token import BlockQuoteMarkdownToken
@@ -51,6 +54,7 @@ class RuleMd027(RulePlugin):
         self.__last_token: Optional[MarkdownToken] = None
         # self.__debug_on = False
         self.__list_tracker = ListTracker()
+        self.__leading_space_index_tracker = LeadingSpaceIndexTracker()
 
         self.__delayed_bleading_fixes: Dict[
             MarkdownToken, List[Tuple[int, str, bool, BlankLineMarkdownToken]]
@@ -87,6 +91,7 @@ class RuleMd027(RulePlugin):
         self.__have_incremented_for_this_line = False
         self.__last_token = None
         self.__list_tracker.starting_new_file()
+        self.__leading_space_index_tracker.clear()
 
     # pylint: disable=too-many-arguments
     def __report_issue(
@@ -322,6 +327,13 @@ class RuleMd027(RulePlugin):
 
     # pylint: enable=too-many-arguments
 
+    def __process_pending_container_end_tokens(
+        self, context: PluginScanContext, token: MarkdownToken
+    ) -> None:
+        _ = context
+        while self.__leading_space_index_tracker.have_any_registered_container_ends():
+            self.__leading_space_index_tracker.process_container_end(token)
+
     def next_token(self, context: PluginScanContext, token: MarkdownToken) -> None:
         """
         Event that a new token is being processed.
@@ -335,6 +347,9 @@ class RuleMd027(RulePlugin):
         ):
             self.__have_incremented_for_this_line = False
 
+        if not token.is_end_token or token.is_end_of_stream:
+            self.__process_pending_container_end_tokens(context, token)
+
         num_container_tokens = len(
             [i for i in self.__container_tokens if i.is_block_quote_start]
         )
@@ -349,12 +364,16 @@ class RuleMd027(RulePlugin):
         #     if self.__container_tokens:
         #         print(f"self.__container_tokens>{ParserHelper.make_value_visible(self.__container_tokens)}")
         if token.is_block_quote_start:
+            self.__leading_space_index_tracker.open_container(token)
             self.__handle_block_quote_start(token)
         elif token.is_block_quote_end:
+            self.__leading_space_index_tracker.register_container_end(token)
             self.__handle_block_quote_end(context, token, num_container_tokens)
         elif token.is_list_start:
+            self.__leading_space_index_tracker.open_container(token)
             self.__handle_list_start(context, token, num_container_tokens)
         elif token.is_list_end:
+            self.__leading_space_index_tracker.register_container_end(token)
             self.__handle_list_end(context, token)
         elif token.is_new_list_item:
             self.__handle_new_list_item(context, token, num_container_tokens)
@@ -363,6 +382,8 @@ class RuleMd027(RulePlugin):
             if num_container_tokens:
                 self.__handle_within_block_quotes(context, token)
 
+        self.__leading_space_index_tracker.track_since_last_non_end_token(token)
+
         self.__last_token = token
 
     def __handle_block_quote_start(self, token: MarkdownToken) -> None:
@@ -643,7 +664,7 @@ class RuleMd027(RulePlugin):
         if scoped_token is not None and scoped_token.is_block_quote_start:
 
             self.__handle_blank_line_inner(
-                scoped_token, delayed_bq_index, blank_line_token
+                scoped_token, delayed_bq_index, blank_line_token, token
             )
 
         if blank_line_token.extracted_whitespace:
@@ -660,6 +681,7 @@ class RuleMd027(RulePlugin):
         scoped_token: MarkdownToken,
         delayed_bq_index: int,
         blank_line_token: BlankLineMarkdownToken,
+        token: MarkdownToken,
     ) -> None:
         scoped_block_quote_token = cast(BlockQuoteMarkdownToken, scoped_token)
         assert scoped_block_quote_token.bleading_spaces is not None
@@ -667,16 +689,28 @@ class RuleMd027(RulePlugin):
             ParserHelper.newline_character
         )
 
+        container_index = (
+            self.__leading_space_index_tracker.get_container_stack_size() - 1
+        )
+        if self.__leading_space_index_tracker.get_container_stack_item(
+            container_index
+        ).is_block_quote_start:
+            block_quote_index = self.__leading_space_index_tracker.get_tokens_block_quote_bleading_space_index(
+                token
+            )
+        else:
+            block_quote_index = delayed_bq_index
+
         # If we are closing other containers, can cause issues. So do not fire.
         is_end_with_other_closed_containers = (
-            delayed_bq_index == len(split_leading_spaces) - 1
+            block_quote_index == len(split_leading_spaces) - 1
             and self.__delayed_blank_line_with_list_end
         )
 
         # If we have matching nested block quotes, and then a blank line, we need to prevent
         # the firing.
         is_special_case = (
-            delayed_bq_index == 0
+            block_quote_index == 0
             and len(split_leading_spaces) == 1
             and blank_line_token.line_number != scoped_block_quote_token.line_number
         )
@@ -684,14 +718,15 @@ class RuleMd027(RulePlugin):
         assert (
             not is_special_case
             and not is_end_with_other_closed_containers
-            and delayed_bq_index < len(split_leading_spaces)
+            and block_quote_index < len(split_leading_spaces)
         )
-        specific_block_quote_prefix = split_leading_spaces[delayed_bq_index]
+
+        specific_block_quote_prefix = split_leading_spaces[block_quote_index]
         mod_specific_block_quote_prefix = specific_block_quote_prefix.rstrip(" ")
         if mod_specific_block_quote_prefix != specific_block_quote_prefix:
             self.__register_blank_line(
                 scoped_block_quote_token,
-                delayed_bq_index,
+                block_quote_index,
                 mod_specific_block_quote_prefix,
                 bool(blank_line_token.extracted_whitespace),
                 blank_line_token,
diff --git a/pymarkdown/plugins/rule_md_031.py b/pymarkdown/plugins/rule_md_031.py
index 4bc342d0..b7134d1c 100644
--- a/pymarkdown/plugins/rule_md_031.py
+++ b/pymarkdown/plugins/rule_md_031.py
@@ -15,25 +15,16 @@ from pymarkdown.plugin_manager.plugin_details import (
 )
 from pymarkdown.plugin_manager.plugin_scan_context import PluginScanContext
 from pymarkdown.plugin_manager.rule_plugin import RulePlugin
+from pymarkdown.plugins.utils.leading_space_index_tracker import (
+    LeadingSpaceIndexTracker,
+)
 from pymarkdown.tokens.blank_line_markdown_token import BlankLineMarkdownToken
 from pymarkdown.tokens.block_quote_markdown_token import BlockQuoteMarkdownToken
 from pymarkdown.tokens.list_start_markdown_token import ListStartMarkdownToken
 from pymarkdown.tokens.markdown_token import EndMarkdownToken, MarkdownToken
-from pymarkdown.tokens.setext_heading_markdown_token import SetextHeadingMarkdownToken
 from pymarkdown.tokens.text_markdown_token import TextMarkdownToken
 
 
-@dataclass
-class ClosedContainerAdjustments:
-    """
-    Keep track of line space used by already closed containers.
-    """
-
-    adjustment: int = 0
-    count: int = 0
-    count2: int = 0
-
-
 @dataclass(frozen=True)
 class PendingContainerAdjustment:
     """
@@ -58,15 +49,11 @@ class RuleMd031(RulePlugin):
         self.__last_non_end_token: Optional[MarkdownToken] = None
         self.__last_token: Optional[MarkdownToken] = None
         self.__second_last_token: Optional[MarkdownToken] = None
-        self.__container_token_stack: List[MarkdownToken] = []
-        self.__pending_container_ends = 0
         self.__container_adjustments: List[List[PendingContainerAdjustment]] = []
-        self.__closed_container_adjustments: List[ClosedContainerAdjustments] = []
-        self.__end_tokens: List[EndMarkdownToken] = []
         self.__fix_count = 0
-        self.__removed_container_token_stack: Optional[MarkdownToken] = None
-        # self.__removed_container_adjustments = None
-        # self.__removed_closed_container_adjustments = None
+        self.__removed_container_stack_token: Optional[MarkdownToken] = None
+
+        self.__leading_space_index_tracker = LeadingSpaceIndexTracker()
 
     def get_details(self) -> PluginDetails:
         """
@@ -106,12 +93,9 @@ class RuleMd031(RulePlugin):
         self.__last_non_end_token = None
         self.__last_token = None
         self.__end_fenced_code_block_token = None
-        self.__container_token_stack = []
         self.__container_adjustments = []
-        self.__closed_container_adjustments = []
-        self.__end_tokens = []
-        self.__pending_container_ends = 0
         self.__fix_count = 0
+        self.__leading_space_index_tracker.clear()
 
     def __fix_spacing_special_case(
         self, context: PluginScanContext, token: MarkdownToken
@@ -147,27 +131,21 @@ class RuleMd031(RulePlugin):
         )
 
     def __fix_spacing_block_quote(self, token: MarkdownToken) -> None:
-        container_index = len(self.__container_token_stack) - 1
-        block_quote_token = cast(
-            BlockQuoteMarkdownToken, self.__container_token_stack[container_index]
+        leading_space_insert_index = self.__leading_space_index_tracker.get_tokens_block_quote_bleading_space_index(
+            token
         )
-        assert (
-            block_quote_token.bleading_spaces is not None
-        ), "At least one line should have been processed."
-        split_leading_space = block_quote_token.bleading_spaces.split("\n")
-        if token.is_setext_heading:
-            setext_token = cast(SetextHeadingMarkdownToken, token)
-            token_line_number = setext_token.original_line_number
-        else:
-            token_line_number = token.line_number
 
-        leading_space_insert_index = (
-            token_line_number - block_quote_token.line_number
-        ) - (
-            self.__closed_container_adjustments[-1].adjustment
-            - self.__closed_container_adjustments[-1].count2
+        container_index = (
+            self.__leading_space_index_tracker.get_container_stack_size() - 1
         )
-
+        block_quote_token = cast(
+            BlockQuoteMarkdownToken,
+            self.__leading_space_index_tracker.get_container_stack_item(
+                container_index
+            ),
+        )
+        assert block_quote_token.bleading_spaces is not None
+        split_leading_space = block_quote_token.bleading_spaces.split("\n")
         former_item_leading_space = split_leading_space[
             leading_space_insert_index
         ].rstrip()
@@ -179,22 +157,23 @@ class RuleMd031(RulePlugin):
 
         while (
             container_index > 0
-            and not self.__container_token_stack[container_index - 1].is_list_start
+            and not self.__leading_space_index_tracker.get_container_stack_item(
+                container_index - 1
+            ).is_list_start
         ):
             container_index -= 1
 
         if (
             container_index > 0
-            and self.__container_token_stack[container_index - 1].is_list_start
+            and self.__leading_space_index_tracker.get_container_stack_item(
+                container_index - 1
+            ).is_list_start
         ):
-            if token.is_setext_heading:
-                setext_token = cast(SetextHeadingMarkdownToken, token)
-                token_line_number = setext_token.original_line_number
-            else:
-                token_line_number = token.line_number
             leading_space_insert_index = (
-                token_line_number
-                - self.__container_token_stack[container_index - 1].line_number
+                LeadingSpaceIndexTracker.calculate_token_line_number(token)
+                - self.__leading_space_index_tracker.get_container_stack_item(
+                    container_index - 1
+                ).line_number
             )
             self.__container_adjustments[container_index - 1].append(
                 PendingContainerAdjustment(leading_space_insert_index, "")
@@ -203,10 +182,14 @@ class RuleMd031(RulePlugin):
     def __fix_spacing_list(
         self, context: PluginScanContext, token: MarkdownToken
     ) -> None:
-        initial_index = container_index = len(self.__container_token_stack) - 1
+        initial_index = container_index = (
+            self.__leading_space_index_tracker.get_container_stack_size() - 1
+        )
         while (
             container_index >= 0
-            and self.__container_token_stack[container_index - 1].is_list_start
+            and self.__leading_space_index_tracker.get_container_stack_item(
+                container_index - 1
+            ).is_list_start
         ):
             container_index -= 1
         if container_index >= 0:
@@ -227,8 +210,8 @@ class RuleMd031(RulePlugin):
             # )
 
         if (
-            self.__removed_container_token_stack is not None
-            and not self.__removed_container_token_stack.is_block_quote_start
+            self.__removed_container_stack_token is not None
+            and not self.__removed_container_stack_token.is_block_quote_start
             # and container_index
         ):
             self.__fix_spacing_list_remove_list(context)
@@ -239,7 +222,7 @@ class RuleMd031(RulePlugin):
 
     def __fix_spacing_list_remove_list(self, context: PluginScanContext) -> None:
         removed_list_token = cast(
-            ListStartMarkdownToken, self.__removed_container_token_stack
+            ListStartMarkdownToken, self.__removed_container_stack_token
         )
         assert removed_list_token.leading_spaces is not None
         split_spaces = removed_list_token.leading_spaces.split("\n")
@@ -248,10 +231,10 @@ class RuleMd031(RulePlugin):
             split_spaces.insert(split_spaces_length - 1, "")
         else:
             split_spaces.append("")
-        assert self.__removed_container_token_stack is not None
+        assert self.__removed_container_stack_token is not None
         self.register_fix_token_request(
             context,
-            self.__removed_container_token_stack,
+            self.__removed_container_stack_token,
             "next_token",
             "leading_spaces",
             "\n".join(split_spaces),
@@ -260,21 +243,24 @@ class RuleMd031(RulePlugin):
     def __fix_spacing_list_not_remove_list(
         self, initial_index: int, container_index: int, token: MarkdownToken
     ) -> None:
-        if self.__closed_container_adjustments[-1].adjustment:
+        last_closed_container_info = (
+            self.__leading_space_index_tracker.get_closed_container_info(-1)
+        )
+
+        if last_closed_container_info.adjustment:
             adjust = 2 if container_index >= 0 else 1
         else:
             adjust = self.__calculate_adjust(initial_index, container_index)
-        if token.is_setext_heading:
-            setext_token = cast(SetextHeadingMarkdownToken, token)
-            token_line_number = setext_token.original_line_number
-        else:
-            token_line_number = token.line_number
         index = (
-            token_line_number - self.__container_token_stack[initial_index].line_number
+            LeadingSpaceIndexTracker.calculate_token_line_number(token)
+            - self.__leading_space_index_tracker.get_container_stack_item(
+                initial_index
+            ).line_number
         )
-        index -= self.__closed_container_adjustments[-1].adjustment
+        index -= last_closed_container_info.adjustment
+        index -= adjust
         self.__container_adjustments[initial_index].append(
-            PendingContainerAdjustment(index - adjust, "")
+            PendingContainerAdjustment(index, "")
         )
 
     def __fix_spacing_list_prefix(
@@ -285,22 +271,24 @@ class RuleMd031(RulePlugin):
     ) -> Tuple[BlockQuoteMarkdownToken, int, Optional[str]]:
         block_quote_index = cast(
             BlockQuoteMarkdownToken,
-            self.__container_token_stack[container_index - 1],
+            self.__leading_space_index_tracker.get_container_stack_item(
+                container_index - 1
+            ),
         )
-        if token.is_setext_heading:
-            setext_token = cast(SetextHeadingMarkdownToken, token)
-            token_line_number = setext_token.original_line_number
-        else:
-            token_line_number = token.line_number
+
+        current_closed_container_info = (
+            self.__leading_space_index_tracker.get_closed_container_info(
+                container_index - 1
+            )
+        )
+
         index = (
-            token_line_number
+            LeadingSpaceIndexTracker.calculate_token_line_number(token)
             - block_quote_index.line_number
-            - self.__closed_container_adjustments[container_index - 1].adjustment
+            - current_closed_container_info.adjustment
         )
-        df = self.__closed_container_adjustments[container_index - 1].adjustment
-        ff = df != 0
-        if ff:
-            index += self.__closed_container_adjustments[container_index - 1].count
+        if current_closed_container_info.adjustment != 0:
+            index += current_closed_container_info.count
 
         # ss = None
         # This may be due to a commented out test.
@@ -321,22 +309,20 @@ class RuleMd031(RulePlugin):
         return block_quote_index, index, None
 
     def __calculate_adjust(self, initial_index: int, container_index: int) -> int:
+
+        last_closed_container_info = (
+            self.__leading_space_index_tracker.get_closed_container_info(-1)
+        )
         assert (
             initial_index < 2
             or container_index
-            or not self.__closed_container_adjustments[-1].adjustment
+            or not last_closed_container_info.adjustment
         )
-        # if (
-        #     initial_index >= 2
-        #     and not container_index
-        #     and self.__closed_container_adjustments[-1].adjustment
-        # ):
-        #     return 1
         return (
             0
             if initial_index >= 1
             and not container_index
-            and self.__closed_container_adjustments[-1].adjustment
+            and last_closed_container_info.adjustment
             else 1
         )
 
@@ -346,15 +332,17 @@ class RuleMd031(RulePlugin):
         if special_case:
             self.__fix_spacing_special_case(context, token)
             return
-        if self.__container_token_stack:
-            if self.__container_token_stack[-1].is_block_quote_start:
+        if self.__leading_space_index_tracker.in_at_least_one_container():
+            if self.__leading_space_index_tracker.get_container_stack_item(
+                -1
+            ).is_block_quote_start:
                 self.__fix_spacing_block_quote(token)
             else:
                 self.__fix_spacing_list(context, token)
-        elif self.__removed_container_token_stack:
-            if self.__removed_container_token_stack.is_list_start:
+        elif self.__removed_container_stack_token:
+            if self.__removed_container_stack_token.is_list_start:
                 removed_list_token = cast(
-                    ListStartMarkdownToken, self.__removed_container_token_stack
+                    ListStartMarkdownToken, self.__removed_container_stack_token
                 )
                 assert removed_list_token.leading_spaces is None
                 # if removed_list_token.leading_spaces is not None:
@@ -364,7 +352,7 @@ class RuleMd031(RulePlugin):
                 split_spaces = [""]
                 self.register_fix_token_request(
                     context,
-                    self.__removed_container_token_stack,
+                    self.__removed_container_stack_token,
                     "next_token",
                     "leading_spaces",
                     "\n".join(split_spaces),
@@ -406,8 +394,10 @@ class RuleMd031(RulePlugin):
 
         can_trigger = (
             self.__trigger_in_list_items
-            if self.__container_token_stack
-            and self.__container_token_stack[-1].is_list_start
+            if self.__leading_space_index_tracker.in_at_least_one_container()
+            and self.__leading_space_index_tracker.get_container_stack_item(
+                -1
+            ).is_list_start
             else True
         )
         if (
@@ -458,8 +448,10 @@ class RuleMd031(RulePlugin):
     ) -> None:  # sourcery skip: extract-method
         can_trigger = not token.is_end_of_stream
         if (
-            self.__container_token_stack
-            and self.__container_token_stack[-1].is_list_start
+            self.__leading_space_index_tracker.in_at_least_one_container()
+            and self.__leading_space_index_tracker.get_container_stack_item(
+                -1
+            ).is_list_start
         ):
             can_trigger = self.__trigger_in_list_items
         if (
@@ -486,10 +478,13 @@ class RuleMd031(RulePlugin):
         context: PluginScanContext,
         next_container_adjustment_list: List[PendingContainerAdjustment],
     ) -> None:
-        if self.__container_token_stack[-1].is_block_quote_start:
+        if self.__leading_space_index_tracker.get_container_stack_item(
+            -1
+        ).is_block_quote_start:
             token_part_name = "bleading_spaces"
             block_quote_token = cast(
-                BlockQuoteMarkdownToken, self.__container_token_stack[-1]
+                BlockQuoteMarkdownToken,
+                self.__leading_space_index_tracker.get_container_stack_item(-1),
             )
             assert (
                 block_quote_token.bleading_spaces is not None
@@ -497,7 +492,10 @@ class RuleMd031(RulePlugin):
             split_spaces = block_quote_token.bleading_spaces.split("\n")
         else:
             token_part_name = "leading_spaces"
-            list_token = cast(ListStartMarkdownToken, self.__container_token_stack[-1])
+            list_token = cast(
+                ListStartMarkdownToken,
+                self.__leading_space_index_tracker.get_container_stack_item(-1),
+            )
             assert (
                 list_token.leading_spaces is not None
             ), "Pending containers means this should at least have a newline in it."
@@ -517,83 +515,26 @@ class RuleMd031(RulePlugin):
 
         self.register_fix_token_request(
             context,
-            self.__container_token_stack[-1],
+            self.__leading_space_index_tracker.get_container_stack_item(-1),
             "next_token",
             token_part_name,
             "\n".join(split_spaces),
         )
 
-    def __process_pending_container_end_block_quote(self, token: MarkdownToken) -> None:
-        for stack_index in range(len(self.__container_token_stack) - 2, -1, -1):
-            current_stack_token = self.__container_token_stack[stack_index]
-            if current_stack_token.is_block_quote_start:
-                if token.is_setext_heading:
-                    setext_token = cast(SetextHeadingMarkdownToken, token)
-                    token_line_number = setext_token.original_line_number
-                else:
-                    token_line_number = token.line_number
-                line_number_delta = (
-                    token_line_number - self.__container_token_stack[-1].line_number
-                )
-                extra_end_data = self.__end_tokens[-1].extra_end_data
-                if extra_end_data is not None:
-                    line_number_delta += 1
-                self.__closed_container_adjustments[
-                    stack_index
-                ].adjustment += line_number_delta
-                self.__closed_container_adjustments[stack_index].count += 1
-                if (
-                    self.__container_token_stack[-1].is_block_quote_start
-                    and cast(
-                        BlockQuoteMarkdownToken, self.__container_token_stack[-1]
-                    ).weird_kludge_six
-                ):
-                    self.__closed_container_adjustments[stack_index].count2 += 1
-                break
-
-    def __process_pending_container_end_list(self, token: MarkdownToken) -> None:
-        for stack_index in range(len(self.__container_token_stack) - 2, -1, -1):
-            current_stack_token = self.__container_token_stack[stack_index]
-            if current_stack_token.is_list_start:
-                if token.is_setext_heading:
-                    setext_token = cast(SetextHeadingMarkdownToken, token)
-                    token_line_number = setext_token.original_line_number
-                else:
-                    token_line_number = token.line_number
-                line_number_delta = (
-                    token_line_number - self.__container_token_stack[-1].line_number
-                )
-                self.__closed_container_adjustments[
-                    stack_index
-                ].adjustment += line_number_delta
-                break
-
-    def __process_pending_container_end(
+    def __process_pending_container_end_tokens(
         self, context: PluginScanContext, token: MarkdownToken
     ) -> None:
-        if context.in_fix_mode:
-            if next_container_adjustment_list := self.__container_adjustments[-1]:
-                self.__process_pending_container_end_adjustment(
-                    context, next_container_adjustment_list
-                )
-            if self.__container_token_stack[-1].is_block_quote_start:
-                self.__process_pending_container_end_block_quote(token)
-            else:
-                self.__process_pending_container_end_list(token)
-
-        self.__removed_container_token_stack = self.__container_token_stack[-1]
-        del self.__container_token_stack[-1]
-
-        # self.__removed_container_adjustments = self.__container_adjustments[-1]
-        del self.__container_adjustments[-1]
-
-        # self.__removed_closed_container_adjustments = (
-        #     self.__closed_container_adjustments[-1]
-        # )
-        del self.__closed_container_adjustments[-1]
+        while self.__leading_space_index_tracker.have_any_registered_container_ends():
+            if context.in_fix_mode:
+                if next_container_adjustment_list := self.__container_adjustments[-1]:
+                    self.__process_pending_container_end_adjustment(
+                        context, next_container_adjustment_list
+                    )
 
-        del self.__end_tokens[-1]
-        self.__pending_container_ends -= 1
+            self.__removed_container_stack_token = (
+                self.__leading_space_index_tracker.process_container_end(token)
+            )
+            del self.__container_adjustments[-1]
 
     def __calculate_special_case(
         self, context: PluginScanContext, token: MarkdownToken
@@ -601,9 +542,13 @@ class RuleMd031(RulePlugin):
         return bool(
             context.in_fix_mode
             and token.is_fenced_code_block
-            and len(self.__container_token_stack) >= 2
-            and self.__container_token_stack[-1].is_block_quote_start
-            and self.__container_token_stack[-2].is_block_quote_start
+            and self.__leading_space_index_tracker.get_container_stack_size() >= 2
+            and self.__leading_space_index_tracker.get_container_stack_item(
+                -1
+            ).is_block_quote_start
+            and self.__leading_space_index_tracker.get_container_stack_item(
+                -2
+            ).is_block_quote_start
             and self.__last_token
             and self.__second_last_token
             and self.__last_token.is_block_quote_end
@@ -616,28 +561,27 @@ class RuleMd031(RulePlugin):
         """
 
         special_case = self.__calculate_special_case(context, token)
-        # special_case = False
 
         if not token.is_end_token or token.is_end_of_stream:
-            while self.__pending_container_ends and not special_case:
-                self.__process_pending_container_end(context, token)
+            if not special_case:
+                self.__process_pending_container_end_tokens(context, token)
             if self.__end_fenced_code_block_token:
                 self.__handle_end_fenced_code_block(context, token)
 
         if token.is_block_quote_start or token.is_list_start:
-            self.__container_token_stack.append(token)
             self.__container_adjustments.append([])
-            self.__closed_container_adjustments.append(ClosedContainerAdjustments())
+            self.__leading_space_index_tracker.open_container(token)
         elif token.is_block_quote_end or token.is_list_end:
-            self.__pending_container_ends += 1
-            self.__end_tokens.append(cast(EndMarkdownToken, token))
+            self.__leading_space_index_tracker.register_container_end(token)
         elif token.is_fenced_code_block:
             self.__handle_fenced_code_block(context, token, special_case)
-            while self.__pending_container_ends and special_case:
-                self.__process_pending_container_end(context, token)
+            if special_case:
+                self.__process_pending_container_end_tokens(context, token)
         elif token.is_fenced_code_block_end:
             self.__end_fenced_code_block_token = cast(EndMarkdownToken, token)
 
+        self.__leading_space_index_tracker.track_since_last_non_end_token(token)
+
         if (
             not token.is_end_token
             and not token.is_block_quote_start
@@ -647,9 +591,7 @@ class RuleMd031(RulePlugin):
 
         self.__second_last_token = self.__last_token
         self.__last_token = token
-        self.__removed_container_token_stack = None
-        # self.__removed_container_adjustments = None
-        # self.__removed_closed_container_adjustments = None
+        self.__removed_container_stack_token = None
 
 
 # pylint: enable=too-many-instance-attributes
diff --git a/pymarkdown/plugins/utils/leading_space_index_tracker.py b/pymarkdown/plugins/utils/leading_space_index_tracker.py
new file mode 100644
index 00000000..0ba346af
--- /dev/null
+++ b/pymarkdown/plugins/utils/leading_space_index_tracker.py
@@ -0,0 +1,190 @@
+"""
+Module to work with the rules to keep track of the current container "leading space" index.
+"""
+
+from dataclasses import dataclass
+from typing import List, cast
+
+from pymarkdown.tokens.block_quote_markdown_token import BlockQuoteMarkdownToken
+from pymarkdown.tokens.markdown_token import EndMarkdownToken, MarkdownToken
+from pymarkdown.tokens.setext_heading_markdown_token import SetextHeadingMarkdownToken
+
+
+@dataclass
+class ClosedContainerAdjustments:
+    """
+    Keep track of line space used by already closed containers.
+    """
+
+    adjustment: int = 0
+    count: int = 0
+    count2: int = 0
+
+
+class LeadingSpaceIndexTracker:
+    """
+    Class to track the leading spaces for each container.
+    """
+
+    def __init__(self) -> None:
+        self.__closed_container_adjustments: List[ClosedContainerAdjustments] = []
+        self.__container_token_stack: List[MarkdownToken] = []
+        self.__end_tokens: List[EndMarkdownToken] = []
+        self.__since_last_non_end_token: List[MarkdownToken] = []
+
+    def clear(self) -> None:
+        """
+        Clear all tracking (at the beginning of a new file).
+        """
+        self.__closed_container_adjustments.clear()
+        self.__container_token_stack.clear()
+        self.__end_tokens.clear()
+
+    def open_container(self, token: MarkdownToken) -> None:
+        """
+        Open a new container.
+        """
+        assert token.is_block_quote_start or token.is_list_start
+        self.__container_token_stack.append(token)
+        self.__closed_container_adjustments.append(ClosedContainerAdjustments())
+
+    def register_container_end(self, token: MarkdownToken) -> None:
+        """
+        Register the end of the current container for processing once the
+        next non-end token is encountered.
+        """
+        assert token.is_block_quote_end or token.is_list_end
+        self.__end_tokens.append(cast(EndMarkdownToken, token))
+
+    def have_any_registered_container_ends(self) -> bool:
+        """
+        Check to see if any container ends have been registered and not processed.
+        """
+        return bool(self.__end_tokens)
+
+    def process_container_end(self, token: MarkdownToken) -> MarkdownToken:
+        """
+        Process a registered container end.
+        """
+
+        if self.__container_token_stack[-1].is_block_quote_start:
+            self.__process_container_end_block_quote(token, self.__end_tokens)
+        else:
+            self.__process_container_end_list(token)
+
+        del self.__closed_container_adjustments[-1]
+        del self.__end_tokens[-1]
+
+        last_token_on_stack = self.__container_token_stack[-1]
+        del self.__container_token_stack[-1]
+        return last_token_on_stack
+
+    def track_since_last_non_end_token(self, token: MarkdownToken) -> None:
+        """
+        Keep track of the last non-end token and any end tokens since then.
+        """
+        if not token.is_end_token:
+            self.__since_last_non_end_token.clear()
+        self.__since_last_non_end_token.append(token)
+
+    def get_closed_container_info(self, index: int) -> ClosedContainerAdjustments:
+        """
+        Get the current information on all closed containers.
+        """
+        return self.__closed_container_adjustments[index]
+
+    def in_at_least_one_container(self) -> bool:
+        """
+        Check to see if we are in at least one container.
+        """
+        return bool(self.__container_token_stack)
+
+    def get_container_stack_size(self) -> int:
+        """
+        Get the number of containers that we are currently in.
+        """
+        return len(self.__container_token_stack)
+
+    def get_container_stack_item(self, index: int) -> MarkdownToken:
+        """
+        Get a specific container from the stack.
+        """
+        return self.__container_token_stack[index]
+
+    @staticmethod
+    def calculate_token_line_number(token: MarkdownToken) -> int:
+        """
+        Since setext tokens are "weird", helper function to calculate the line number.
+        """
+        if token.is_setext_heading:
+            setext_token = cast(SetextHeadingMarkdownToken, token)
+            return setext_token.original_line_number
+        return token.line_number
+
+    def __process_container_end_block_quote(
+        self, token: MarkdownToken, end_tokens: List[EndMarkdownToken]
+    ) -> None:
+        for stack_index in range(len(self.__container_token_stack) - 2, -1, -1):
+            current_stack_token = self.__container_token_stack[stack_index]
+            if current_stack_token.is_block_quote_start:
+                line_number_delta = (
+                    LeadingSpaceIndexTracker.calculate_token_line_number(token)
+                    - self.__container_token_stack[-1].line_number
+                )
+                if end_tokens[-1].extra_end_data is not None:
+                    line_number_delta += 1
+                self.__closed_container_adjustments[
+                    stack_index
+                ].adjustment += line_number_delta
+                self.__closed_container_adjustments[stack_index].count += 1
+
+                does_current_container_have_weird_kludge_six = (
+                    self.__container_token_stack[-1].is_block_quote_start
+                    and cast(
+                        BlockQuoteMarkdownToken, self.__container_token_stack[-1]
+                    ).weird_kludge_six
+                )
+                was_last_non_end_token_blank_line = (
+                    self.__end_tokens
+                    and self.__since_last_non_end_token
+                    and self.__since_last_non_end_token[0].is_blank_line
+                )
+
+                if (
+                    does_current_container_have_weird_kludge_six
+                    and not was_last_non_end_token_blank_line
+                ):
+                    self.__closed_container_adjustments[stack_index].count2 += 1
+                break
+
+    def __process_container_end_list(self, token: MarkdownToken) -> None:
+        for stack_index in range(len(self.__container_token_stack) - 2, -1, -1):
+            current_stack_token = self.__container_token_stack[stack_index]
+            if current_stack_token.is_list_start:
+                line_number_delta = (
+                    LeadingSpaceIndexTracker.calculate_token_line_number(token)
+                    - self.__container_token_stack[-1].line_number
+                )
+                self.__closed_container_adjustments[
+                    stack_index
+                ].adjustment += line_number_delta
+                break
+
+    def get_tokens_block_quote_bleading_space_index(self, token: MarkdownToken) -> int:
+        """
+        Get the index of the token within the contain block quote's bleading_spaces string.
+        """
+        container_index = self.get_container_stack_size() - 1
+        assert self.__container_token_stack[container_index].is_block_quote_start
+        block_quote_token = cast(
+            BlockQuoteMarkdownToken, self.__container_token_stack[container_index]
+        )
+        last_closed_container_info = self.__closed_container_adjustments[-1]
+
+        assert (
+            block_quote_token.bleading_spaces is not None
+        ), "At least one line should have been processed."
+        return (
+            LeadingSpaceIndexTracker.calculate_token_line_number(token)
+            - block_quote_token.line_number
+        ) - (last_closed_container_info.adjustment - last_closed_container_info.count2)


Test patch:
diff --git a/publish/test-results.json b/publish/test-results.json
index 6eae7fb0..23baa29b 100644
--- a/publish/test-results.json
+++ b/publish/test-results.json
@@ -1300,10 +1300,10 @@
         },
         {
             "name": "test.rules.test_md027",
-            "totalTests": 117,
+            "totalTests": 118,
             "failedTests": 0,
             "errorTests": 0,
-            "skippedTests": 1,
+            "skippedTests": 0,
             "elapsedTimeInMilliseconds": 0
         },
         {
@@ -1364,7 +1364,7 @@
         },
         {
             "name": "test.rules.test_md031",
-            "totalTests": 372,
+            "totalTests": 373,
             "failedTests": 0,
             "errorTests": 0,
             "skippedTests": 13,
diff --git a/test/rules/test_md007.py b/test/rules/test_md007.py
index 5b619777..ac6ab9ef 100644
--- a/test/rules/test_md007.py
+++ b/test/rules/test_md007.py
@@ -253,6 +253,7 @@ scanTests = [
 >    * this is level 2
 """,
         scan_expected_return_code=1,
+        use_debug=True,
         scan_expected_output=(
             "{temp_source_path}:4:6: MD007: Unordered list indentation [Expected: 2, Actual=3] (ul-indent)"
         ),
diff --git a/test/rules/test_md027.py b/test/rules/test_md027.py
index 8a032908..2af1d7af 100644
--- a/test/rules/test_md027.py
+++ b/test/rules/test_md027.py
@@ -741,11 +741,10 @@ scanTests = [
 """,
         disable_rules="",
         scan_expected_return_code=1,
-        # use_debug=True,
         scan_expected_output="""{temp_source_path}:5:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:7:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)""",
     ),
-    pluginRuleTest(  # https://github.com/jackdewinter/pymarkdown/issues/1209
+    pluginRuleTest(
         "md031_final_bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_thematics",
         source_file_contents="""> + > -----
 >   > > block 1
@@ -760,8 +759,6 @@ scanTests = [
 > + another list""",
         disable_rules="md047,md032",
         scan_expected_return_code=0,
-        # use_debug=True,
-        mark_scan_as_skipped=True,
         scan_expected_output="""""",
     ),
     pluginRuleTest(
@@ -776,7 +773,6 @@ scanTests = [
 """,
         disable_rules="md007,md009,md012,md030,md031",
         scan_expected_return_code=0,
-        # use_debug=True,
         scan_expected_output="",
     ),
     pluginRuleTest(
@@ -790,6 +786,24 @@ scanTests = [
 >     ```
 >     -----
 > + another list
+""",
+        disable_rules="md007,md009,md012,md030,md031",
+        scan_expected_return_code=0,
+        # use_debug=True,
+        scan_expected_output="",
+    ),
+    pluginRuleTest(
+        "md031_final_bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_blockx",
+        source_file_contents="""> + > -----
+>   > > block 1
+>   > > block 2
+>   >
+>   > ```block
+>   > A code block
+>   > ```
+>   >
+>   > -----
+> + another list
 """,
         disable_rules="md007,md009,md012,md030,md031",
         scan_expected_return_code=0,
diff --git a/test/rules/test_md031.py b/test/rules/test_md031.py
index bcebb3d7..9e7fc139 100644
--- a/test/rules/test_md031.py
+++ b/test/rules/test_md031.py
@@ -54,7 +54,6 @@ A code block
 This is a blank line and some text.
 """,
         scan_expected_return_code=1,
-        use_debug=True,
         scan_expected_output="""{temp_source_path}:2:1: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         fix_expected_file_contents="""This is text and no blank line.
@@ -262,7 +261,6 @@ This is a blank line and some text.
 >
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:2:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
@@ -286,7 +284,6 @@ This is a blank line and some text.
 > ___
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:3:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -313,7 +310,6 @@ This is a blank line and some text.
 > ---
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:3:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -338,7 +334,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
@@ -362,7 +357,6 @@ This is a blank line and some text.
 > ___
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -389,7 +383,6 @@ This is a blank line and some text.
 > ---
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -413,7 +406,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:2:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:4:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -437,7 +429,6 @@ This is a blank line and some text.
 > ****
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:3:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -488,7 +479,6 @@ This is a blank line and some text.
 > ****
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:3:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:4:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -511,7 +501,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:2:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:4:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -534,7 +523,6 @@ This is a blank line and some text.
 > ```
 > This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:3:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -560,7 +548,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:7:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -589,7 +576,6 @@ This is a blank line and some text.
 > ___
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -621,7 +607,6 @@ This is a blank line and some text.
 > ---
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -650,7 +635,6 @@ This is a blank line and some text.
 > ```
 > This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md032",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:3:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -677,7 +661,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:7:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -705,7 +688,6 @@ This is a blank line and some text.
 > ___
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026,md032",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:4:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -736,7 +718,6 @@ This is a blank line and some text.
 > ---
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -766,7 +747,6 @@ This is a blank line and some text.
 > ```
 > This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:4:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -794,7 +774,6 @@ This is a blank line and some text.
 > ---
 > This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:7:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -823,7 +802,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         mark_scan_as_skipped=True,
         mark_fix_as_skipped=True,
         scan_expected_return_code=1,
@@ -855,7 +833,6 @@ This is a blank line and some text.
 > ```
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:7:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:9:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -887,9 +864,7 @@ This is a blank line and some text.
 > ___
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026,md027",
-        # use_fix_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:8:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -923,7 +898,6 @@ This is a blank line and some text.
 > ---
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022,md026",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:8:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -956,7 +930,6 @@ This is a blank line and some text.
 >
 >This is a blank line and some text.
 """,
-        use_debug=True,
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:4:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
@@ -984,7 +957,6 @@ This is a blank line and some text.
 > ---
 >This is a blank line and some text.
 """,
-        use_debug=True,
         disable_rules="md022",
         scan_expected_return_code=1,
         scan_expected_output="""{temp_source_path}:5:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
@@ -1144,7 +1116,6 @@ A code block
         scan_expected_output="""{temp_source_path}:2:1: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:4:1: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
-        use_debug=True,
         fix_expected_file_contents="""> block quote
 
 ```block
@@ -1224,8 +1195,6 @@ A code block
 {temp_source_path}:4:1: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
-        use_fix_debug=False,
         fix_expected_file_contents="""+ list
 
 ```block
@@ -1496,8 +1465,6 @@ abc
 {temp_source_path}:6:3: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        # use_fix_debug=True,
-        # use_debug=True,
         fix_expected_file_contents="""+ list
   + inner list
     couple of lines
@@ -2032,7 +1999,6 @@ abc
 {temp_source_path}:6:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""> > + block 3
 > >   block 3
 > > + block 3
@@ -2060,7 +2026,6 @@ abc
 {temp_source_path}:7:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""> > + block 3
 > >   block 3
 > > + block 3
@@ -2092,7 +2057,6 @@ abc
 {temp_source_path}:9:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md022,md024",
-        use_debug=True,
         fix_expected_file_contents="""> > + block 3
 > >   block 3
 > > + block 3
@@ -2389,7 +2353,6 @@ abc
 {temp_source_path}:6:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""> > + --------
 > >   > block 1
@@ -2637,7 +2600,6 @@ abc
 {temp_source_path}:6:6: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > >
    > > block 3
    > > block 3
@@ -2726,7 +2688,6 @@ abc
 {temp_source_path}:6:6: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > >
    > > block 3
    > block 3
@@ -2754,6 +2715,7 @@ abc
 {temp_source_path}:7:6: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
+        use_debug=True,
         fix_expected_file_contents="""1. > >
    > > block 3
    > block 3
@@ -2899,7 +2861,6 @@ abc
 {temp_source_path}:4:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > >
    > > ```block
@@ -2921,7 +2882,6 @@ abc
 {temp_source_path}:3:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > >
    > > ```block
@@ -2967,7 +2927,6 @@ abc
 {temp_source_path}:6:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md027",
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""1. > + ----
    >   > block 1
@@ -3173,7 +3132,6 @@ abc
 {temp_source_path}:6:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > > > inner block 1
    > > > inner block 2
@@ -3201,7 +3159,6 @@ abc
 {temp_source_path}:7:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > > > inner block 1
    > > > inner block 2
@@ -3233,7 +3190,6 @@ abc
 {temp_source_path}:9:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md022,md024",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > > > inner block 1
    > > > inner block 2
@@ -3265,7 +3221,6 @@ abc
 {temp_source_path}:7:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > > + list 1
    > >   list 2
@@ -3295,7 +3250,6 @@ abc
 {temp_source_path}:8:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > > + list 1
    > >   list 2
@@ -3329,7 +3283,6 @@ abc
 {temp_source_path}:10:8: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md022,md024",
-        use_debug=True,
         fix_expected_file_contents="""1. > > ----
    > > + list 1
    > >   list 2
@@ -3479,7 +3432,6 @@ abc
 {temp_source_path}:6:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md027",
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""> + list 1
 >   > block 2
@@ -3659,7 +3611,6 @@ abc
 {temp_source_path}:7:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        # mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""> + list 1
 >   + list 2
 >     list 3
@@ -3948,7 +3899,9 @@ abc
         scan_expected_output="""{temp_source_path}:4:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 {temp_source_path}:6:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
-        disable_rules="md032",
+        disable_rules="md032,md027",
+        # use_fix_debug=True,
+        use_debug=True,
         fix_expected_file_contents="""> + > -----
 >   > > block 1
 >   > > block 2
@@ -3980,8 +3933,6 @@ abc
 {temp_source_path}:9:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        # use_debug=True,
-        use_fix_debug=False,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""> + > -----
 >   > > block 1
@@ -4028,6 +3979,24 @@ abc
 > + another list
 """,
     ),
+    pluginRuleTest(  # test_extra_044mcv0 test_extra_044mcv1
+        "bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_thematics_fixed",
+        source_file_contents="""> + > -----
+>   > > block 1
+>   > > block 2
+>   > -----
+>   >
+>   > ```block
+>   > A code block
+>   > ```
+>   >
+>   > -----
+> + another list
+""",
+        scan_expected_return_code=0,
+        scan_expected_output="",
+        disable_rules="md032,md027",
+    ),
     pluginRuleTest(
         "bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_setext",
         source_file_contents="""> + > -----
@@ -4227,7 +4196,6 @@ abc
 """,
         disable_rules="md032,md027",
         mark_fix_as_skipped=temp_disable_fixes,
-        use_debug=True,
         use_fix_debug=True,
         fix_expected_file_contents="""> + + -----
 >     > block 1
@@ -4258,7 +4226,6 @@ abc
 {temp_source_path}:7:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md027",
-        use_debug=True,
         fix_expected_file_contents="""> + + -----
 >     > block 1
 >     > block 2
@@ -4292,7 +4259,6 @@ abc
 {temp_source_path}:9:7: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md027,md022,md024",
-        use_debug=True,
         fix_expected_file_contents="""> + + -----
 >     > block 1
 >     > block 2
@@ -4494,7 +4460,6 @@ abc
 {temp_source_path}:6:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""+ + list 1
     > block 2.1
     > block 2.2
@@ -4522,7 +4487,6 @@ abc
 {temp_source_path}:7:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         fix_expected_file_contents="""+ + list 1
     > block 2.1
     > block 2.2
@@ -4555,7 +4519,6 @@ abc
 {temp_source_path}:9:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md022,md024",
-        use_debug=True,
         fix_expected_file_contents="""+ + list 1
     > block 2.1
     > block 2.2
@@ -4587,8 +4550,6 @@ abc
 {temp_source_path}:6:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        # use_fix_debug=True,
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""+ + list 1
 + + + list 2.1
@@ -4678,7 +4639,6 @@ abc
 {temp_source_path}:6:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""+ + list 1
 + + + list 2.1
@@ -4707,7 +4667,6 @@ abc
 {temp_source_path}:7:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032",
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""+ + list 1
 + + + list 2.1
@@ -4741,7 +4700,6 @@ abc
 {temp_source_path}:9:5: MD031: Fenced code blocks should be surrounded by blank lines (blanks-around-fences)
 """,
         disable_rules="md032,md022,md024",
-        use_debug=True,
         mark_fix_as_skipped=temp_disable_fixes,
         fix_expected_file_contents="""+ + list 1
 + + + list 2.1
diff --git a/test/test_markdown_extra.py b/test/test_markdown_extra.py
index 3aed14d5..bfa8b077 100644
--- a/test/test_markdown_extra.py
+++ b/test/test_markdown_extra.py
@@ -11680,7 +11680,6 @@ block 2</p>
 @pytest.mark.gfm
 def test_extra_044mcv1():
     """
-    BAR-A
     bad_fenced_block_in_block_quote_in_list_in_block_quote_with_previous_block_with_thematics
     """