Thursday, May 7, 2026
#!/bin/bash
# ================================================================
# Script : rac_copilot_triage.sh
# Purpose: Collect comprehensive Oracle RAC + VM performance data
# and generate a structured prompt for AI‑assisted triage.
# Scope : Oracle 19c+ RAC on Linux VM (VMware / KVM / OVM)
# Output : rac_copilot_evidence_.log (drop into Copilot)
# ================================================================
# Usage : ./rac_copilot_triage.sh
# Example: ./rac_copilot_triage.sh INC0012345
# Prereqs: Run as oracle (or grid) user with OSWatcher installed
# and environment sourced (. oraenv or grid_env).
# ================================================================
set -o pipefail
# ---- Config ----
TICKET="${1:-UNKNOWN}"
REPORT_DIR="/tmp/rac_copilot_${TICKET}_$(date +%Y%m%d_%H%M%S)"
EVIDENCE_FILE="${REPORT_DIR}/rac_copilot_evidence_${TICKET}.log"
PROMPT_FILE="${REPORT_DIR}/copilot_prompt_${TICKET}.txt"
OSW_ARCHIVE="/opt/oswbb/archive" # adjust to your OSWatcher path
OS_COLLECTION_SECS=60 # how long to collect OS metrics
SQL_OUTPUT="${REPORT_DIR}/db_metrics.txt"
mkdir -p "${REPORT_DIR}"
exec > >(tee -a "${EVIDENCE_FILE}") 2>&1
echo "============================================================"
echo "RAC Copilot Triage Script — Started at $(date)"
echo "ServiceNow Ticket : ${TICKET}"
echo "Hostname : $(hostname)"
echo "Report Directory : ${REPORT_DIR}"
echo "============================================================"
# ================================================================
# SECTION 1 : OS / VM Identification & Health
# ================================================================
echo ""
echo "========== OS & VM IDENTIFICATION =========="
echo "TIMESTAMP: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
echo ""
echo "--- uname ---"
uname -a
echo ""
echo "--- OS Release ---"
cat /etc/os-release 2>/dev/null || cat /etc/redhat-release 2>/dev/null
echo ""
echo "--- CPU Info (lscpu) ---"
lscpu 2>/dev/null | head -40
echo ""
echo "--- Memory Info ---"
free -h 2>/dev/null; echo "---"; cat /proc/meminfo 2>/dev/null | head -20
echo ""
echo "--- Block Devices ---"
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,ROTA 2>/dev/null
echo ""
echo "--- Network Interfaces ---"
ip addr show 2>/dev/null || ifconfig -a 2>/dev/null
# ---- VM-specific detection ----
echo ""
echo "--- VM Detection ---"
systemd-detect-virt 2>/dev/null && echo "(systemd-detect-virt)"
grep -qi 'vmware\|virtualbox\|kvm\|xen\|microsoft' /sys/class/dmi/id/product_name 2>/dev/null \
&& echo "Physical product: $(cat /sys/class/dmi/id/product_name 2>/dev/null)" \
|| echo "Bare-metal or undetected"
grep -qi 'hypervisor' /proc/cpuinfo 2>/dev/null && echo "Hypervisor flag found in /proc/cpuinfo"
# ================================================================
# SECTION 2 : OS Live Metrics (snapshot over OS_COLLECTION_SECS)
# ================================================================
echo ""
echo "========== OS LIVE METRICS (${OS_COLLECTION_SECS}s collection) =========="
echo ""
echo "--- vmstat (last 3 lines) ---"
vmstat 1 $((OS_COLLECTION_SECS > 10 ? 10 : OS_COLLECTION_SECS)) 2>/dev/null | tail -5
echo ""
echo "--- mpstat ---"
mpstat -P ALL 1 3 2>/dev/null | tail -20
echo ""
echo "--- iostat -xm (last 5 lines) ---"
iostat -xm 1 3 2>/dev/null | tail -15
echo ""
echo "--- netstat -s (TCP retrans / UDP errors) ---"
netstat -s 2>/dev/null | grep -iE "retransmit|drop|error|overflow|reassembly"
echo ""
echo "--- CPU Steal Time (top) ---"
top -bn2 -d 5 2>/dev/null | grep -E "Cpu\(s\)|%Cpu" | tail -1
echo ""
echo "--- NUMA Stats ---"
numactl --hardware 2>/dev/null || echo "numactl not available"
grep -i "numa" /proc/vmstat 2>/dev/null | head -10
echo ""
echo "--- HugePages ---"
grep -i huge /proc/meminfo 2>/dev/null
# ================================================================
# SECTION 3 : Oracle Grid Infrastructure / Clusterware Health
# ================================================================
echo ""
echo "========== GRID INFRASTRUCTURE / CLUSTERWARE =========="
echo ""
echo "--- olsnodes ---"
olsnodes -s -t 2>/dev/null || echo "olsnodes not available"
echo ""
echo "--- crsctl check cluster ---"
crsctl check cluster -all 2>/dev/null || echo "crsctl not available"
echo ""
echo "--- crsctl stat res -t (summary) ---"
crsctl stat res -t 2>/dev/null | head -40
echo ""
echo "--- srvctl status database ---"
srvctl status database -d $(ps -ef | grep pmon | grep -v grep | grep -v asm | awk -F_ '{print $3}' | head -1) 2>/dev/null \
|| echo "Could not determine DB name for srvctl"
echo ""
echo "--- ASM Disk Group Usage ---"
if command -v asmcmd &>/dev/null; then
asmcmd lsdg 2>/dev/null
else
echo "asmcmd not available — run from grid home"
fi
# ================================================================
# SECTION 4 : Oracle Database Diagnostics (SQL)
# ================================================================
echo ""
echo "========== DATABASE DIAGNOSTICS (SQL via SQL*Plus) =========="
echo "TIMESTAMP: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
# Locate sqlplus
SQLPLUS="$(which sqlplus 2>/dev/null || echo 'sqlplus')"
cat > "${REPORT_DIR}/rac_metrics.sql" << 'EOSQL'
-- ================================================================
-- RAC Copilot Triage SQL — All metrics for AI analysis
-- ================================================================
SET LINESIZE 300
SET PAGESIZE 50000
SET VERIFY OFF
SET FEEDBACK OFF
SET HEADING ON
SET TIMING OFF
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: DATABASE IDENTIFICATION ===
PROMPT ============================================================
PROMPT Include PDB name, open mode, environment, instance info,
PROMPT host, version, startup time and RAC node count in your report.
SELECT 'INSTANCE: ' || instance_name || ' #' || instance_number ||
' on ' || host_name || ' version ' || version_full ||
' started ' || TO_CHAR(startup_time,'YYYY-MM-DD HH24:MI') ||
' status ' || status || ' role ' || INSTANCE_ROLE
FROM v$instance;
SELECT name || ' (open_mode:' || open_mode || ' DB_ROLE:' || DATABASE_ROLE ||
' created:' || TO_CHAR(created,'YYYY-MM-DD') || ')' AS db_info
FROM v$database;
SELECT COMPR_NAME, COMPR_STATUS, VERSION FROM dba_registry;
SELECT con_id, name, open_mode, restricted, total_size/1024/1024/1024 size_gb
FROM v$pdbs ORDER BY con_id;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: RAC CLUSTER HEALTH ===
PROMPT ============================================================
PROMPT If is_public=YES, RAC may be using wrong NIC. Must be NO.
PROMPT If any IF_STATE is DOWN, flag as RED.
SELECT * FROM gv$cluster_interconnects;
--- Interconnect latency (v$instance_ping):
SELECT inst1.instance_number src_inst, inst2.instance_number dst_inst,
elap.connected, elap.ping_latency_ms
FROM v$instance_ping elap,
(SELECT instance_number FROM v$instance) inst1,
(SELECT instance_number FROM v$instance) inst2
WHERE inst1.instance_number = elap.instance_number(+);
--- GES Statistics:
SELECT inst_id, resource_name1, resource_name2, state, owner_node, blocked, blocker
FROM gv$ges_blocking_enqueue WHERE blocker = 1;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: CLUSTER-WIDE PROCESS CAPACITY ===
PROMPT ============================================================
PROMPT ACTIVE_PROCESSES vs MAX_PROCESSES per instance.
PROMPT GREEN: <65%, YELLOW: 65-85%, RED: >85%.
SELECT NVL(TO_CHAR(p.inst_id),'CLUSTER_TOTAL') AS inst_id,
COUNT(*) AS active_processes,
MAX(p.max_proc) AS max_processes,
ROUND(COUNT(*)/MAX(p.max_proc)*100,2) AS pct_used
FROM (SELECT inst_id FROM gv$process) p
CROSS JOIN (SELECT inst_id, TO_NUMBER(VALUE) max_proc
FROM gv$parameter WHERE name='processes') m
WHERE p.inst_id = m.inst_id
GROUP BY ROLLUP(p.inst_id) ORDER BY p.inst_id;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: SESSION COUNTS PER INSTANCE ===
PROMPT ============================================================
SELECT inst_id, status, type, COUNT(*) AS session_count
FROM gv$session GROUP BY inst_id, status, type
ORDER BY inst_id, status, type;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: CPU SATURATION (CDB-LEVEL, PER INSTANCE) ===
PROMPT ============================================================
PROMPT cpu_wait_sec = db_time_sec - db_cpu_sec.
PROMPT 0: GREEN. Small & stable: YELLOW. Large or growing: RED.
SELECT inst_id,
ROUND(SUM(CASE WHEN stat_name='DB time' THEN value END)/1e6,2) db_time_sec,
ROUND(SUM(CASE WHEN stat_name='DB CPU' THEN value END)/1e6,2) db_cpu_sec,
ROUND((SUM(CASE WHEN stat_name='DB time' THEN value END)-
SUM(CASE WHEN stat_name='DB CPU' THEN value END))/1e6,2) cpu_wait_sec
FROM gv$sys_time_model GROUP BY inst_id ORDER BY inst_id;
SELECT inst_id, value AS cpu_count
FROM gv$parameter WHERE name='cpu_count' ORDER BY inst_id;
SELECT inst_id, name, is_top_plan, cpu_managed, utilization_limit
FROM gv$rsrc_plan WHERE is_top_plan='TRUE' ORDER BY inst_id;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: VM-SPECIFIC METRICS ===
PROMPT ============================================================
PROMPT CPU steal time >5% on any VM node is RED.
PROMPT BUSY_TIME high but IDLE_TIME near zero = CPU overcommitted.
SELECT inst_id,
SUM(CASE WHEN stat_name='BUSY_TIME' THEN value END)/100 CPU_BUSY_SEC,
SUM(CASE WHEN stat_name='IDLE_TIME' THEN value END)/100 CPU_IDLE_SEC,
SUM(CASE WHEN stat_name='RSRC_MGR_CPU_WAIT_TIME' THEN value END)/100 CPU_RM_WAIT_SEC,
SUM(CASE WHEN stat_name='NUM_CPUS' THEN value END) NUM_CPUS
FROM gv$osstat
WHERE stat_name IN ('BUSY_TIME','IDLE_TIME','RSRC_MGR_CPU_WAIT_TIME','NUM_CPUS')
GROUP BY inst_id ORDER BY inst_id;
--- System metrics (1-min granularity, last 60 minutes):
PROMPT
PROMPT --- gv$sysmetric_history: CPU Usage Per Sec (last 10 rows) ---
SELECT inst_id, TO_CHAR(end_time,'HH24:MI') tm,
ROUND(MAX(CASE WHEN metric_name='CPU Usage Per Sec' THEN value END)/100,1) cpu_cores_used,
ROUND(MAX(CASE WHEN metric_name='Host CPU Utilization (%)' THEN value END),1) host_cpu_pct,
ROUND(MAX(CASE WHEN metric_name='Database Time Per Sec' THEN value END)/100,1) db_time_cores
FROM gv$sysmetric_history
WHERE end_time > SYSDATE - 10/1440
AND metric_name IN ('CPU Usage Per Sec','Host CPU Utilization (%)','Database Time Per Sec')
AND group_id = 2
GROUP BY inst_id, TO_CHAR(end_time,'HH24:MI')
ORDER BY inst_id, tm;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: RAC GC WAIT EVENTS (CLUSTER-WIDE) ===
PROMPT ============================================================
PROMPT Focus on gc cr/current block busy, gc block lost, gc cr multi block.
PROMPT 3-way transfers > 5% of 2-way: YELLOW. gc block lost > 0: RED.
PROMPT --- Top 15 Wait Events (excluding Idle) ---
SELECT * FROM (
SELECT inst_id, event, wait_class,
total_waits, time_waited_micro/1e6 time_waited_sec,
ROUND(time_waited_micro/1e6/NULLIF(total_waits,0)*1000,3) avg_wait_ms
FROM gv$system_event
WHERE wait_class <> 'Idle'
ORDER BY time_waited_micro DESC
) WHERE ROWNUM <= 15;
PROMPT --- GC Wait Events Specifically ---
SELECT inst_id, event, total_waits, time_waited_micro/1e6 time_waited_sec
FROM gv$system_event
WHERE event LIKE 'gc%'
ORDER BY time_waited_micro DESC;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: BLOCKING SESSIONS ===
PROMPT ============================================================
PROMPT Cross-instance blocking must be called out explicitly.
SELECT a.inst_id blocker_inst, a.sid blocker_sid,
a.username blocker_user, a.event blocker_event,
b.inst_id waiter_inst, b.sid waiter_sid,
b.username waiter_user, b.event waiter_event,
b.seconds_in_wait
FROM gv$session a
JOIN gv$session b
ON a.sid = b.final_blocking_session
AND a.inst_id = b.final_blocking_instance
WHERE b.final_blocking_session IS NOT NULL
ORDER BY b.seconds_in_wait DESC;
PROMPT --- Enqueue Locks Held ---
SELECT l.inst_id, l.sid, s.username, s.program, l.type,
l.lmode, l.request, l.block, l.ctime
FROM gv$lock l JOIN gv$session s
ON l.sid = s.sid AND l.inst_id = s.inst_id
WHERE l.block > 0 AND l.type IN ('TX','TM')
ORDER BY l.inst_id, l.sid;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: ASH LAST HOUR (CLUSTER-WIDE) ===
PROMPT ============================================================
PROMPT --- Wait Classes (last hour, all instances) ---
SELECT wait_class, COUNT(*) AS samples,
ROUND(COUNT(*)/36,0) AS est_active_sessions
FROM gv$active_session_history
WHERE sample_time > SYSDATE - 1/24
AND session_state = 'WAITING'
AND wait_class <> 'Idle'
GROUP BY wait_class ORDER BY samples DESC;
PROMPT --- Top 10 Wait Events (last hour) ---
SELECT event, wait_class, COUNT(*) AS samples
FROM gv$active_session_history
WHERE sample_time > SYSDATE - 1/24
AND session_state = 'WAITING'
AND wait_class <> 'Idle'
GROUP BY event, wait_class ORDER BY samples DESC
FETCH FIRST 10 ROWS ONLY;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: TOP SQL (last hour ASH) ===
PROMPT ============================================================
SELECT sql_id, COUNT(*) AS ash_samples,
ROUND(COUNT(*)/36,0) AS est_active_sessions
FROM gv$active_session_history
WHERE sample_time > SYSDATE - 1/24
AND sql_id IS NOT NULL
GROUP BY sql_id ORDER BY ash_samples DESC
FETCH FIRST 10 ROWS ONLY;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: SGA / PGA MEMORY ===
PROMPT ============================================================
SELECT inst_id, name, ROUND(bytes/1024/1024) AS size_mb, resizeable
FROM gv$sgainfo ORDER BY inst_id, name;
SELECT inst_id, ROUND(SUM(pga_alloc_mem)/1024/1024/1024,2) total_pga_gb,
ROUND(SUM(pga_used_mem)/1024/1024/1024,2) used_pga_gb,
ROUND(SUM(pga_max_mem)/1024/1024/1024,2) max_pga_gb
FROM gv$process GROUP BY inst_id ORDER BY inst_id;
SELECT name, value FROM v$parameter
WHERE name IN ('sga_target','sga_max_size','memory_target','memory_max_target',
'pga_aggregate_target','shared_pool_size','db_cache_size');
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: TABLESPACE & FRA SPACE ===
PROMPT ============================================================
SELECT tablespace_name,
ROUND(SUM(bytes)/1024/1024/1024,2) total_gb,
ROUND(SUM(maxbytes)/1024/1024/1024,2) max_gb
FROM dba_data_files GROUP BY tablespace_name
ORDER BY total_gb DESC;
SELECT ROUND(SPACE_LIMIT/1024/1024/1024,2) fra_total_gb,
ROUND(SPACE_USED/1024/1024/1024,2) fra_used_gb,
ROUND(SPACE_USED/SPACE_LIMIT*100,2) fra_pct
FROM v$recovery_file_dest;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: DATA GUARD STATUS ===
PROMPT ============================================================
SELECT * FROM v$dataguard_stats;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: RECENT ALERT LOG ERRORS ===
PROMPT ============================================================
SELECT TO_CHAR(originating_timestamp,'YYYY-MM-DD HH24:MI') alert_time,
message_text
FROM v$diag_alert_ext
WHERE (message_text LIKE '%ORA-%' OR message_text LIKE '%error%'
OR message_text LIKE '%fail%')
AND originating_timestamp > SYSDATE - 1
AND ROWNUM <= 50
ORDER BY originating_timestamp DESC;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: REAL-TIME SQL MONITOR (TOP 10) ===
PROMPT ============================================================
SELECT inst_id, sql_id, sql_exec_id, status,
ROUND(elapsed_time/1e6,1) elapsed_sec,
ROUND(cpu_time/1e6,1) cpu_sec,
ROUND(user_io_wait_time/1e6,1) io_wait_sec,
ROUND(temp_space_allocated/1024/1024,1) temp_mb
FROM gv$sql_monitor
WHERE status IN ('EXECUTING','DONE')
AND (cpu_time + user_io_wait_time) > 0
ORDER BY elapsed_time DESC FETCH FIRST 10 ROWS ONLY;
PROMPT
PROMPT ============================================================
PROMPT === COPILOT_AUTO_INSTRUCT: DATABASE FILES I/O ===
PROMPT ============================================================
SELECT file_name, ROUND(bytes/1024/1024/1024,2) size_gb
FROM dba_data_files ORDER BY bytes DESC FETCH FIRST 20 ROWS ONLY;
SELECT name, ROUND(value/1024/1024,2) size_mb
FROM v$sga ORDER BY name;
PROMPT ============================================================
PROMPT === END DATABASE METRICS ===
PROMPT ============================================================
EOSQL
# ---- Execute SQL ----
echo "Connecting to database ..."
$SQLPLUS -S / as sysdba @"${REPORT_DIR}/rac_metrics.sql" > "${SQL_OUTPUT}" 2>&1
RC=$?
if [ $RC -ne 0 ]; then
echo "WARNING: SQL*Plus exited with code $RC. Output may be incomplete."
fi
cat "${SQL_OUTPUT}" >> "${EVIDENCE_FILE}"
# ================================================================
# SECTION 5 : Include recent OSWatcher data (optional)
# ================================================================
echo ""
echo "========== OSWATCHER RECENT DATA =========="
if [ -d "${OSW_ARCHIVE}" ]; then
# Find the most recent oswtop or oswvmstat file
LATEST_VMSTAT=$(find "${OSW_ARCHIVE}" -name "*vmstat*" -type f -mmin -120 2>/dev/null | tail -1)
if [ -n "${LATEST_VMSTAT}" ]; then
echo "--- Last 50 lines of ${LATEST_VMSTAT} ---"
tail -50 "${LATEST_VMSTAT}"
else
echo "No recent OSWatcher vmstat data found. Consider installing OSWbb."
fi
else
echo "OSWatcher archive not found at ${OSW_ARCHIVE}."
echo "Install OSWbb (Doc ID 301137.1) for continuous OS metrics."
fi
# ================================================================
# SECTION 6 : Build Copilot Prompt
# ================================================================
echo ""
echo "========== BUILDING COPILOT PROMPT =========="
cat > "${PROMPT_FILE}" << 'EOPROMPT'
# Role
You are an expert **Oracle RAC & VM Performance DBA**. You triage incidents using evidence from OS, clusterware, and database diagnostics. You provide a **confidence score (0–100%)** for every finding.
# Context
- **ServiceNow Ticket**:
- **Environment**: Oracle 19c+ RAC running on Linux virtual machines (VMware / KVM / OVM).
- **Evidence Source**: The attached log file contains comprehensive OS + clusterware + database metrics collected simultaneously from all nodes.
# Task
Analyze the **ENTIRE attached evidence file** from scratch. Do NOT rely on prior conversation. Produce:
## A) Executive Summary
2–3 sentences describing the overall health (GREEN / YELLOW / RED) and the single most critical finding.
## B) Full On-Call DBA Report for ServiceNow
For each area below, provide findings, a severity verdict, and a **confidence score**:
1. **Cluster Health** – olsnodes, crsctl, interconnect, GES enqueues
2. **Process & Session Capacity** – per-instance ACTIVE_PROCESSES vs MAX_PROCESSES
3. **CPU Saturation** – DB_Time vs DB_CPU per instance; Host CPU utilization; CPU steal
4. **RAC Global Cache (Cache Fusion)** – gc wait events; 2-way vs 3-way vs disk reads; interconnect latency
5. **Blocking & Locking** – cross-instance blockers; TX/TM locks; duration
6. **Memory Stability** – SGA/PGA sizing; ORA-4031; shared pool free memory
7. **Storage & I/O** – tablespace usage; FRA usage; datafile I/O; ASM disk groups
8. **Top SQL** – ASH samples; SQL Monitor; temp spill
9. **Alert Log** – ORA- errors; cluster communication errors
10. **Data Guard** – transport/apply lag (if applicable)
## C) Numeric Summary
Provide a concise table with:
- Instances: N | RAC: Yes/No | DB Version: X.Y.Z
- Active Processes (per node / cluster total)
- Max Processes (per node)
- Active User Sessions (per node / cluster total)
- Blocking Sessions (count; 0 = GREEN)
- GC 3-way % of total GC requests
- FRA % Used
- Top Wait Event (name + avg ms)
- CPU Wait (sec) per instance
- ORA- Errors in last 24h
## D) Actionable Remediation
List the top 3 immediate actions, ordered by urgency.
# Interpretation Rules (MANDATORY)
- **GC wait events**: 2-way is fast; 3-way is hot-block contention; disk read means block not in any cache.
- **gc buffer busy / gc cr block busy**: Hot block accessed concurrently from multiple instances. Focus on application partitioning or reverse-key indexes.
- **gc block lost**: Always RED — indicates private network packet loss. Check UDP buffer sizes (net.core.rmem_max), MTU mismatch, or faulty NIC.
- **CPU steal time**: >5% on VM nodes → RED. Indicates hypervisor CPU overcommitment. Recommend CPU reservations.
- **PX Deq: * waits**: Parallel coordination, NOT blocking. Do NOT escalate.
- **resmgr:cpu quantum**: Expected throttling under Resource Manager. Cross-reference with active plan.
- **ACTIVE_PROCESSES >85% of MAX_PROCESSES**: RED. Risk of ORA-00020.
- **DB TIME >> DB CPU on multiple instances**: CDB-level CPU oversubscription. NOT a single PDB problem.
# Confidence Score Guidance
- **90–100%**: Very clear evidence; metric values and trends well captured.
- **70–89%**: Generally clear, but some inference required or data limited.
- **50–69%**: Partial evidence; key metrics missing or ambiguous.
- **<50%**: Low confidence; critical data unavailable; recommend manual investigation.
# Output Format
Use a clean, structured Markdown format. Include **severity badges** (🟢 GREEN / 🟡 YELLOW / 🔴 RED) and **confidence scores** for each finding.
EOPROMPT
# Replace placeholder with actual ticket
sed -i "s//${TICKET}/g" "${PROMPT_FILE}"
echo ""
echo "============================================================"
echo "=== COLLECTION COMPLETE ==="
echo "============================================================"
echo "Evidence file : ${EVIDENCE_FILE}"
echo "Copilot prompt: ${PROMPT_FILE}"
echo ""
echo "=== NEXT STEPS ==="
echo "1) Open a NEW Copilot session (clear prior context)."
echo "2) Copy-paste the contents of: ${PROMPT_FILE}"
echo "3) Then drag-and-drop the evidence file: ${EVIDENCE_FILE}"
echo "4) Say: 'Analyze the attached evidence file using the instructions above.'"
echo "5) Once analysis is complete, say: 'Create a downloadable .txt artifact with the full report.'"
echo "============================================================"