Problem
ruleSignature (packages/loopover-engine/src/miner/deny-hook-synthesis.ts, lines 132-139) is the sole identity function resolveEffectiveDenyRules (merging built-in + approved custom rules) and synthesizeDenyRuleProposals (deduping newly-derived proposals against existing rules) use to decide "is this the same rule":
function ruleSignature(rule: DenyRule): string {
return JSON.stringify({ matcher: rule.matcher, pathPattern: rule.pathPattern ?? null, inputIncludesAll: rule.inputIncludesAll ?? null, reason: rule.reason });
}
DenyRule (packages/loopover-engine/src/miner/deny-hooks.ts) has five matching fields: matcher, pathPattern, inputIncludesAll, inputTokenPattern, reason. inputTokenPattern was added specifically because a plain inputIncludesAll substring test false-positives on unrelated longer flags (the file's own comment: -f vs --follow-tags) — it materially changes what a rule matches, but ruleSignature never includes it.
Concretely: a maintainer-approved custom rule that narrows an existing rule with the same matcher/pathPattern/inputIncludesAll/reason but a different (or newly-added) inputTokenPattern would be treated as an exact duplicate of the existing rule by both consumers and silently dropped from the merged set — a real, more specific safety rule loses its distinguishing constraint with no warning. Currently latent (only one built-in rule uses inputTokenPattern today, already distinguished by a unique reason), but it's a genuine gap in the equality logic that the synthesis/approval pipeline is explicitly designed to eventually hit.
Area
packages/loopover-engine/src/miner/deny-hook-synthesis.ts (ruleSignature).
Proposal
Include inputTokenPattern in ruleSignature's computed identity, the same way the other four DenyRule fields are already included (nullish-coalesced the same way pathPattern/inputIncludesAll are).
Deliverables
Resources
packages/loopover-engine/src/miner/deny-hook-synthesis.ts (lines 132-139, the function to fix)
packages/loopover-engine/src/miner/deny-hooks.ts (DenyRule's five fields, and the -f/--follow-tags comment explaining why inputTokenPattern exists)
Boundaries
Identity-function fix only — does not change deny-rule matching semantics themselves, only which rules are considered "the same rule" for merge/dedup purposes.
maintainer-only — this is inside the deny-hook safety-rule matching/merge logic (the mechanism that decides which dangerous CLI commands get blocked), and a subtle behavior change here deserves a security-aware reviewer even though the fix itself is a one-field addition.
Problem
ruleSignature(packages/loopover-engine/src/miner/deny-hook-synthesis.ts, lines 132-139) is the sole identity functionresolveEffectiveDenyRules(merging built-in + approved custom rules) andsynthesizeDenyRuleProposals(deduping newly-derived proposals against existing rules) use to decide "is this the same rule":DenyRule(packages/loopover-engine/src/miner/deny-hooks.ts) has five matching fields:matcher,pathPattern,inputIncludesAll,inputTokenPattern,reason.inputTokenPatternwas added specifically because a plaininputIncludesAllsubstring test false-positives on unrelated longer flags (the file's own comment:-fvs--follow-tags) — it materially changes what a rule matches, butruleSignaturenever includes it.Concretely: a maintainer-approved custom rule that narrows an existing rule with the same matcher/pathPattern/inputIncludesAll/reason but a different (or newly-added)
inputTokenPatternwould be treated as an exact duplicate of the existing rule by both consumers and silently dropped from the merged set — a real, more specific safety rule loses its distinguishing constraint with no warning. Currently latent (only one built-in rule usesinputTokenPatterntoday, already distinguished by a uniquereason), but it's a genuine gap in the equality logic that the synthesis/approval pipeline is explicitly designed to eventually hit.Area
packages/loopover-engine/src/miner/deny-hook-synthesis.ts(ruleSignature).Proposal
Include
inputTokenPatterninruleSignature's computed identity, the same way the other fourDenyRulefields are already included (nullish-coalesced the same waypathPattern/inputIncludesAllare).Deliverables
ruleSignatureincludesrule.inputTokenPattern ?? nullin its identity computation.inputTokenPatternproduce different signatures and are NOT deduped/merged into one.Resources
packages/loopover-engine/src/miner/deny-hook-synthesis.ts(lines 132-139, the function to fix)packages/loopover-engine/src/miner/deny-hooks.ts(DenyRule's five fields, and the-f/--follow-tagscomment explaining whyinputTokenPatternexists)Boundaries
Identity-function fix only — does not change deny-rule matching semantics themselves, only which rules are considered "the same rule" for merge/dedup purposes.
maintainer-only — this is inside the deny-hook safety-rule matching/merge logic (the mechanism that decides which dangerous CLI commands get blocked), and a subtle behavior change here deserves a security-aware reviewer even though the fix itself is a one-field addition.