Prompt-Residue Comments.
Comments that are artifacts of the generation conversation — restated prompts, step-by-step narration, chat asides, and placeholder elisions like `// ... rest of the code here` — committed into source instead of real documentation.
##Signs and Symptoms
A reviewer spots Prompt-Residue Comments when the comments document the conversation that produced the code rather than the code itself. Four tells, often co-occurring:
- Restated prompt — a comment that paraphrases the request verbatim (
// Function to add two numbers) above a function literally namedadd. - Step narration — line-by-line play-by-play of obvious operations (
// Step 1: loop over the array,// increment i by 1abovei++). - Chat asides — second-person, present-tense remarks aimed at you, the prompter (
// As requested, here is the updated handler,// Sure! Here's the fix,// Note: replace with your actual API key). - Elision / placeholder residue —
// ... rest of the code here,// keep your existing logic,// your code here,// TODO: implement error handlingleft in committed source.
// Function to add two numbers and return the result <- restates the prompt
function add(a: number, b: number): number {
// Step 1: add the two numbers <- narrates the obvious
const sum = a + b;
return sum; // return the sum
}
// As requested, here is the updated handler <- chat aside to "you"
export async function handler(req: Req, res: Res) {
// ... keep your existing validation logic here ... <- elision: real code dropped
// TODO: implement error handling <- placeholder shipped as-is
const user = await db.users.find(req.params.id);
res.json(user);
}
The elision line is the dangerous one: it reads as documentation but is actually an instruction to a human to paste code that the model omitted — apply the block verbatim and the existing validation silently disappears. OX Security found "Comments Everywhere" in 90–100% of AI-generated code in its 300+ repo study, describing them as markers that "look helpful but mainly support the AI itself, cluttering repositories."
##Reasons for the Problem
Why models emit it
- Next-token mimicry of tutorial corpora. The training mix is saturated with blog posts, StackOverflow answers, and docs where every line is explained for a learner. The model reproduces that didactic register — narration and restated intent — because it is the statistically likely continuation, not because the surrounding repo needs it.
- Chat register bleed / sycophancy. RLHF tunes assistants to be explanatory and agreeable in the chat channel. That conversational, second-person tone leaks into the code channel, producing "As requested…" and "Note: you should…" asides that make no sense once the code is detached from the conversation.
- Reasoning narrated as comments. Models externalize their plan ("Step 1… Step 2…") as inline comments — chain-of-thought leakage frozen into the file.
- Elision is a chat affordance, misapplied. In a chat reply,
// ... rest unchanged ...is a polite way to avoid re-printing a file. When that reply is pasted or auto-applied to a real file, the affordance becomes literal residue — and literal data loss. - No repo context, so it restates the prompt. Lacking the ticket, the domain, and the real "why," the model has nothing true to say in a comment, so it falls back to paraphrasing the only thing it has: your prompt. OX characterizes the comments as "internal markers to navigate context limits… dependence on short-term memory rather than true understanding."
Why it hurts
- Review load. Every narration line is noise a human must read past. OX's framing: AI "codes like a junior dev" at machine speed, and human review "cannot scale to match AI's output" — residue comments make each diff more expensive to review precisely when there are more diffs.
- Correctness / data loss. Elision placeholders (
// ...existing code...) cause real code to be dropped when blocks are applied blindly. - Comment rot. Restated-prompt comments duplicate the code's intent in prose; the prose drifts as the code changes, leaving actively misleading documentation — Fowler's classic Comments-as-deodorant smell.
- Hidden incompleteness.
// TODO: implement error handlingis the model signaling it worked at the edge of its competence; shipped as-is, it is unfinished logic disguised as a tracked task. - Security tells.
// replace with your actual API keytypically sits beside a hardcoded placeholder credential — the residue marks exactly the line a scanner (and an attacker) cares about.
##Treatment
Prompting / generation tactics
- Constrain the register: "Output the complete file. Never abbreviate with
// ...,// rest of the code, or// existing code. Do not narrate steps — comment only non-obvious rationale (the why). No conversational asides; this goes straight into a repo." - Ask for a unified diff rather than a prose-wrapped snippet, so omissions are explicit and applyable instead of hand-waved with an elision comment.
- Require the model to run the formatter and your lint config (e.g.
no-warning-commentswith custom terms) and report the result — closing the "validate with the linter" loop catches placeholder/TODO residue automatically. - Add a pre-commit / CI grep gate for residue markers (
rest of the code,your code here,existing code,As requested,Step \d) and treat elision markers as a hard blocker, since they often mean code was silently dropped.
The refactor
Delete chat asides and narration outright. Where a comment merely restates what the code does, that is the signal to make the code self-documenting — apply Extract Function and Rename so the name carries the intent, then keep only comments that explain a non-obvious why (Fowler: Remove comments that are deodorant for bad names).
// before — prompt residue
// Create a function that validates an email address using a regex
function validateEmail(input) {
// check if the input matches the email pattern
const re = /^[^@]+@[^@]+\.[^@]+$/;
// return true or false
return re.test(input);
}
// after — name carries intent; the only comment explains the non-obvious why
const EMAIL_RE = /^[^@]+@[^@]+\.[^@]+$/; // intentionally loose: we only catch typos pre-send, not RFC 5322
const isValidEmail = (input: string): boolean => EMAIL_RE.test(input);
For elision residue, never apply the block as written — diff it against the current file and restore what the model dropped. For // TODO: implement …, either finish the logic or convert it into a tracked issue and fail the build on the placeholder term so it cannot ship as-is.
##Detected by
- ESLint no-warning-comments — Flags TODO/FIXME/XXX and custom configurable terms — set `terms` to catch placeholder residue like "your code here" or "rest of the code"
- SonarQube / SonarSource S125 — Sections of code should not be commented out — flags elided/leftover commented-out blocks
- SonarQube / SonarSource S1135 — Track uses of "TODO" tags — surfaces placeholder TODO residue shipped as code
- SonarQube / SonarSource S1134 — Track uses of "FIXME" tags