fix(prompts): make template token substitution order-independent
RenderTemplate replaced tokens one key at a time over a StringBuilder, so a token appearing inside an already-substituted value got substituted again on a later pass. The prompt briefs only escaped this because their callers happen to pass "tasks" last -- reordering the dictionary or adding a fourth token would have started rewriting user-authored task descriptions, which after the enhance phase carry file paths and config snippets. Single-pass regex over the template instead; unknown tokens still pass through.
This commit is contained in:
@@ -22,6 +22,42 @@ public class PromptFilesTests
|
||||
Assert.Equal("## {Wochentag}, {dd.MM.yyyy} — 01.06.2026", outp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderTemplate_does_not_substitute_tokens_that_appear_inside_a_value()
|
||||
{
|
||||
// A sharpened task description can legitimately contain "{repo}" (a config snippet, a
|
||||
// path placeholder). Substitution must be a single pass over the TEMPLATE, so injected
|
||||
// values are never rescanned.
|
||||
var outp = PromptFiles.RenderTemplate(
|
||||
"Repo: {repo}\n\n{tasks}",
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
["repo"] = "C:\\real\\repo",
|
||||
["tasks"] = "- Fix the {repo} placeholder in the config template",
|
||||
});
|
||||
|
||||
Assert.Equal("Repo: C:\\real\\repo\n\n- Fix the {repo} placeholder in the config template", outp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderTemplate_result_is_independent_of_dictionary_order()
|
||||
{
|
||||
const string template = "Scope: {scope}\nRepo: {repo}\n\n{tasks}";
|
||||
var task = "- Document {scope} and {repo} tokens";
|
||||
|
||||
var tasksLast = PromptFiles.RenderTemplate(template, new Dictionary<string, string>
|
||||
{
|
||||
["scope"] = "List: Bugs", ["repo"] = "C:\\repo", ["tasks"] = task,
|
||||
});
|
||||
var tasksFirst = PromptFiles.RenderTemplate(template, new Dictionary<string, string>
|
||||
{
|
||||
["tasks"] = task, ["repo"] = "C:\\repo", ["scope"] = "List: Bugs",
|
||||
});
|
||||
|
||||
Assert.Equal(tasksLast, tasksFirst);
|
||||
Assert.Contains("- Document {scope} and {repo} tokens", tasksLast);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DefaultFor_system_mentions_blocked_marker_and_scope()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user