Project
cortex
Description
cortex-commands/src/command.rs substitute_placeholders() uses an ascending for-loop to replace numbered placeholders in the template:
for i in 1..=max_placeholder {
let placeholder = format!('${i}');
result = result.replace(&placeholder, &replacement);
}
Rust's str::replace() is a literal substring replacement. When i=1, it replaces all occurrences of '$1', INCLUDING the prefix '$1' inside '$10', '$11', '$12', ..., '$19'. Similarly, when i=2, it replaces '$2' inside '$20', '$21', etc.
Example: Template 'Run $1 and item $10', args = 'first second':
- i=1: replace '$1' with 'first'
Template becomes: 'Run first and item first0' <- $10 CORRUPTED!
- i=10: replace '$10' in 'Run first and item first0'
No '$10' found — it was already destroyed by i=1 step
Final: 'Run first and item first0' (WRONG: expected 'Run first and item second')
Any command template using $10 or higher loses correct substitution. The last numbered argument also swallows extra args via 'captures rest' logic, but the index corruption happens before that step.
Error Message
Debug Logs
cortex-commands/src/command.rs:200-231 (substitute_placeholders):
pub fn substitute_placeholders(template: &str, arguments: &str) -> String {
let mut result = template.to_string();
result = result.replace('$ARGUMENTS', arguments);
let args: Vec<&str> = parse_arguments(arguments);
let max_placeholder = find_max_placeholder(&result);
for i in 1..=max_placeholder { // BUG: ascending order!
let placeholder = format!('${i}');
let replacement = ...; // arg i or rest
result = result.replace(&placeholder, &replacement); // BUG: corrupts $10+
}
result
}
Rust demonstration:
let s = 'Run $1 and item $10';
let s = s.replace('$1', 'alpha'); // => 'Run alpha and item alpha0'
let s = s.replace('$10', 'kappa'); // No '$10' found! => 'Run alpha and item alpha0'
cortex /multi-batch-cmd alpha beta gamma delta epsilon zeta eta theta iota kappa
Expected: 'Process alpha in batch kappa'
Actual: 'Process alpha in batch alpha0'
error: template placeholder $10 was corrupted to 'alpha0' by $1 substitution
System Information
OS: Ubuntu 22.04 LTS | Version: v0.0.7
Screenshots
https://github.com/petar-vasilev/screenshots/blob/main/452b10bb87b6406cbb1068725ddba48e.png
Steps to Reproduce
- Run:
cortex /custom-cmd arg1 arg2 arg3
- Create custom command template: 'Process $1 in batch $10'
- Run: cortex /custom-cmd alpha beta gamma delta epsilon zeta eta theta iota kappa
- Expected: 'Process alpha in batch kappa'
- Actual: 'Process alpha in batch alpha0' (because $10 became 'alpha' + '0')
- Verified with Rust: 'Process $1 in batch $10'.replace('$1', 'alpha') == 'Process alpha in batch alpha0'
Expected Behavior
substitute_placeholders() should replace placeholders in DESCENDING order
to avoid prefix collisions:
for i in (1..=max_placeholder).rev() { // Descending: $10 before $1
let placeholder = format!('${i}');
result = result.replace(&placeholder, &replacement);
}
With descending order for 'Run $1 and item $10':
i=10: replace '$10' with 'kappa' => 'Run $1 and item kappa'
i=1: replace '$1' with 'alpha' => 'Run alpha and item kappa'
Result: 'Run alpha and item kappa' (CORRECT)
Alternatively, use regex with word-boundary matching to avoid substring collision.
Actual Behavior
cortex-commands/src/command.rs: substitute_placeholders() iterates from i=1 to max_placeholder (ascending). At i=1, result.replace('$1', arg) also replaces the '$1' prefix within '$10', '$11', ..., '$19', converting them into 'arg10', 'arg11', etc. When i=10 is reached, '$10' no longer exists in the string, so the correct value for $10 is never inserted. Templates with 10+ positional placeholders silently produce wrong output.
Additional Context
── Code Evidence ────────────────────────────────────────────────────
This affects all templates using 2+ digit placeholders ($10 through $99).
The pattern of corruption:
- i=1 corrupts $10-$19 (substitutes $1 prefix)
- i=2 corrupts $20-$29 (substitutes $2 prefix)
- ...and so on
For example, with i=2 and arg2='beta':
'$21'.replace('$2', 'beta') = 'beta1' (not $21's intended value)
The find_max_placeholder() regex r'$(\d+)' correctly captures multi-digit
numbers, so max_placeholder may correctly be 10. But the loop order
then causes the corruption.
cortex-commands/src/command.rs:245-256 (find_max_placeholder)
fn find_max_placeholder(template: &str) -> u32 {
re.captures_iter(template) // correctly finds $10
.filter_map(...)
.max()
.unwrap_or(0) // may return 10, 11, etc.
}
Project
cortex
Description
cortex-commands/src/command.rs substitute_placeholders() uses an ascending for-loop to replace numbered placeholders in the template:
for i in 1..=max_placeholder {
let placeholder = format!('${i}');
result = result.replace(&placeholder, &replacement);
}
Rust's str::replace() is a literal substring replacement. When i=1, it replaces all occurrences of '$1', INCLUDING the prefix '$1' inside '$10', '$11', '$12', ..., '$19'. Similarly, when i=2, it replaces '$2' inside '$20', '$21', etc.
Example: Template 'Run $1 and item $10', args = 'first second':
Template becomes: 'Run first and item first0' <- $10 CORRUPTED!
No '$10' found — it was already destroyed by i=1 step
Final: 'Run first and item first0' (WRONG: expected 'Run first and item second')
Any command template using $10 or higher loses correct substitution. The last numbered argument also swallows extra args via 'captures rest' logic, but the index corruption happens before that step.
Error Message
Debug Logs
cortex-commands/src/command.rs:200-231 (substitute_placeholders): pub fn substitute_placeholders(template: &str, arguments: &str) -> String { let mut result = template.to_string(); result = result.replace('$ARGUMENTS', arguments); let args: Vec<&str> = parse_arguments(arguments); let max_placeholder = find_max_placeholder(&result); for i in 1..=max_placeholder { // BUG: ascending order! let placeholder = format!('${i}'); let replacement = ...; // arg i or rest result = result.replace(&placeholder, &replacement); // BUG: corrupts $10+ } result } Rust demonstration: let s = 'Run $1 and item $10'; let s = s.replace('$1', 'alpha'); // => 'Run alpha and item alpha0' let s = s.replace('$10', 'kappa'); // No '$10' found! => 'Run alpha and item alpha0' cortex /multi-batch-cmd alpha beta gamma delta epsilon zeta eta theta iota kappa Expected: 'Process alpha in batch kappa' Actual: 'Process alpha in batch alpha0' error: template placeholder $10 was corrupted to 'alpha0' by $1 substitutionSystem Information
OS: Ubuntu 22.04 LTS | Version: v0.0.7Screenshots
https://github.com/petar-vasilev/screenshots/blob/main/452b10bb87b6406cbb1068725ddba48e.png
Steps to Reproduce
cortex /custom-cmd arg1 arg2 arg3Expected Behavior
substitute_placeholders() should replace placeholders in DESCENDING order
to avoid prefix collisions:
for i in (1..=max_placeholder).rev() { // Descending: $10 before $1
let placeholder = format!('${i}');
result = result.replace(&placeholder, &replacement);
}
With descending order for 'Run $1 and item $10':
i=10: replace '$10' with 'kappa' => 'Run $1 and item kappa'
i=1: replace '$1' with 'alpha' => 'Run alpha and item kappa'
Result: 'Run alpha and item kappa' (CORRECT)
Alternatively, use regex with word-boundary matching to avoid substring collision.
Actual Behavior
cortex-commands/src/command.rs: substitute_placeholders() iterates from i=1 to max_placeholder (ascending). At i=1, result.replace('$1', arg) also replaces the '$1' prefix within '$10', '$11', ..., '$19', converting them into 'arg10', 'arg11', etc. When i=10 is reached, '$10' no longer exists in the string, so the correct value for $10 is never inserted. Templates with 10+ positional placeholders silently produce wrong output.
Additional Context
── Code Evidence ────────────────────────────────────────────────────
This affects all templates using 2+ digit placeholders ($10 through $99).
The pattern of corruption:
- i=1 corrupts $10-$19 (substitutes $1 prefix)
- i=2 corrupts $20-$29 (substitutes $2 prefix)
- ...and so on
For example, with i=2 and arg2='beta':
'$21'.replace('$2', 'beta') = 'beta1' (not $21's intended value)
The find_max_placeholder() regex r'$(\d+)' correctly captures multi-digit
numbers, so max_placeholder may correctly be 10. But the loop order
then causes the corruption.
cortex-commands/src/command.rs:245-256 (find_max_placeholder)
fn find_max_placeholder(template: &str) -> u32 {
re.captures_iter(template) // correctly finds $10
.filter_map(...)
.max()
.unwrap_or(0) // may return 10, 11, etc.
}