Skip to content

fix: 长会话任务锚点重注入 + 过早 end_turn 提示,缓解任务跑偏 - #1309

Open
universe-hcy wants to merge 1 commit into
claude-code-best:mainfrom
universe-hcy:avoid_long_task_attention_degradation
Open

fix: 长会话任务锚点重注入 + 过早 end_turn 提示,缓解任务跑偏#1309
universe-hcy wants to merge 1 commit into
claude-code-best:mainfrom
universe-hcy:avoid_long_task_attention_degradation

Conversation

@universe-hcy

@universe-hcy universe-hcy commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

现象:
长开发任务跑到一半反复"停住"(像卡顿),由于这个任务并非我完全关心的,在每次卡住后我按顺序发了 6 条催促:

# 行号 时间(UTC) 催促内容
1 177 11:32 目前开发进度怎么样了
2 186 11:43 目前开发到哪个阶段了
3 218 11:54 继续执行后续的工作
4 253 12:02 自动执行后续的所有流程
5 264 12:09 继续完成未完成的任务
6 281 12:16 继续完成当前任务

后期模型"忘记任务要做什么"、编辑把文件写出"重复的、不可能编译的行",陷入自我核实打转。执行 /rewind 退回后恢复正常。这个现象我先前在qwen模型上遇到过几次,属于是模型注意力被稀释后导致的任务锚点漂移轨迹问题,目前看起来opus 4.8对于长任务 + 连续无锚点注入也会出现这个问题。

由于无法保障用户都知道存在模型注意力被稀释后导致的任务锚点漂移轨迹问题,同时用户并行使用agent,并不一定能够对当前任务足够重视,从而在长任务卡住时也可能出现连续输出“继续 ”的情况,期望在harness层进行一定的保障。下面我采用了token 友好的方式,对该问题进行修复

修复方案:
长会话反复无锚点催促("继续/接着做")会导致任务锚点衰减、模型过早
end_turn 打转。新增两层客户端护栏(均 token 友好):

  • 层3 触发式锚点重注入:仅当最新用户消息是短的无锚点催促且存在未完成 任务时,注入一次 ephemeral 未完成任务清单(工具循环 内不重复注入,无每轮成本)。
  • 层2 过早 end_turn 提示:turn 自然完成且仍有 in_progress 任务时,显示 0-token 本地 system 提示(不发给模型)。

Summary by CodeRabbit

  • New Features

    • Added automatic continuation prompts for unfinished tasks after a completed turn.
    • Pressing Tab on an empty prompt inserts the suggested continuation.
    • Added warnings when unfinished tasks remain, including task details and pending counts.
    • Added context contamination detection with remediation guidance, including /rewind.
  • Tests

    • Added coverage for task continuation, task notices, and context-contamination detection.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The REPL now surfaces unfinished-task notices, stores a Tab-insertable continuation prompt, and detects harness-like context bleed in assistant output. New task reminder and degradation guard utilities include focused unit tests.

Changes

Turn completion safeguards

Layer / File(s) Summary
Task reminder builders and coverage
src/services/api/taskAnchorReminder.ts, src/services/api/__tests__/taskAnchorReminder.test.ts
Adds unfinished-task prioritization, continuation prompt generation, notice formatting, and tests for selection, counts, overflow, and Tab guidance.
REPL completion safeguards
src/screens/REPL.tsx
Adds Tab handling for pending continuations and appends task warnings or context-bleed warnings after non-aborted turns.
Context-bleed detection and coverage
src/services/api/degradationGuard.ts, src/services/api/__tests__/degradationGuard.test.ts
Detects fingerprinted closed system-reminder blocks and tests matching and non-matching assistant output.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant REPL
  participant taskAnchorReminder
  participant degradationGuard
  participant Transcript
  REPL->>taskAnchorReminder: Build task notice and continuation
  taskAnchorReminder-->>REPL: Return notice and prompt
  REPL->>Transcript: Append task warning
  REPL->>degradationGuard: Analyze assistant output
  degradationGuard-->>REPL: Return warning or null
  REPL->>Transcript: Append degradation warning
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了长会话中的任务锚点重注入和过早 end_turn 提示这两个核心改动。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@src/screens/REPL.tsx`:
- Around line 3533-3536: Update the dynamic imports in the notice injection
within REPL to use the relative paths ../utils/tasks.js and
../services/api/taskAnchorReminder.js instead of src/ aliases, while preserving
the existing imported symbols and Promise.all flow.

In `@src/services/api/taskAnchorReminder.ts`:
- Around line 20-25: Update isAnchorlessNudge to reject trimmed text containing
an explicit task anchor before applying ANCHORLESS_NUDGE_PATTERN, while
preserving existing length and nudge-word validation. Reuse the existing
task-reference detection symbol if available, and add regression coverage
confirming inputs such as “continue Task `#2`” return false.
🪄 Autofix (Beta)

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: 9af9169d-beab-4a26-86e1-3efe3884e075

