prompt: matched-close check + drop dead-code guard (argus #527 nits)

This commit is contained in:
damocles 2026-05-27 23:40:13 +02:00 committed by Mara
commit 800d9925a5

View file

@ -52,7 +52,11 @@ pub fn render(flavor: Flavor, label: &str, operator_pronouns: &str) -> String {
/// Walk `template` line-by-line. Inside a `<!-- role:X -->` block,
/// suppress all lines unless `X == target`. Marker lines themselves are
/// always elided from the output. Unbalanced openers (no matching
/// closer) hold the suppression state until end-of-file.
/// closer) hold the suppression state until end-of-file. A mismatched
/// closer (`<!-- /role:manager -->` inside a `role:agent` block) is
/// elided from the output but does NOT reset the active role — keeps
/// the suppression conservative so a typo can't dump wrong-flavor
/// content (per argus #527 review nit).
fn filter_role_blocks(template: &str, target: &str) -> String {
let mut out = String::with_capacity(template.len());
// None = outside any block; Some(role) = inside role-tagged block.
@ -63,8 +67,12 @@ fn filter_role_blocks(template: &str, target: &str) -> String {
active_role = Some(role);
continue;
}
if parse_close_marker(trimmed).is_some() {
active_role = None;
if let Some(close_role) = parse_close_marker(trimmed) {
if active_role == Some(close_role) {
active_role = None;
}
// Mismatched close: elide the marker line but keep the
// active role intact so wrong-flavor content stays gated.
continue;
}
let include = match active_role {
@ -82,15 +90,12 @@ fn filter_role_blocks(template: &str, target: &str) -> String {
/// `<!-- role:agent -->` → `Some("agent")`. Anything else returns
/// None. Whitespace inside the marker is tolerated so a future
/// author's `<!--role:foo-->` (no spaces) still parses; the dashboard
/// markdown renderer is equally lenient.
/// markdown renderer is equally lenient. Close tags (`/role:...`)
/// can't accidentally match — the `strip_prefix("role:")` rejects
/// the leading slash before we'd ever see it.
fn parse_open_marker(line: &str) -> Option<&str> {
let inside = line.strip_prefix("<!--")?.strip_suffix("-->")?.trim();
let role = inside.strip_prefix("role:")?.trim();
// Reject closer-looking content ("/role:..." would start with "/")
// so `/role:agent` doesn't accidentally match here.
if role.starts_with('/') {
return None;
}
Some(role)
}
@ -182,6 +187,36 @@ shared closer
assert_eq!(parse_close_marker("just text"), None);
}
#[test]
fn mismatched_close_keeps_active_role() {
// `<!-- role:agent -->` block with a stray `<!-- /role:manager -->`
// closer inside: the manager-tagged close must NOT pop the agent
// gate, else manager-target output would leak the agent block's
// text (or vice-versa). Stray marker line itself is still elided.
// Per argus #527 review nit.
let template = "shared\n\
<!-- role:agent -->\n\
agent line 1\n\
<!-- /role:manager -->\n\
agent line 2\n\
<!-- /role:agent -->\n\
shared end\n";
let manager = filter_role_blocks(template, "manager");
// Both agent lines stay gated out for the manager target; the
// stray close didn't accidentally pop the role. Stray marker
// itself elided from the output.
assert!(!manager.contains("agent line 1"));
assert!(!manager.contains("agent line 2"));
assert!(!manager.contains("<!--"));
assert!(manager.contains("shared"));
assert!(manager.contains("shared end"));
// Agent target still sees both lines (matched closer pops at the end).
let agent = filter_role_blocks(template, "agent");
assert!(agent.contains("agent line 1"));
assert!(agent.contains("agent line 2"));
assert!(agent.contains("shared end"));
}
#[test]
fn unbalanced_opener_suppresses_until_eof() {
// Stray opener with no closer — content stays suppressed for