Context
Follow-up to #1402, which made multi-line quoted arguments a termination condition for shell approval pattern extraction. That fix keys on the symptom (an embedded line break) rather than the underlying category (quoted free-text content is call-specific), so the single-line variant of the same bug remains.
Problem
A single-line quoted message body flows verbatim into the stored pattern — neither existing termination rule fires:
freshdesk ticket reply --message "Single line body"
Current stored pattern:
freshdesk ticket reply --message Single line body
Every unique body becomes a new pattern — the same bloat class as #1402, minus the newline. Approve-once retry keys are overly specific, and the prompt's pattern line carries call-specific content.
Note: the digit rule masks this for many real invocations (freshdesk ticket reply 605 --message "..." terminates at 605), so the bug only manifests when no digit-bearing token precedes the quoted arg.
Possible approach
ShellSyntaxTree.Arg.Raw preserves outer quotes (the SummarizeMultilineArg helper added in #1402 already sniffs them), so quoted args are structurally detectable without package changes. Two candidate predicates, from narrower to broader:
- Whitespace-containing arg — an unquoted arg cannot contain whitespace, so
Raw containing a space proves it was quoted free text. Catches "Single line body" but not "fix".
- Any quote-leading arg — catches single-word quoted values too (
git commit -m "fix"), but quoted and unquoted variants of the same command would then normalize differently (git commit -m fix keeps the operand, git commit -m "fix" drops it).
Why this needs design discussion (deferred from #1402)
This is a behavior change with grant-semantics implications, not a pure bug fix:
git commit -m "fix the bug" would normalize to git commit -m — pattern-store consumers and any tests pinning current normalization need review.
- Quoted globs and patterns are arguably invocation intent, not free text:
find . -name "*.cs", grep "foo bar" file. Dropping them may be fine (they are call-specific) but should be a deliberate choice.
- The spec's "Shell command pattern matching" requirement (
openspec/specs/tool-approval-gates/spec.md) currently defines call-specific classification as "one morphological rule" (digit-bearing); adding a quoted-content rule should be reconciled with that framing rather than bolted on.
Affected code
src/Netclaw.Security/IToolApprovalMatcher.cs — ReconstructClauseText(), IsCallSpecificValueToken()
openspec/specs/tool-approval-gates/spec.md — "Shell command pattern matching" requirement
Context
Follow-up to #1402, which made multi-line quoted arguments a termination condition for shell approval pattern extraction. That fix keys on the symptom (an embedded line break) rather than the underlying category (quoted free-text content is call-specific), so the single-line variant of the same bug remains.
Problem
A single-line quoted message body flows verbatim into the stored pattern — neither existing termination rule fires:
IsCallSpecificValueTokenrequires a digit-bearing tokenfreshdesk ticket reply --message "Single line body"Current stored pattern:
Every unique body becomes a new pattern — the same bloat class as #1402, minus the newline. Approve-once retry keys are overly specific, and the prompt's pattern line carries call-specific content.
Note: the digit rule masks this for many real invocations (
freshdesk ticket reply 605 --message "..."terminates at605), so the bug only manifests when no digit-bearing token precedes the quoted arg.Possible approach
ShellSyntaxTree.Arg.Rawpreserves outer quotes (theSummarizeMultilineArghelper added in #1402 already sniffs them), so quoted args are structurally detectable without package changes. Two candidate predicates, from narrower to broader:Rawcontaining a space proves it was quoted free text. Catches"Single line body"but not"fix".git commit -m "fix"), but quoted and unquoted variants of the same command would then normalize differently (git commit -m fixkeeps the operand,git commit -m "fix"drops it).Why this needs design discussion (deferred from #1402)
This is a behavior change with grant-semantics implications, not a pure bug fix:
git commit -m "fix the bug"would normalize togit commit -m— pattern-store consumers and any tests pinning current normalization need review.find . -name "*.cs",grep "foo bar" file. Dropping them may be fine (they are call-specific) but should be a deliberate choice.openspec/specs/tool-approval-gates/spec.md) currently defines call-specific classification as "one morphological rule" (digit-bearing); adding a quoted-content rule should be reconciled with that framing rather than bolted on.Affected code
src/Netclaw.Security/IToolApprovalMatcher.cs—ReconstructClauseText(),IsCallSpecificValueToken()openspec/specs/tool-approval-gates/spec.md— "Shell command pattern matching" requirement