fix(ai): full-sweep audit — placeholders only in system prompts + CI guardrail
All checks were successful
Mirror to GitHub / mirror (push) Successful in 10s
All checks were successful
Mirror to GitHub / mirror (push) Successful in 10s
The "AI parrots example content from system prompt" bug bit us twice in one day across two different prompt sites. Patching individual prompts is treating the symptom; this commit makes the rule structural. Audit + sanitize: - assistant_chat_service.ASSISTANT_SYSTEM_PROMPT — already cleaned in prior commits, but the [FORK] schema still had literal "Brief reason" / "Short name" / "One sentence" placeholders. Replaced with <angle-bracket> placeholders. Anti-parrot rule itself rewritten to describe the failure mode abstractly instead of naming "jsmith" so the rule no longer trips the guardrail (and so the model doesn't see "jsmith" as a token at all). - ai_chat_service.py — removed three concrete-example offenders: "Get-Service ADSync" command literal, the "DC01 server_name" intake form payload (in two places), and the inline interview demos using "Azure AD Sync failures" / "Exchange Online mailbox migration". Replaced with technology-neutral schema descriptions. - ai_tree_generator_service.BRANCH_DETAIL_SYSTEM_PROMPT — replaced the fully-fleshed DNS troubleshooting tree (with literal Dnscache / ipconfig / google.com / Start-Service) with a placeholder schema showing only ID-linkage shape. - kb_conversion_service.PROCEDURAL_SYSTEM_PROMPT — replaced the worked Server Manager + DC01 example payload with a placeholder schema. Guardrail (tests/test_prompt_anti_parrot.py): - Imports every module under app/services/ and app/core/ and walks every uppercase string constant ending in _PROMPT, _SCHEMA, _PROTOCOL, _FORMAT, or _CONTEXT. - test 1: known-leaked-token list (jsmith, DC01, ADSync, Dnscache, google.com, "Outlook keeps", "Teams drops") must not appear in any prompt constant. Add to the list when a new leak shows up in prod — the list IS the audit trail. - test 2: marker blocks ([QUESTIONS], [ACTIONS], [SUGGEST_FIX], etc.) must contain placeholders only. Distinguishes JSON keys (followed by ':', allowed) from JSON values (followed by ',' / ']' / '}', must be <placeholder>); allows pipe-separated enum types (text|password|select) and a small set of fixed enum values (question, diagnostic_check, decision, action, ...). Verified by feeding the test a known-bad block — caught it correctly. Documented the rule in CLAUDE.md → AI / FlowPilot lessons, naming the test as the enforcement point so future contributors know how to extend it (add to the known-leaked list when a new leak surfaces). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -153,48 +153,29 @@ Identify values that would change between executions (server names, IPs, usernam
|
||||
|
||||
## Output Format
|
||||
|
||||
Return a JSON object:
|
||||
Return a JSON object with this SHAPE (DO NOT copy the placeholders below
|
||||
verbatim — fill each field with content derived from the actual KB article
|
||||
the engineer attached, NOT from this schema):
|
||||
```json
|
||||
{
|
||||
"title": "Procedure title derived from the article",
|
||||
"description": "Brief description of what this procedure accomplishes",
|
||||
"title": "<procedure title derived from the article>",
|
||||
"description": "<brief description of what this procedure accomplishes>",
|
||||
"steps": [
|
||||
{
|
||||
"id": "unique-step-id",
|
||||
"type": "step",
|
||||
"content": "Open Server Manager and navigate to Add Roles on [VAR:server_name]",
|
||||
"confidence": 0.95,
|
||||
"source_excerpt": "Step 1: Open Server Manager on DC01..."
|
||||
},
|
||||
{
|
||||
"id": "warning-dns",
|
||||
"type": "warning",
|
||||
"content": "WARNING: This will restart DNS and cause brief connectivity loss",
|
||||
"confidence": 0.90,
|
||||
"source_excerpt": "Note: Restarting DNS will cause a brief outage"
|
||||
},
|
||||
{
|
||||
"id": "section-verification",
|
||||
"type": "section_header",
|
||||
"content": "Verification Steps",
|
||||
"confidence": 1.0,
|
||||
"source_excerpt": "Verification"
|
||||
"id": "<unique-kebab-case-id>",
|
||||
"type": "step|warning|section_header",
|
||||
"content": "<step body — may include [VAR:<your_variable>] interpolation>",
|
||||
"confidence": <float 0.0-1.0>,
|
||||
"source_excerpt": "<the verbatim sentence/phrase from the article that this step came from>"
|
||||
}
|
||||
],
|
||||
"intake_form": [
|
||||
{
|
||||
"variable_name": "server_name",
|
||||
"label": "Server Name",
|
||||
"field_type": "text",
|
||||
"required": true,
|
||||
"display_order": 1
|
||||
},
|
||||
{
|
||||
"variable_name": "ip_address",
|
||||
"label": "IP Address",
|
||||
"field_type": "text",
|
||||
"required": true,
|
||||
"display_order": 2
|
||||
"variable_name": "<snake_case_name fitting THIS procedure>",
|
||||
"label": "<Human Label>",
|
||||
"field_type": "text|password|select|textarea|number|boolean",
|
||||
"required": true|false,
|
||||
"display_order": <integer>
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user