📥 Commits

Reviewing files that changed from the base of the PR and between 34b3dc9 and e3b15d0.

📒 Files selected for processing (4)
  • src/screens/REPL.tsx
  • src/services/api/__tests__/taskAnchorReminder.test.ts
  • src/services/api/claude.ts
  • src/services/api/taskAnchorReminder.ts

Comment thread src/screens/REPL.tsx Outdated
Comment on lines +3533 to +3536
const [{ listTasks, getTaskListId }, { buildUnfinishedTaskNotice }] = await Promise.all([
import('src/utils/tasks.js'),
import('src/services/api/taskAnchorReminder.js'),
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -HI -t f . | rg '/(tsconfig[^/]*\.json|package\.json|bunfig\.toml)$'
rg -n -C2 '"(baseUrl|paths)"|src/' \
  --glob 'tsconfig*.json' \
  --glob 'package.json' \
  --glob 'bunfig.toml' .

Repository: claude-code-best/claude-code

Length of output: 18729


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Top-level package manifests/configs:"
fd -HI -t f '/^(package\.json|tsconfig\.json|bunfig\.toml|vite\.config\.[^/]+)$' -d 2 . | sed 's#^\./##' | sort

echo
echo "Top-level package.json scripts and imports:"
python3 - <<'PY'
import json
from pathlib import Path
p=Path('package.json')
if p.exists():
    data=json.loads(p.read_text())
    print(json.dumps({"name": data.get("name")} | {k:data.get(k) for k in ["scripts","imports","type","tsup"]}, indent=2, sort_keys=True))
else:
    print("no package.json")
PY

echo
echo "Top-level tsconfig relevant fields:"
python3 - <<'PY'
import json
from pathlib import Path
p=Path('tsconfig.json')
if p.exists():
    data=json.loads(p.read_text())
    print(json.dumps({k:data.get(k) for k in ["extends","compilerOptions","include","exclude","references"]}, indent=2, sort_keys=True))
else:
    print("no top-level tsconfig.json")
PY

echo
echo "Top-level bunfig relevant:"
if [ -f bunfig.toml ]; then cat -n bunfig.toml; else echo "no bunfig.toml"; fi

echo
echo "Other root aliases/imports:"
rg -n -C2 '"imports"|"alias"|[Aa]lias|root:\s*[^#]+|baseUrl|resolve|alias:' --glob 'package.json' --glob 'tsconfig*.json' --glob 'vite.config.*' --glob 'bunfig.toml' .

Repository: claude-code-best/claude-code

Length of output: 7679


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import json, re
p='package.json'
data=json.load(open(p))
root=re.compile(r'^\s*root\s*=?\s*["\']?([^"'\n\#]+)["\']?\s*$|^\s*root\s*=\s*["\']?([^"'\n\#]+)["\']?\s*$')
tsconfig=json.load(open('tsconfig.json'))
files=[]
for f in ['src/utils/tasks.js', 'src/services/api/taskAnchorReminder.js']:
    try:
        from pathlib import Path
        files.append((f, Path(f).exists()))
    except Exception as e:
        files.append((f, f'<error: {e}>'))
print(json.dumps({
    "root_root_alias": re.search(root, open('bunfig.toml').read()).group(1) if root.search(open('bunfig.toml').read()) else None,
    "package_root_alias": data.get("root"),
    "tsconfig_paths_src": tsconfig.get("compilerOptions", {}).get("paths", {}).get("src/*"),
    "files_exist": dict(files)
}, indent=2))
PY

Repository: claude-code-best/claude-code

Length of output: 424


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "bunfig root settings:"
python3 - <<'PY'
from pathlib import Path
p=Path('bunfig.toml')
text=p.read_text()
for line in text.splitlines():
    s=line.strip()
    if s.startswith('root'):
        print(line)
print(bool(p.exists()))
PY

echo
echo "package root settings:"
python3 - <<'PY'
import json
data=json.load(open('package.json'))
print(data.get('root'))
PY

echo
echo "tsconfig src alias:"
python3 - <<'PY'
import json
data=json.load(open('tsconfig.json'))
print(data.get('compilerOptions',{}).get('paths',{}).get('src/*'))
PY

echo
echo "target files exist:"
python3 - <<'PY'
from pathlib import Path
for f in ['src/utils/tasks.js', 'src/services/api/taskAnchorReminder.js']:
    print(f"{f}: {Path(f).exists()}")
PY

Repository: claude-code-best/claude-code

Length of output: 359


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Search exact specifier targets:"
rg -n "'src/utils/tasks\.js'|'src/services/api/taskAnchorReminder\.js'|utils/tasks|taskAnchorReminder" --glob '!node_modules' .

echo
echo "Top-level manifest root package files:"
fd -HI -t f '^root\.js$|^src$' . -d 4 | sed 's#^\./##'

echo
echo "REPL snippet context:"
sed -n '3525,3550p' src/screens/REPL.tsx 2>/dev/null || true

Repository: claude-code-best/claude-code

Length of output: 4906


Use relative dynamic imports for the notice injection.

src/* is only configured in TypeScript and Vite config; Bun package imports are not configured with a src/ alias, so these bare imports can resolve differently at native Bun runtime. Use ../utils/tasks.js and ../services/api/taskAnchorReminder.js instead.

🤖 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 `@src/screens/REPL.tsx` around lines 3533 - 3536, Update the dynamic imports in
the notice injection within REPL to use the relative paths ../utils/tasks.js and
../services/api/taskAnchorReminder.js instead of src/ aliases, while preserving
the existing imported symbols and Promise.all flow.

Comment thread src/services/api/taskAnchorReminder.ts Outdated
Comment on lines +20 to +25
export function isAnchorlessNudge(text: string): boolean {
const trimmed = text.trim()
if (!trimmed || trimmed.length > MAX_NUDGE_CHARS) {
return false
}
return ANCHORLESS_NUDGE_PATTERN.test(trimmed)

Copy link
Copy Markdown
Contributor

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

Reject nudges that include a task anchor.

Line 25 treats any short text containing a nudge word as anchorless. For example, continue Task #2`` matches and injects a reminder telling the model to continue the highest-priority task, overriding the user’s explicit task selection. Exclude explicit task references (and add regression coverage for them).

Proposed direction
+const TASK_REFERENCE_PATTERN = /(?:task|任务)\s*#?\d+\b/i
+
 export function isAnchorlessNudge(text: string): boolean {
   const trimmed = text.trim()
   if (!trimmed || trimmed.length > MAX_NUDGE_CHARS) {
     return false
   }
-  return ANCHORLESS_NUDGE_PATTERN.test(trimmed)
+  return (
+    ANCHORLESS_NUDGE_PATTERN.test(trimmed) &&
+    !TASK_REFERENCE_PATTERN.test(trimmed)
+  )
 }
📝 Committable suggestion

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

Suggested change
export function isAnchorlessNudge(text: string): boolean {
const trimmed = text.trim()
if (!trimmed || trimmed.length > MAX_NUDGE_CHARS) {
return false
}
return ANCHORLESS_NUDGE_PATTERN.test(trimmed)
const TASK_REFERENCE_PATTERN = /(?:task|)\s*#?\d+\b/i
export function isAnchorlessNudge(text: string): boolean {
const trimmed = text.trim()
if (!trimmed || trimmed.length > MAX_NUDGE_CHARS) {
return false
}
return (
ANCHORLESS_NUDGE_PATTERN.test(trimmed) &&
!TASK_REFERENCE_PATTERN.test(trimmed)
)
}
🤖 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 `@src/services/api/taskAnchorReminder.ts` around lines 20 - 25, Update
isAnchorlessNudge to reject trimmed text containing an explicit task anchor
before applying ANCHORLESS_NUDGE_PATTERN, while preserving existing length and
nudge-word validation. Reuse the existing task-reference detection symbol if
available, and add regression coverage confirming inputs such as “continue Task
`#2`” return false.

@universe-hcy
universe-hcy force-pushed the avoid_long_task_attention_degradation branch from e3b15d0 to a1bcddf Compare July 27, 2026 20:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@src/screens/REPL.tsx`:
- Around line 3550-3596: Replace the four bare `src/...` dynamic imports in the
unfinished-task notice and context-bleed guard blocks with correct relative
module paths, matching the existing relative-import style in `REPL.tsx`.
Preserve the imported symbols and both blocks’ best-effort error handling so the
safeguards execute instead of being silently skipped.

In `@src/services/api/degradationGuard.ts`:
- Around line 62-65: Update the degradation guard around CLOSED_REMINDER_BLOCK
matching to ignore matches located inside Markdown inline code spans or fenced
code blocks, while preserving detection for ordinary reminder blocks. Add a
regression test covering a quoted closed reminder in both relevant code formats
and verify it does not return CONTEXT_BLEED_NOTICE.
- Line 46: Wrap the over-width notice string in degradationGuard.ts by joining
shorter segments while preserving its exact content. Apply the same
shorter-segment construction to both fixture strings in degradationGuard.test.ts
at the specified sites, keeping all non-TSX lines within 80 characters.
🪄 Autofix (Beta)

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: 0ebeadad-4d8e-4e9b-9079-34a88ccf10a1

📥 Commits

Reviewing files that changed from the base of the PR and between e3b15d0 and a1bcddf.

📒 Files selected for processing (5)
  • src/screens/REPL.tsx
  • src/services/api/__tests__/degradationGuard.test.ts
  • src/services/api/__tests__/taskAnchorReminder.test.ts
  • src/services/api/degradationGuard.ts
  • src/services/api/taskAnchorReminder.ts

Comment thread src/screens/REPL.tsx
Comment on lines +3550 to +3596
// ── Unfinished-task notice ──
// When a turn completes naturally (not interrupted) but a task the model
// itself marked in_progress is still unfinished, surface a display-only
// local notice so the user doesn't have to blindly nudge "继续". This is a
// 'system' message: never sent to the model (0 token cost). Best-effort —
// a task-read failure must not affect turn teardown.
if (!abortController.signal.aborted) {
try {
const [{ listTasks, getTaskListId }, { buildUnfinishedTaskNotice, buildContinuationPrompt }] =
await Promise.all([import('src/utils/tasks.js'), import('src/services/api/taskAnchorReminder.js')]);
const tasks = await listTasks(getTaskListId());
const notice = buildUnfinishedTaskNotice(tasks);
if (notice) {
setMessages(prev => [...prev, createSystemMessage(notice, 'warning')]);
setPendingContinuation(buildContinuationPrompt(tasks));
} else {
setPendingContinuation(null);
}
} catch {
// Ignore — the notice is a convenience, not part of the turn contract.
}
}

// ── Context-bleed / degradation guard ──
// If the model regurgitated an internal <system-reminder> tag as its own
// output, that's an early signal of long-context inference-side degradation
// (2026-07-27: the model then hallucinated "file corrupted / tool not
// executed" while every tool had actually run). Surface a display-only local
// warning suggesting /rewind. 'system' message: never sent to the model
// (0 token cost). Read messagesRef.current — the closure's `messages` may be
// stale. Best-effort — a detection failure must not affect turn teardown.
if (!abortController.signal.aborted) {
try {
const [{ getLastAssistantMessage, getAssistantMessageText }, { detectContextBleed }] = await Promise.all([
import('src/utils/messages.js'),
import('src/services/api/degradationGuard.js'),
]);
const lastAssistant = getLastAssistantMessage(messagesRef.current);
const bleedNotice = lastAssistant ? detectContextBleed(getAssistantMessageText(lastAssistant)) : null;
if (bleedNotice) {
setMessages(prev => [...prev, createSystemMessage(bleedNotice, 'warning')]);
}
} catch {
// Ignore — the guard is a convenience, not part of the turn contract.
}
}

Copy link
Copy Markdown
Contributor

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

Bare src/... dynamic imports still unresolved — both new safeguards are silently dead.

This repeats a concern already raised on a prior commit of this PR (relative-import fix requested for the notice injection) but it's still present, now duplicated across two more import pairs in the same block. import('src/utils/tasks.js'), import('src/services/api/taskAnchorReminder.js'), import('src/utils/messages.js'), and import('src/services/api/degradationGuard.js') are bare specifiers — Bun resolves these via the Node module algorithm (node_modules lookup), not via the TypeScript/Vite-only src/* path alias, so each of these will reject with "Cannot find module" at runtime. Because both blocks wrap the import in a catch {} that silently swallows failures, both new safeguards (the unfinished-task notice/continuation prompt and the context-bleed guard) will never fire — and pendingContinuation (consumed by the Tab handler at L1681-1705) will never be set to anything but null. Every other dynamic import in this file already uses relative paths (e.g. ../utils/commitAttribution.js, ../commands/clear/conversation.js).

🐛 Proposed fix — use relative paths
-          const [{ listTasks, getTaskListId }, { buildUnfinishedTaskNotice, buildContinuationPrompt }] =
-            await Promise.all([import('src/utils/tasks.js'), import('src/services/api/taskAnchorReminder.js')]);
+          const [{ listTasks, getTaskListId }, { buildUnfinishedTaskNotice, buildContinuationPrompt }] =
+            await Promise.all([
+              import('../utils/tasks.js'),
+              import('../services/api/taskAnchorReminder.js'),
+            ]);
-          const [{ getLastAssistantMessage, getAssistantMessageText }, { detectContextBleed }] = await Promise.all([
-            import('src/utils/messages.js'),
-            import('src/services/api/degradationGuard.js'),
-          ]);
+          const [{ getLastAssistantMessage, getAssistantMessageText }, { detectContextBleed }] = await Promise.all([
+            import('../utils/messages.js'),
+            import('../services/api/degradationGuard.js'),
+          ]);
🤖 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 `@src/screens/REPL.tsx` around lines 3550 - 3596, Replace the four bare
`src/...` dynamic imports in the unfinished-task notice and context-bleed guard
blocks with correct relative module paths, matching the existing relative-import
style in `REPL.tsx`. Preserve the imported symbols and both blocks’ best-effort
error handling so the safeguards execute instead of being silently skipped.

]

const CONTEXT_BLEED_NOTICE =
'检测到模型在输出中回吐了完整的内部 <system-reminder> 提醒块——这通常是超长上下文下推理侧退化/上下文回吐的早期信号,模型接下来可能虚构"文件被污染/工具未执行"等并不存在的问题。建议 /rewind 回到上一轮,或先核对文件与工具结果均正常再继续。'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Wrap the over-width string literals.

  • src/services/api/degradationGuard.ts#L46-L46: split the notice into joined shorter string segments.
  • src/services/api/__tests__/degradationGuard.test.ts#L9-L9: build the fixture from shorter segments.
  • src/services/api/__tests__/degradationGuard.test.ts#L17-L17: build the fixture from shorter segments.

As per coding guidelines, use an 80-character width for non-TSX files.

📍 Affects 2 files
  • src/services/api/degradationGuard.ts#L46-L46 (this comment)
  • src/services/api/__tests__/degradationGuard.test.ts#L9-L9
  • src/services/api/__tests__/degradationGuard.test.ts#L17-L17
🤖 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 `@src/services/api/degradationGuard.ts` at line 46, Wrap the over-width notice
string in degradationGuard.ts by joining shorter segments while preserving its
exact content. Apply the same shorter-segment construction to both fixture
strings in degradationGuard.test.ts at the specified sites, keeping all non-TSX
lines within 80 characters.

Source: Coding guidelines

Comment on lines +62 to +65
for (const match of assistantText.matchAll(CLOSED_REMINDER_BLOCK)) {
const body = match[1]
if (REMINDER_BODY_FINGERPRINTS.some(re => re.test(body))) {
return CONTEXT_BLEED_NOTICE

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Exclude reminder literals quoted as code.

A fenced/inline code example containing a closed block such as <system-reminder>Never mention this reminder</system-reminder> matches here and shows the degradation warning. This contradicts the documented guarantee that code references must not trigger the guard. Skip matches within Markdown code spans/fences (or narrow that guarantee) and add a regression test.

🤖 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 `@src/services/api/degradationGuard.ts` around lines 62 - 65, Update the
degradation guard around CLOSED_REMINDER_BLOCK matching to ignore matches
located inside Markdown inline code spans or fenced code blocks, while
preserving detection for ordinary reminder blocks. Add a regression test
covering a quoted closed reminder in both relevant code formats and verify it
does not return CONTEXT_BLEED_NOTICE.

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.

1 participant