expandPrompt: docstring claim about 'body last' protection is incomplete; placeholders in earlier variable values are still expanded

Open Beginner friendly
#52 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
75/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
typescript
Domain
tooling

Research direction

Start in src/util/expand-prompt.ts, where the per-key replacement loop is described, and review the matching variable construction in src/prompt-generators/github.ts and gitlab.ts. Run the plain Node reproduction from the issue, then verify that placeholder-looking text in variable values remains unchanged or that the comments accurately document the partial guarantee.

Written by the indexing model from the issue text.

Description

bug S4

Observed behavior

buildVariables in src/prompt-generators/github.ts (and the matching helper in src/prompt-generators/gitlab.ts) intentionally places body/description last in the returned object, with this comment:

Keep body last so any placeholder-looking text inside the issue body is inserted after replacement of other variables has finished.

The implementation in expandPrompt iterates Object.entries(variables) and runs result.replaceAll('{{key}}', value) for each, so this ordering does protect against an issue body that contains, say, {{title}} (the body is substituted last, after {{title}} is already gone).

The protection only goes one way, though. Earlier variable values whose text contains {{body}} are still re-substituted in the next iteration. Example:

let result = 'Title: {{title}}\nBody: {{body}}';
const variables = {
  title: 'fix {{body}} formatting',   // mentions another placeholder
  body: 'this is the body text',
};
for (const [key, value] of Object.entries(variables)) {
  result = result.replaceAll('{{' + key + '}}', value);
}
// result:
//   Title: fix this is the body text formatting
//   Body: this is the body text

The {{body}} inside the title placeholder text got expanded to the body content because the title substitution happened first and left a {{body}} token in the template, which the later body substitution then replaced.

This contradicts what the docstring tells the reader to expect (body last makes placeholder-looking text safe). It is unlikely to bite in practice for real GitHub issue titles, but it is exactly the failure mode the comment claims to prevent, and the same shape is duplicated in gitlab.ts.

Expected behavior

Either:

  • Variable substitution is a single pass that never re-substitutes the result of a previous substitution (so placeholder-looking text in any variable value is preserved verbatim), and the docstring describes that guarantee; or
  • The docstring is updated to clearly describe the partial protection (body last protects against placeholders inside the body, but not against {{body}} appearing inside other variable values).

A single-pass substitution can be done by scanning for {{...}} tokens in result once and looking each up in the variable map, falling through unknown names unchanged.

Minimal reproduction

See snippet above; reproducible in plain Node.

Suggested fix

Replace the per-key replaceAll loop in src/util/expand-prompt.ts with a single-pass token substitution:

const VARIABLE_PATTERN = /\{\{([a-zA-Z0-9_]+)\}\}/g;
result = result.replace(VARIABLE_PATTERN, (match, name) =>
  Object.hasOwn(variables, name) ? variables[name] : match,
);

This also incidentally fixes the related $-pattern corruption (filed separately) because the function form of replace does not interpret $ patterns.

If the single-pass approach is not desired, at minimum update the Keep \body` last...comment ingithub.tsandgitlab.ts` to describe the actual (one-directional) guarantee.

Dominant language
TypeScript
Stars
2
Forks
1
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from joewalker/loop-the-loop

All issues in joewalker/loop-the-loop

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.