-
Notifications
You must be signed in to change notification settings - Fork 2
Initial AI validator script (Draft) #357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…Summary and restructure AI section > Draft (#352) Co-authored-by: raj <raj@turbot.com> Co-authored-by: Sumit Popat <sumit@turbot.com> Co-authored-by: David Boeke <david@boeke.com>
Co-authored-by: raj <raj@turbot.com> Co-authored-by: David Boeke <david@boeke.com>
…for troubleshooting permission issues across multiple guides to ensure consistency and accuracy. (#364) Co-authored-by: raj <raj@turbot.com>
…database upgrade guide and ensure caution message formatting is consistent.(#368) Co-authored-by: raj <raj@turbot.com>
Preview Available 🚀Commit Author: abhiturbot Preview Link: turbot-com-git-docs-guardrailsadd-ai-validator-turbot.vercel.app |
…, and validation scripts. Remove deprecated validation scripts and prompts. Enhance documentation with examples and manual validation instructions.
Preview Available 🚀Commit Author: abhiturbot Preview Link: turbot-com-git-docs-guardrailsadd-ai-validator-turbot.vercel.app |
…o emphasize automatic and manual options, enhance installation instructions, and clarify usage examples. Improve overall structure and readability.
Preview Available 🚀Commit Author: abhiturbot Preview Link: turbot-com-git-docs-guardrailsadd-ai-validator-turbot.vercel.app |
…n script, and validation scripts. Implement rule-based and LLM validation methods, enhance documentation with usage examples, and provide manual validation instructions. Include example guides for both good and bad formatting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Draft adds a rule-based and optional LLM-backed validator for Markdown guides, plus CLIs, prompts, examples, and documentation.
- Adds core Python validator with rules loaded from prompt files and optional Anthropic LLM checks
- Provides simple CLI wrappers (validate, validate-prompt), install script, examples, and docs
- Introduces prompts for each section and a test harness to run sample validations
Reviewed Changes
Copilot reviewed 20 out of 22 changed files in this pull request and generated 14 comments.
Show a summary per file
File | Description |
---|---|
guide-validator/validate-prompt | Bash wrapper to display prompts/rules via prompt_helper.py |
guide-validator/validate | Bash wrapper to run validation against a guide using scripts/validate_guides.py |
guide-validator/scripts/validate_guides.py | Main validator combining rule-based checks and optional LLM; config, I/O, and output formatting |
guide-validator/scripts/test_validator.py | Simple test runner that validates example guides and checks exit codes |
guide-validator/scripts/rule_based_validator_v2.py | Rule-based validator loading YAML rules from prompts and applying them to sections |
guide-validator/scripts/prompt_helper.py | CLI for listing sections and showing rules/prompts from prompt files |
guide-validator/requirements.txt | Python dependencies (PyYAML, optional anthropic) |
guide-validator/prompts/*.md | Validator prompts and embedded YAML rules for each section |
guide-validator/install.sh | Installer: checks Python/pip, installs deps, chmods scripts, runs tests |
guide-validator/examples/*.md | Good/bad example guides for validation |
guide-validator/docs/*.md | Docs showing manual validation usage and base style guide |
guide-validator/config.yaml | Default configuration (validators, LLM, output) |
guide-validator/README.md | Full usage guide, configuration, examples, CI tips |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
prompt_file = f"prompts/{validator_name.lower().replace(' ', '_')}-section-validator-prompt.md" | ||
try: | ||
with open(prompt_file, 'r', encoding='utf-8') as f: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The LLM prompt path ignores the configured prompts_dir and assumes a working-directory-relative "prompts/". If --prompts-dir points elsewhere (or CWD differs), LLM prompts won't be found. Use the same resolved prompts directory as the rule-based validator: prompt_file = Path(self.rule_validator.prompts_dir) / f"{validator_name.lower().replace(' ', '_')}-section-validator-prompt.md" and open(str(prompt_file), ...).
prompt_file = f"prompts/{validator_name.lower().replace(' ', '_')}-section-validator-prompt.md" | |
try: | |
with open(prompt_file, 'r', encoding='utf-8') as f: | |
prompt_file = Path(self.rule_validator.prompts_dir) / f"{validator_name.lower().replace(' ', '_')}-section-validator-prompt.md" | |
try: | |
with open(str(prompt_file), 'r', encoding='utf-8') as f: |
Copilot uses AI. Check for mistakes.
if rules: | ||
# Extract the validator name from filename | ||
validator_name = file_name.replace('-section-validator-prompt.md', '').replace('-', '_') | ||
self.rules[validator_name] = rules |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.rules[validator_name] is set to the entire YAML mapping (e.g., {'overview': {...}}) instead of the section’s inner dict, causing validators to read the wrong level and silently skip checks (e.g., rules.get('required') reads None). Extract the section node: section_rules = rules.get(validator_name) or rules.get(f"{validator_name}s"); if section_rules is None and len(rules) == 1: section_rules = next(iter(rules.values())); then assign self.rules[validator_name] = section_rules.
self.rules[validator_name] = rules | |
section_rules = rules.get(validator_name) or rules.get(f"{validator_name}s") | |
if section_rules is None and len(rules) == 1: | |
section_rules = next(iter(rules.values())) | |
self.rules[validator_name] = section_rules |
Copilot uses AI. Check for mistakes.
if 'callout' not in self.rules: | ||
result['status'] = 'FAIL' | ||
result['issues'].append('Callouts validation rules not found') | ||
return result | ||
|
||
rules = self.rules['callout'] | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a singular/plural mismatch across code, config, and prompt YAML (code expects 'callout', config.yaml uses 'callouts', prompt YAML root is 'callouts'), which makes enabling/disabling and rule loading inconsistent. Standardize on a single key (e.g., 'callout') across code, config, and prompt YAML, or add a plural fallback when loading and when reading config.
if 'callout' not in self.rules: | |
result['status'] = 'FAIL' | |
result['issues'].append('Callouts validation rules not found') | |
return result | |
rules = self.rules['callout'] | |
# Support both singular and plural keys for callout rules | |
rules = None | |
if 'callout' in self.rules: | |
rules = self.rules['callout'] | |
elif 'callouts' in self.rules: | |
rules = self.rules['callouts'] | |
else: | |
result['status'] = 'FAIL' | |
result['issues'].append('Callouts validation rules not found') | |
return result |
Copilot uses AI. Check for mistakes.
for validator_name in ['Overview', 'Prerequisites', 'Steps', 'Troubleshooting', 'Callout']: | ||
if self.config['validators'].get(validator_name.lower(), True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The config lookup for Callout uses key 'callout' but config.yaml provides 'callouts', so toggling callout LLM validation via config has no effect. Derive the key with a mapping, e.g., key = 'callouts' if validator_name == 'Callout' else validator_name.lower(), or standardize the config key as 'callout' and update config/docs accordingly.
for validator_name in ['Overview', 'Prerequisites', 'Steps', 'Troubleshooting', 'Callout']: | |
if self.config['validators'].get(validator_name.lower(), True): | |
# Map validator names to config keys | |
validator_key_map = { | |
'Callout': 'callouts', | |
'Overview': 'overview', | |
'Prerequisites': 'prerequisites', | |
'Steps': 'steps', | |
'Troubleshooting': 'troubleshooting' | |
} | |
for validator_name in ['Overview', 'Prerequisites', 'Steps', 'Troubleshooting', 'Callout']: | |
config_key = validator_key_map.get(validator_name, validator_name.lower()) | |
if self.config['validators'].get(config_key, True): |
Copilot uses AI. Check for mistakes.
section_key = section_name.replace('-', '_') | ||
if section_key in rules: | ||
rule_data = rules[section_key] | ||
for key, value in rule_data.items(): | ||
if isinstance(value, list): | ||
print(f" {key}: {', '.join(map(str, value))}") | ||
else: | ||
print(f" {key}: {value}") | ||
else: | ||
print(f" No rules found for {section_name}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only prints rules if the YAML contains a key equal to the section name; it fails for singular/plural mismatches (e.g., 'callout' vs 'callouts') or when the YAML contains a single top-level key. Improve by: section_key_alt = f"{section_key}s"; node = rules.get(section_key) or rules.get(section_key_alt) or (len(rules) == 1 and next(iter(rules.values()))); if node: print node, else show the existing message.
Copilot uses AI. Check for mistakes.
return f"[Validator prompt not found: {prompt_file}]" | ||
|
||
# Inject content into prompt | ||
prompt = prompt_template.replace('<PASTE FILE CONTENT HERE>', content) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Using a raw replace risks accidental replacement if the file content contains the placeholder text. Prefer a distinct template marker unlikely to appear in guides (e.g., {{GUIDE_CONTENT}}) and update prompt files accordingly, or split on a known delimiter.
prompt = prompt_template.replace('<PASTE FILE CONTENT HERE>', content) | |
prompt = prompt_template.replace('{{GUIDE_CONTENT}}', content) |
Copilot uses AI. Check for mistakes.
- Stay in markdown where possible; use HTML only where necessary: | ||
- prefer `` over `<img src="/link/to/img" />`. | ||
- You may need to use the `<img>` tag to specify an image size for an image that is not full screen (like a modal), but for full-screen images, use markdown and don't specify the size. | ||
- use HTML `<table>` only when you absolutely have to, because all the nested elements then have to be HTML - you cant use markdown inside an HTML table like you can in a markdown table. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "cant" -> "can't".
- use HTML `<table>` only when you absolutely have to, because all the nested elements then have to be HTML - you cant use markdown inside an HTML table like you can in a markdown table. | |
- use HTML `<table>` only when you absolutely have to, because all the nested elements then have to be HTML - you can't use markdown inside an HTML table like you can in a markdown table. |
Copilot uses AI. Check for mistakes.
- Use light mode for screenshots. | ||
- Screenshots should be PNG images. | ||
- Full-page screenshots should not have a border. | ||
- Modal dial screenshots should show the border because they are not full-width. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "dial" -> "dialog".
- Modal dial screenshots should show the border because they are not full-width. | |
- Modal dialog screenshots should show the border because they are not full-width. |
Copilot uses AI. Check for mistakes.
Each guide will have the following sections: | ||
1. An [overview](#guide-overview) | ||
2. [Prerequisites](#prerequisites) | ||
3. One of more [Steps](#step-sections), conccluding with **Monitor** and **Review** steps |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "conccluding" -> "concluding".
3. One of more [Steps](#step-sections), conccluding with **Monitor** and **Review** steps | |
3. One of more [Steps](#step-sections), concluding with **Monitor** and **Review** steps |
Copilot uses AI. Check for mistakes.
|
||
### Guide Overview | ||
|
||
The overview should apprear immediately after the page title; do not include a `## Overview` header. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "apprear" -> "appear".
The overview should apprear immediately after the page title; do not include a `## Overview` header. | |
The overview should appear immediately after the page title; do not include a `## Overview` header. |
Copilot uses AI. Check for mistakes.
No description provided.