| name | troubleshoot-report |
| description | Use when triaging a support email, ticket, or bug report about a Symplectic Elements SSRS custom report — wrong data, missing rows, parameter errors, formatting issues, or any RDL/SQL diagnosis. Triggered by pasted ticket text or a ClientMoniker/ReportName argument. |
| allowed-tools | Read, Glob, Grep, Bash, Write, WebFetch |
| argument-hint | ["ClientMoniker/ReportName"] |
Troubleshoot Report - SSRS Report Issue Diagnosis
You are helping a technical engineer diagnose and troubleshoot issues with SSRS custom reports for Symplectic Elements v6.10.0. Your job is to read the issue description, find the report, analyze the code, and present a diagnosis pointing to the exact location to fix.
When to use
Use this skill when triaging a Symplectic Elements SSRS custom report issue — a support email, a ticket, a bug report, or a "why is this report doing X?" question. Typical symptoms: wrong data, missing rows, parameter errors, formatting glitches, sub-report failures, environment mismatches, or any RDL/SQL diagnosis you'd otherwise do by hand. The skill diagnoses only — it does not edit the report.
Skip this skill if the issue is a pure Elements UI / admin question with no RDL or SQL involved.
Setup: Locate the CustomReports folder
The CustomReports folder path varies per user. To find it:
-
First check if .custom_reports_path exists next to this SKILL.md (i.e. inside .claude/skills/troubleshoot-report/):
Read: .claude/skills/troubleshoot-report/.custom_reports_path
If it exists, use its content as the path. (The path is resolved relative to wherever the user is running Claude Code from; if the read fails because cwd differs, fall back to step 2.)
-
If the file does not exist or cannot be read, ask the user:
"Where is your CustomReports folder? (e.g. C:\source\elements-client-services\CustomReports)"
Save their answer to .custom_reports_path next to this SKILL.md so they are not asked again:
Write: {REPORTS_DIR}/.claude/skills/troubleshoot-report/.custom_reports_path
Use this path as {REPORTS_DIR} in all steps below.
Phase 0: Input handling
If $ARGUMENTS matches a ClientMoniker/ReportName pattern (e.g. UoM/PublicationReport):
- Split into client moniker and report name.
- Skip to Phase 2 to locate the report file directly.
- Then prompt for the issue description:
"Paste the support email or issue description for {ReportName} ({ClientMoniker}) below:"
If $ARGUMENTS is other text (e.g. a description or report name only):
- Treat it as part of the issue context and proceed to Phase 1.
If no $ARGUMENTS:
- Prompt:
"Paste the support email or issue description below:"
Phase 1: Understand the issue
Parse the pasted content to extract key information:
- Report identification: Look for report names (often ending in
.rdl or .sql), client monikers, or references to specific report titles.
- Problem description: What is the user reporting as wrong? (wrong data, missing data, error, wrong format, etc.)
- Expected vs actual: What should the report show vs what it actually shows?
- Error messages: Any specific error text, SQL errors, or SSRS rendering errors.
- Data specifics: Particular users, groups, dates, or parameters mentioned.
Summarize your understanding back to the user:
"Here's what I understand from the ticket:
- Issue: {problem description}
- Report: {report name, if found}
- Client: {client moniker, if found}
- Expected behavior: {what should happen}
- Actual behavior: {what is happening}
Is this correct?"
If the report name or client cannot be identified from the content, ask:
"I couldn't identify the report name or client from the description. What's the client moniker and report name?"
Error message lookup: If the issue description contains a specific error message (SSRS rendering error, SQL error, Elements UI error), search the KB immediately:
python "{REPORTS_DIR}/.claude/skills/troubleshoot-report/scripts/kb_api.py" "{error text — first 4–6 words}"
If results are returned and any snippet mentions the error or a known issue, surface it before proceeding:
"The KB has a potentially relevant article: {title} (article_id: {id}) — {one-line snippet summary}. This may explain the error."
- Empty result (no matching articles): continue silently — that's normal.
- Errored call (script crashed, network failure, missing package, non-zero exit): do NOT continue silently. Add the failed call to the Phase 5
### Lookups That Failed section and proceed, noting what evidence is consequently missing.
Phase 2: Find the report
-
Search for the report file:
- Primary:
Glob for {REPORTS_DIR}/**/{ReportName}*.rdl and {REPORTS_DIR}/**/{ReportName}*.sql
- If multiple matches, list them and ask the user to pick one.
- Fallback:
Grep across _Docs.md files in {REPORTS_DIR} for keywords from the issue description.
-
If no match found, prompt:
"I couldn't find the report in the repository. What's the client moniker and report name?"
-
Disambiguate when the ticket uses a display name. If the ticket references the report by a human-readable display name (e.g. "TFOM CV", "Action Report", "Faculty Compliance") rather than a .rdl filename, and your Glob/Grep returns more than one plausible candidate (e.g. CPA.rdl AND CPA_main_report.rdl AND CPA_subreport.rdl), do NOT silently pick one. List every plausible match and ask:
"The ticket references '{display name}' but multiple files could match: \n - {file1}\n - {file2}\n - {file3}\nWhich one is the engineer running?"
This applies even if one file looks like an obvious "main" candidate — a _main_report, _with_Annotations, or PROD/-vs-TEST/ variant can change the diagnosis. Wait for the engineer's pick before reading any RDL.
-
Comparative tickets (two or more reports compared to each other): locate ALL referenced reports in this phase. If any of them is ambiguous per step 3, disambiguate each independently before proceeding.
-
Confirm with the user:
"Found {ReportName}.rdl in {ClientMoniker}. Is this the right report?"
Phase 3: Load context
Run all independent lookups in a single parallel batch. Steps 1–6 below have no dependencies on each other — issue every tool call as one message containing multiple tool uses in parallel. Do not run them serially. Step 7 (target dataset identification) depends on step 5 and runs after the batch returns.
Calls to fire in the parallel batch (one message, many tool calls):
- Read
.claude/skills/troubleshoot-report/DIAGNOSIS_LOG.md (step 1)
- Read every default reference file directly by name — do not
ls first. The current default files are: context.md, report-types.md, sql-patterns.md, elements-product-overview.md, and Symplectic Elements v6.10.0 - Reporting Database Guide (4).md. The following additional .md references exist in the folder but are on-demand only — read whichever is relevant to the ticket symptom, not all by default: Designing and deploying SSRS formatted reports.md (deployment/config tickets), How is the Reporting Database kept up to date_.md (sync/freshness tickets), Report performance.md (slowness tickets), Stock Dashboard, Formatted Reports, and Data Extracts Available in the Reporting Hub.md (stock-report background), Which Elements report type should I create_.md (report-type advice), ref-manager-publications-report.md (REF Manager tickets), co-author-affiliation-bridge.md (per-author affiliation tickets). Skip all .csv and .pdf files in the default batch. Do not Read schema.csv, schema v7.3.csv, display_names.csv, or stored_procedures.csv — they are too large and will error or burn tokens. Query them with Grep on demand instead (e.g. Grep "^Group User Membership," schema.csv). (step 3)
- Read the report file located in Phase 2 (step 5) — RDL files are often very large. If you suspect the file exceeds the Read token cap, skip the full read in the parallel batch and use
Grep for <DataSet Name=, <CommandText>, <ReportParameter, <DataSourceReference in the post-processing step instead, then Read only the relevant line ranges.
- Read
{ReportName}_Docs.md if you know it exists in the same folder; otherwise omit (step 6)
- Bash
python "{REPORTS_DIR}/.claude/skills/troubleshoot-report/scripts/kb_api.py" "{2–4 word symptom query}" — only if Phase 1 yielded a useful query (step 2)
- Bash the two SQLite queries against
reports_knowledge.db (step 4) — issue them as two separate Bash calls so they run in parallel. If you already know the DB is missing from a prior turn, omit; otherwise include — a missing file just errors cheaply.
After the batch returns, do post-processing sequentially: announce any past-issue / cross-client matches from step 4, fetch KB attachments if step 2 surfaced a highly relevant article, then identify the target dataset (step 7).
The numbered detail below is reference material for what each call does and how to interpret results — not a serial execution order.
-
Read the past-mistakes log for this skill:
Read: .claude/skills/troubleshoot-report/DIAGNOSIS_LOG.md
Scan every entry. Before forming your hypothesis in Phase 4, mentally check whether the current issue matches any "What I got wrong" pattern. If a matching lesson exists, call it out explicitly in the diagnosis under Lessons Applied.
-
Search the Symplectic support knowledge base for relevant articles:
Build a 2–4 word plain-language query from the issue — focus on the symptom, not internal table or report names. Then run:
python "{REPORTS_DIR}/.claude/skills/troubleshoot-report/scripts/kb_api.py" "{keywords}"
Each result has a title, snippet, article_id, and category_id. If results are returned, scan the snippets for anything relevant to the reported issue and note them under KB Articles in your diagnosis.
- Empty result (the script returned
[] or no relevant articles): skip silently.
- Errored call (missing
algoliasearch package, non-zero exit, exception, network timeout): do NOT skip silently. Add the failed call + the exact error to the Phase 5 ### Lookups That Failed section so the engineer knows the KB coverage is incomplete.
When to expect useful results: The KB contains Symplectic product documentation — feature guides, OA policy, REF, group setup, release notes. It is most useful for understanding how the product is designed to work (e.g. "how does OA compliance work?", "what does the group hierarchy look like?"). It will rarely return useful results for SQL-level bugs (wrong JOINs, parameter issues, date filters) — use the internal reference files and SQLite KB for those.
Reading PDF attachments: Some KB articles have PDF attachments with deeper documentation. If a returned article looks highly relevant (especially for complex features like Assessment, REF, OA Monitor), check for attachments:
python "{REPORTS_DIR}/.claude/skills/troubleshoot-report/scripts/kb_api.py" --attachments {article_id}
If PDF URLs are returned, fetch and read each one:
WebFetch: {pdf_url} — "Extract all text content"
Read: {path from WebFetch result}
Use the PDF content to deepen your understanding of the feature before diagnosing.
Other kb_api.py flags (rarely needed):
python "{REPORTS_DIR}/.claude/skills/troubleshoot-report/scripts/kb_api.py" --article {article_id}
python "{REPORTS_DIR}/.claude/skills/troubleshoot-report/scripts/kb_api.py" --raw {article_id}
Example queries:
"open access compliance" — for OA/compliance issues
"report missing data" — for missing rows or wrong counts
"group membership hierarchy" — for group-scoping problems
"date filter range" — for date filtering issues
-
Read the reference files named in the parallel-batch instruction above — do not ls the folder. The default .md references (context.md, report-types.md, sql-patterns.md, elements-product-overview.md, and Symplectic Elements v6.10.0 - Reporting Database Guide (4).md) carry curated business and database concepts and should be read directly. The remaining .md references in the folder are on-demand only (see the parallel-batch instruction for which topic each covers) — read them only when the ticket symptom matches.
Use these to interpret table names, field names, and business concepts correctly when diagnosing the issue.
Grep-on-demand only (do NOT Read these — they are too large and will error or burn tokens): schema.csv, schema v7.3.csv, display_names.csv, stored_procedures.csv. Query them by name when needed, e.g. grep "^Publication," ".claude/skills/troubleshoot-report/references/schema.csv".
stored_procedures.csv — load on demand only. During Phase 4, if you encounter a stored procedure or function call in the report (e.g. EXEC SymplecticReports.SomeProcedure or SymplecticReports.fy_SomeFunction(...)), look it up by name:
grep -i "ObjectName" ".claude/skills/troubleshoot-report/references/stored_procedures.csv"
Only fetch the definition when you need to understand what it does. Do not load the whole file.
-
Query the knowledge DB for past issues.
Ensure the DB and diagnoses table exist before querying (idempotent — safe on a fresh checkout):
sqlite3 "{REPORTS_DIR}/.claude/skills/troubleshoot-report/reports_knowledge.db" "CREATE TABLE IF NOT EXISTS diagnoses (id INTEGER PRIMARY KEY AUTOINCREMENT, ticket_number TEXT, client TEXT NOT NULL, report_name TEXT NOT NULL, issue_description TEXT, root_cause TEXT, fix_description TEXT, issue_category TEXT, effort_level TEXT, pattern_tag TEXT, chargeable TEXT, created_date TEXT NOT NULL, modified_date TEXT NOT NULL);"
Then run both queries:
sqlite3 "{REPORTS_DIR}/.claude/skills/troubleshoot-report/reports_knowledge.db" \
"SELECT issue_category, root_cause, fix_description, ticket_number, created_date
FROM diagnoses
WHERE client = '{ClientMoniker}' AND report_name = '{ReportName}'
ORDER BY created_date DESC LIMIT 5;"
sqlite3 "{REPORTS_DIR}/.claude/skills/troubleshoot-report/reports_knowledge.db" \
"SELECT client, report_name, root_cause, ticket_number, created_date
FROM diagnoses
WHERE pattern_tag IS NOT NULL
AND pattern_tag IN (
SELECT DISTINCT pattern_tag FROM diagnoses WHERE client = '{ClientMoniker}'
)
AND client != '{ClientMoniker}'
ORDER BY created_date DESC LIMIT 10;"
If Query 1 returns rows, announce before diagnosing:
"This report has {N} past issue(s) in the knowledge base ({issue_category list}). I'll check those areas first."
If Query 2 returns rows, announce:
"Cross-client pattern match: '{pattern_tag}' was also seen in {client}/{report_name} on {date}."
- No rows returned: skip silently — normal on a fresh checkout or for an unfamiliar report.
- Query errors (DB locked, permissions, syntax): do NOT skip silently. Add to the Phase 5
### Lookups That Failed section so the engineer knows past-issue history may have been missed.
-
Read the report file (.rdl or .sql).
For .rdl files: Extract the essential content - find these XML elements:
<CommandText> tags - the SQL queries
<ReportParameter> tags - parameter definitions (name, type, prompt, default)
<ConnectString> or <DataSourceReference> - the data source
<SharedDataSetReference> - if used instead of inline SQL
Ignore all layout, formatting, embedded images, and page settings.
For .sql files: Read the entire SQL file as-is.
-
If {ReportName}_Docs.md exists in the same folder, read it for a quick summary of the report's purpose.
-
Identify the target dataset before diagnosing.
For .rdl files with multiple datasets, do not assume which dataset handles the reported record type. After reading the file:
a. List every <DataSet Name=...> found in the RDL.
b. If the issue mentions a specific object or record type (e.g. "Sponsored Research Agreement", "conference paper", "grant application") whose category is not explicitly stated:
- Search the
<CommandText> blocks for table names ([Grant Record], [Publication], [Professional Activity], etc.) and type identifier strings to determine which dataset queries that category.
- If ambiguous across two or more datasets, state the ambiguity explicitly and ask:
"I can see this record type could be handled by dataset X or dataset Y. Which category does this object belong to in Elements — Grant, Publication, Professional Activity, or something else?"
c. Once the target dataset is confirmed (either from the code or from the engineer), state it explicitly before proceeding:
"The relevant dataset is {DataSetName}. Proceeding to diagnose that dataset."
Only diagnose the confirmed dataset in Phase 4. Do not analyse all datasets.
Database queries — mandatory rule
Before writing any SQL query for the engineer to run, always verify the table's columns in schema.csv first:
grep "^TableName," ".claude/skills/troubleshoot-report/references/schema.csv"
Never assume a column exists. If you cannot confirm a column in schema.csv, say so and ask the engineer to verify before providing the query.
Phase 4: Diagnose
Cross-reference the issue description against the report code and CONTEXT.md. For each of the 9 categories below, output a verdict block before writing any diagnosis. Do not skip categories.
Output format — one block per category, in order:
- Category: <name>
- Verdict: RULED OUT | POSSIBLE | LIKELY
- Evidence: <specific file + line number or XML element, or "N/A — not applicable because...">
- Confidence: LOW | MED | HIGH
Only after all 9 verdict blocks are written, proceed to Phase 5.
Category 1: Wrong data returned
Check for:
- Missing or incorrect JOINs (e.g. joining on wrong ID column)
- Wrong WHERE filters (e.g. filtering on
= 'Public' when != 'Private' was intended)
- Privacy level not applied correctly (must check BOTH object privacy AND relationship privacy)
- Selecting from wrong table (e.g.
[Publication] vs [Publication Record])
Category 2: Missing data
Check for:
- Parameters not applied in the WHERE clause
- Date filtering not using
fy_REPORT_CheckDateInRange or using it incorrectly
- Group membership join missing sub-groups (should use
[Group User Membership] without filtering Is Explicit)
- Type filter excluding relevant object types
Category 3: Wrong environment
Check for:
- Data source pointing to test instead of prod (or vice versa)
- Inspect
<DataSourceReference> for /elements-{client}-prod/ vs /elements-{client}-test/
Category 4: Group hierarchy issues
Check for:
- Not traversing sub-groups via
[Group User Membership]
- Incorrect
Is Primary / Is Explicit filtering
- Missing
Level 2 Group ID / Level 3 Group ID references
Category 5: Privacy violations
Check for:
- Restricted HR fields (
generic-10 through generic-49) exposed in report output
- Object or relationship privacy not checked
Category 6: Parameter issues
Check for:
- Wrong parameter type (e.g. string instead of int for
User_ID or Group_ID)
- Missing required parameters (
User_ID for user reports, Group_ID for group reports)
- Nullable vs non-nullable mismatch on
Date_1 / Date_2
- Default values interfering with expected behavior
Category 7: Date filtering issues
Check for:
fy_REPORT_CheckDateInRange not called at all
- Wrong arguments passed (not summing
Uses Reporting Date 1 + Uses Reporting Date 2)
- Not joining on
[{Category} Type] to get the Uses Reporting Date flags
Reporting Date 1 / Reporting Date 2 not being used from the correct table
Category 8: Subreport issues
Check for:
- Subreport file missing or misnamed
- Parameters not passed correctly from parent report
- Subreport referencing wrong data source
Category 9: Layout / Formatting
Check for:
<MarkupType>HTML</MarkupType> on a textbox displaying a plain-text field that contains literal \n / \r\n (HTML mode collapses whitespace; newlines disappear)
- Plain-text rendering applied to a field that actually contains HTML markup (tags render as visible text)
- Different
<MarkupType> setting on the same source field between two related reports (one renders correctly, the other doesn't)
<Style> / <Font> / <TextDecoration> divergence between two reports rendering the same field
- Tablix cell missing the textbox / placeholder configuration the sibling report uses
- Code function (e.g.
Code.FormatText, Code.FormatProfessionalActivity) used in one report but not the other for the same field
- Field projected raw in SQL when a sibling report uses a
-html plaintext / REPLACE(...CHAR(10)...,'<br/>') variant
After all 9 verdict blocks: review which categories are LIKELY or POSSIBLE, then proceed to Phase 5 to write the final diagnosis. The diagnosis should address LIKELY categories first, then note POSSIBLE ones as secondary candidates if the primary fix doesn't resolve the issue.
Phase 5: Present diagnosis
Output the diagnosis in this format:
## Diagnosis: {ReportName} — {Client}
### Problem Summary
{1-2 sentences explaining the issue in plain English, using CONTEXT.md to translate table/field names into business terms}
### Root Cause
{What in the SQL/RDL is causing the reported behavior. Reference specific queries, parameters, or XML elements. Quote the relevant SQL snippet if it helps clarify.}
### Where to Fix
- **File:** {full path to the .rdl or .sql file}
- **Location:** {For .rdl: dataset name and which <CommandText>. For .sql: line number or section description}
- **What to change:** {Specific description of the modification needed. Do NOT write the fix — describe what needs to change and where.}
### KB Articles
{If any Symplectic support articles were returned in Phase 3 step 2 and are relevant, list them here as: "- {title} (article_id: {id})". Omit this section if no relevant articles were found.}
### Lookups That Failed
{If any Phase 3 batch call errored (crashed, timed out, returned a non-zero exit, threw an exception), list each here as: "- {what was called} — {exact error or short summary} — missing evidence: {what we would otherwise know}". This is distinct from empty results, which are normal and not surfaced here. Omit this section entirely if no calls errored. NEVER omit it just because the diagnosis is otherwise complete — the engineer needs to know which evidence is missing before accepting the diagnosis.}
### Additional Notes
{Any of: caveats about the fix, related reports in the same client folder that might have the same issue, testing suggestions (e.g. "test with User_ID = X and Date_1 = Y"), or warnings about side effects.}
Important: The skill does NOT auto-edit the report file. It diagnoses and points to the fix location. The engineer decides whether and how to apply the fix.
After presenting the diagnosis, ask:
"Is this diagnosis correct? (yes / no / partially)"
Only proceed to log the knowledge DB once the engineer confirms the diagnosis is correct or corrects it. If they say partially or no, ask what was wrong and revise before logging.
The KB insert is mandatory on every confirmed session. Do not skip it. This includes:
- Bug diagnoses (the default case)
- Chargeable change requests (use
issue_category = 'other' and capture a pattern_tag so cross-client matching still works — e.g. add-supporting-info-columns, add-author-affiliation-column)
- Sessions where the answer was "no bug, working as designed" (record the investigation; future engineers benefit from knowing this report was already triaged)
- Sessions that produced only a reference doc or knowledge note
The chargeable column exists precisely to distinguish defects from change requests — that is the mechanism. Do not invent exceptions like "this wasn't a defect, so I'll skip the insert." If you find yourself reasoning toward skipping, you are wrong; log the row.
Once confirmed, collect metadata and write to the knowledge DB:
-
Ask:
"What's the ticket number for this issue? (press Enter to skip)"
-
Ask:
"How hard was this fix? low / medium / high"
-
Ask:
"Is this work chargeable? yes / no"
-
Based on the root cause of the diagnosis, assign the best-fit issue_category from this controlled vocabulary:
date_filtering — wrong or missing date range logic / fy_REPORT_CheckDateInRange
group_hierarchy — sub-group traversal, Is Explicit, level IDs
wrong_join — missing or incorrect JOIN, wrong ID column
privacy — object or relationship privacy not applied
parameter — wrong type, missing param, nullable mismatch
subreport — missing file, wrong params passed, wrong data source
wrong_env — data source pointing to test vs prod
wrong_table — querying wrong table
missing_data — data exists but not returned, filter too restrictive
formatting — layout, <MarkupType>, HTML vs plain-text rendering, sibling-report divergence in textbox/style
other — does not fit above
-
If the root cause resembles a recurring cross-client pattern, propose a kebab-case pattern_tag slug. Ask:
"Does this look like a pattern that could recur in other clients? Proposed tag: '{slug}' — confirm, change, or press Enter to leave blank."
-
Insert the row using a parameterised Python invocation — this is mandatory and safer than shelling out to sqlite3 with string-substituted SQL. The issue description and root cause routinely contain apostrophes; parameterisation avoids quote-escaping bugs and SQL injection entirely.
Replace the placeholder Python literals below with the actual values collected above. Use the Python None (not the string "None") for any field the engineer left blank — it maps to SQL NULL:
python -c "
import sqlite3, datetime
db = r'{REPORTS_DIR}/.claude/skills/troubleshoot-report/reports_knowledge.db'
today = datetime.date.today().isoformat()
row = (
{TicketNumber!r}, # str or None
{ClientMoniker!r},
{ReportName!r},
{IssueDescription!r},
{RootCause!r},
{FixDescription!r},
{IssueCategory!r},
{EffortLevel!r},
{PatternTag!r}, # str or None
{Chargeable!r},
today,
today,
)
con = sqlite3.connect(db)
cur = con.execute(
'INSERT INTO diagnoses (ticket_number, client, report_name, issue_description, root_cause, fix_description, issue_category, effort_level, pattern_tag, chargeable, created_date, modified_date) '
'VALUES (?,?,?,?,?,?,?,?,?,?,?,?)',
row,
)
print(cur.lastrowid)
con.commit()
con.close()
"
The repr() of each Python value (the !r in the f-string-style placeholders above) is what makes this safe: pass Python literals into the script, and sqlite3's parameterised execute() handles all escaping.
-
Confirm to the engineer (use the row ID printed by the Python script above):
"Logged to knowledge base. Row ID: {id}"
Then ask:
"Want me to troubleshoot another issue, or would you like to modify this report now?"
Phase 6: Capture what I got wrong (mandatory)
After presenting the diagnosis — before closing the session — always ask:
"Did I get anything wrong in that diagnosis? Even a small thing — wrong assumption, missed cause, misleading focus? If so, tell me and I'll log it so I don't repeat it."
If the engineer reports a mistake:
-
Ask a follow-up to confirm the actual root cause:
"Got it. So the real issue was {paraphrase}. Is that right?"
-
Once confirmed, append an entry to .claude/skills/troubleshoot-report/DIAGNOSIS_LOG.md:
## {ReportName} — {Client} ({today's date})
**What I got wrong:** {description of the incorrect or incomplete diagnosis}
**Why I missed it:** {what assumption, pattern, or blind spot caused the error}
**Lesson:** {the specific check or rule to apply next time to catch this correctly}
- Confirm to the engineer:
"Logged. I'll apply that lesson on the next report."
If the engineer says the diagnosis was correct, no entry is needed.