From e15ee864ba625de1ae73d25324c9168d941a7bf4 Mon Sep 17 00:00:00 2001 From: yilin-succeed <204474593+yilin-succeed@users.noreply.github.com> Date: Tue, 15 Sep 2026 12:03:59 +0800 Subject: [PATCH 1/3] fix(bootstrap): isolate objective prose from generated state grammar Quote-isolate the Objective body in both state writers so a collapsed or unclosed fence, comment, or heading/task example inside an objective can no longer open machine grammar and hide the generated Todo sections below. The frontmatter objective keeps the raw text, and the chat context readback strips the quote prefix to recover it verbatim. References #4401 Signed-off-by: yilin-succeed <204474593+yilin-succeed@users.noreply.github.com> --- loopx/bootstrap.py | 18 ++- loopx/chat_server.py | 16 ++- loopx/control_plane/projects/registry.py | 4 +- .../control_plane/test_objective_isolation.py | 119 ++++++++++++++++++ 4 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 tests/control_plane/test_objective_isolation.py diff --git a/loopx/bootstrap.py b/loopx/bootstrap.py index 4138655e83..36ed136faf 100644 --- a/loopx/bootstrap.py +++ b/loopx/bootstrap.py @@ -465,6 +465,22 @@ def apply_onboarding_todos_to_state( return "\n".join(lines) + "\n" +def render_objective_markdown(objective: str) -> str: + """Render objective prose as an isolated Markdown blockquote. + + Generated state grammar owns fences, comments, and headings. Raw + objective text is quoted line by line so a start-goal-collapsed or + unclosed fence, comment, or heading example inside the objective can + never open machine grammar and hide the generated Todo sections below. + The frontmatter ``objective`` field keeps the raw text; readers of the + body section strip the quote prefix to recover it. + """ + lines = str(objective or "").splitlines() + if not lines: + return "" + return "\n".join(f"> {line}" if line.strip() else ">" for line in lines) + + def render_state_markdown( *, project: Path, @@ -516,7 +532,7 @@ def render_state_markdown( ## Objective -{objective} +{render_objective_markdown(objective)} ## Authority Sources diff --git a/loopx/chat_server.py b/loopx/chat_server.py index 32ec182d90..32c8d648dc 100644 --- a/loopx/chat_server.py +++ b/loopx/chat_server.py @@ -132,11 +132,17 @@ def _active_state_section(state_text: str, heading: str) -> str: content_start = start + len(marker) end = state_text.find("\n## ", content_start) section = state_text[content_start : end if end >= 0 else None] - lines = [ - line.strip().removeprefix("- ").strip() - for line in section.splitlines() - if line.strip() and not line.lstrip().startswith("