Skill: Log Correction
SkillMonitoring & opsRecord analyst mistakes, fixes, and reusable learnings so future analyses never repeat an error. Fires automatically when the user corrects work ("actually it's Y", "that's wrong") or teaches a rule ("always use X", "never include test users", "remember that our fiscal year starts in February"), and manually on "log a correction", "save this mistake", "record this lesson". Writes the .knowledge store per docs/KNOWLEDGE.md.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Skill: Log Correction skill
What this skill tells your AI
The instructions your AI receives, as published by ai-analyst-lab/ai-analyst in .claude/skills/log-correction/SKILL.md and read by ahel’s review.
Purpose
Record analyst mistakes, their fixes, and reusable learnings so future analyses
learn from past errors. Runs in two modes against the same store (defined in
docs/KNOWLEDGE.md): auto mode detects corrections and learnings in the
user's messages without being asked, and manual mode handles explicit
"log a correction" requests with full detail.
When to Use
- Auto: the user corrects your work ("that's wrong", "actually it's...", "you used the wrong column") or teaches a reusable rule ("always use X", "never do Y", "remember that our fiscal year starts in February") without asking you to log anything
- Manual: user says "log a correction", "save this mistake", "record this lesson", or similar
- After discovering and fixing an error mid-analysis worth preserving
Auto Mode
Watch every user message for these signals. When one fires, capture it immediately; the user never has to ask.
Correction signals (something you produced was wrong):
- "that's wrong", "that's incorrect", "actually it's...", "it should be..."
- "the column is X not Y", "you used the wrong...", "off by...", "double-counted", "that join is wrong", "missing a filter", "forgot to exclude..."
Learning signals (a reusable methodology or fact):
- "always use...", "never use...", "next time...", "prefer X over Y"
- "remember that...", "the convention here is...", "our team uses...", "going forward...", "don't forget to..."
If both match, treat it as a correction. If neither matches, do nothing and say nothing about it.
On a correction signal: run Steps 1-5 below, but never interrogate the user. Infer severity, category, dataset, and tables from context; leave fields you cannot infer as null. Acknowledge in one line ("Got it, logged as CORR-008.") and then immediately continue with the user's underlying request; logging is never the whole response.
On a learning signal: append a bullet to .knowledge/learnings/index.md
under the closest category heading (Data Patterns, Query Techniques, Business
Context, Stakeholder Preferences, Visualization Insights, Methodology Notes),
formatted - {concise learning} (source: user feedback, {YYYY-MM-DD}).
Acknowledge in one line ("Noted for future analyses.") and continue with the
user's request.
Auto-mode rules:
- Silent operation: no execution reports, no "I detected a correction signal", no file-path listings. One brief acknowledgment line, then the analysis.
- Never ask "should I log this?" Classify and log.
- Never block: if a read or write fails, skip capture and answer the user's question as if nothing happened. Do not retry or announce the failure.
- Never fabricate detail; use null for anything not stated by the user.
Manual Mode Instructions
Step 1: Gather Details
Extract from conversation context or ask the user:
- What was wrong? — One-sentence description of the error
- What is the correct answer? — The fix or corrected approach
- Which dataset/tables? — Dataset name and affected table(s)
- How severe? —
critical(wrong numbers shared) |high(changes conclusions) |medium(directionally correct) |low(no impact) - SQL before/after? — If the error involved a query, capture both versions
If any required field is unclear, ask the user. Do not guess severity.
Step 2: Categorize
IMPORTANT: Assign exactly ONE category from the following list. These are the only valid categories — do not create custom categories.
| Category | Description | Examples |
|---|---|---|
sql | Wrong query — bad join, missing filter, incorrect aggregation, wrong GROUP BY, missing WHERE clause | INNER JOIN instead of LEFT JOIN; forgot WHERE clause to filter test users; COUNT(*) instead of COUNT(DISTINCT); aggregation before filtering |
metric | Wrong metric definition — numerator/denominator error, wrong time window, wrong column | Used revenue_usd instead of order_total_usd for GMV; calculated DAU as total events instead of distinct users; wrong date range for YoY comparison |
schema | Wrong column or table reference — stale schema, misnamed field, wrong table | Referenced old_column_name after schema migration; queried staging.users instead of prod.users; assumed column existed but it doesn't |
logic | Flawed reasoning — Simpson's paradox missed, survivorship bias, wrong comparison | Compared current users to all-time users (survivorship bias); aggregated across segments hiding a reversal; compared apples to oranges |
other | Anything that does not fit the above | Data interpretation error, visualization mistake, wrong stakeholder audience |
If the user mentions a category not in this list (e.g., "filter_missing", "metric_definition"), map it to the closest match from the allowed categories above and confirm with the user.
Step 3: Write the Correction
- Read
.knowledge/corrections/index.yaml(treat a missing or corrupt file per Rule 3: recreate from scratch) - Derive next ID: if
last_correction_idis null, useCORR-001; otherwise parse the numeric suffix, increment, and zero-pad to 3 digits - Build the entry in exactly this format:
- id: "CORR-{N}"
date: "{YYYY-MM-DD}"
severity: "{severity}"
category: "{category}"
dataset: "{dataset_name}"
tables: ["{table1}", "{table2}"]
description: "{what was wrong}"
fix: "{what the correct approach is}"
sql_before: "{original query, if applicable, else null}"
sql_after: "{corrected query, if applicable, else null}"
prevented_by: "{which validation layer should have caught this}"
The prevented_by field should reference one of these validation layers:
structural— schema checks, PK validation, null checks, row count validationlogical— aggregation consistency, trend direction, progression rates < 100%business-rules— metric plausibility, known data quality rules, domain constraintsSimpson's check— segment-first analysis to detect reversalssource tie-out— pandas vs DuckDB comparison on foundational metrics
Examples of prevented_by:
- For wrong aggregation:
"logical (progression rates should never exceed 100%)" - For missing filter:
"business-rules (check for test account filtering in conversion metrics)" - For wrong column:
"structural (column validation against schema)"
- Read
.knowledge/corrections/log.yaml(missing or corrupt: recreate per Rule 3) - Append the new entry to the
correctionslist - Write the YAML back (write the full file in one go so a failed write cannot leave a half-written log)
Step 4: Update Index
- Read
.knowledge/corrections/index.yaml(already loaded in Step 3) - Increment
total_corrections - Increment the matching
by_severity.{severity}counter - Increment
by_category.{category}(create the key if it does not exist) - Set
last_correction_idto the new ID - Set
last_updatedto today's date - Write the YAML back (full file in one go)
Step 5: Confirm
Report to the user:
Correction logged: {id}
Severity: {severity} | Category: {category}
Description: {description}
Fix: {fix}
Future analyses will check for this pattern during validation.
Rules
- Never overwrite existing corrections -- always append
- Always read current state before writing (no blind overwrites)
- If
log.yamlorindex.yamlis missing or corrupt, create from scratch with schema_version 1 - SQL snippets in
sql_before/sql_aftershould be trimmed to the relevant clause, not the entire multi-hundred-line query prevented_byshould reference a specific validation layer from the list in Step 3. Be specific about what check should have caught this.- ONLY use the 5 allowed categories (sql, metric, schema, logic, other). If the user suggests a different category, map it to the closest match.
Edge Cases
- No SQL involved: Set
sql_beforeandsql_afterto null - Dataset unknown: Set
datasetto "unknown" and note in description - Duplicate correction: Still log it -- repeated errors signal a systemic gap
- Correction to a correction: Log as a new entry referencing the prior ID in description
- User suggests custom category: Map to closest allowed category and confirm. Example: "filter_missing" →
sqlcategory with description noting the missing filter.
Signals
- GitHub stars
- 297
- Forks
- 137
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
log-correction- Source
- github.com/ai-analyst-lab/ai-analyst