Domain: IT & Support

You are working as a data analyst for a technology company that operates multiple production systems across different environments and technology stacks. The company relies on historical bug reports to assess system risk, prioritize engineering effort, and make critical hiring and staffing decisions. You are given a dataset (bugs.csv) of bug records containing severity, error codes, environments, ownership, and date, and are asked to perform advanced, multi-step analytical evaluations.
For analysis purposes, the risk index of an issue is defined as the product of its error code and its severity weight. Marginal Risk Contribution (MRC) of an issue is defined as the proportion of that issue’s risk relative to the total risk accumulated by all issues within the same functional domain, where an issue’s risk is determined jointly by the error code and its severity level. Clash Score measures how inconsistent an issue appears across its characteristics. It is computed by first applying min-max normalization independently to error code, severity level, and environment criticality so that each is rescaled relative to its minimum and maximum values in the dataset. The score is then obtained by summing the absolute difference between the normalized error code and severity, and the absolute difference between the normalized severity and environment. Interaction Score measures how strongly an individual issue reflects the combined effect of responsibility and operating context. It is determined by the issue’s risk relative to the total number of issues handled by the same role within the same environment. Consider the following weights where applicable.

Severity: Critical = 4, High = 3, Medium = 2, Low = 1
Environment: Production = 2, Staging = 1, Development = 0

Use the data to answer the following questions. Unless stated otherwise, whenever a question asks you to identify an issue, you should return the corresponding issue identifier.

For any computation that depends on `error_code` directly or indirectly, exclude rows where `error_code` is missing.
For question 2, the phrase "pre-release validation environments" refers only to the `Staging` environment.


1. Compute the average level of risk associated with issues that did not occur in live systems and were handled by roles whose designation includes Developer, rounded to three decimal places of precision.

2. Assume that all issues currently occurring in pre-release validation environments are instead treated as if they occurred in live systems. Determine how much the total weighted impact across the dataset increases as a result of this change. For this question, total weighted impact is defined as the sum of each issue's severity weight multiplied by its environment weight.

3. Considering only functional domains that contain more than one bug, identify the issue with the highest MRC. Break ties lexicographically by issue identifier.

4. Identify the issue that exhibits the greatest inconsistency as measured by the Clash Score. Break ties lexicographically by issue identifier.

5. From all reported bugs, identify the single highest-priority bug by first favoring those with the greatest risk-index. If multiple issues remain tied, prefer the one that has been reported most recently; if a tie still remains, select the issue associated with the most critical operating environment; finally, resolve any remaining tie by choosing the issue with the alphabetically smallest identifier.

Grading rubric:
criterion: Does the answer, after excluding rows with missing `error_code`, compute the average level of risk for issues that did not occur in live systems and were handled by roles whose designation includes "Developer" to be exactly 1110.28?

weight: 10
criterion: Does the answer compute the increase in total weighted impact across the dataset, after treating `Staging` issues as occurring in production, to be exactly 12560?

weight: 10
criterion: Does the answer, after excluding rows with missing `error_code`, identify the issue with the highest Marginal Risk Contribution (MRC) as exactly BUG_000315?

weight: 10
criterion: Does the answer, after excluding rows with missing `error_code`, identify the issue that exhibits the greatest inconsistency, as measured by the Clash Score, as exactly BUG_000024?

weight: 10
criterion: Does the answer, after excluding rows with missing `error_code`, identify the single highest-priority bug using greatest risk index as the primary criterion as exactly BUG_011307?
weight: 10

Golden answer:
# Explanation

1. Any question that depends on `error_code` first excludes rows where `error_code` is missing. A risk index is then calculated by multiplying each remaining issue's error code by its severity weight. The data is filtered to non-Production bugs handled by roles whose designation contains "Developer," and the mean risk index is computed and rounded to three decimal places.

2. The original total weighted impact is computed as the sum of severity_weight x environment_weight for all issues. For this question, "pre-release validation environments" means `Staging`, so Staging issues are reassigned to Production, the total is recomputed under the new environment weights, and the net increase is obtained by subtracting the original total from the new total.

3. Using only rows with non-missing `error_code`, each bug's risk (error_code x severity_weight) is normalized by the total risk of its functional domain to obtain its MRC. Only domains with more than one bug are considered. The bug with the highest MRC is selected, with ties broken lexicographically by bug identifier.

4. Using only rows with non-missing `error_code`, error code, severity weight, and environment weight are each independently min-max normalized. The Clash Score is the sum of the absolute difference between the normalized error code and severity, plus the absolute difference between the normalized severity and environment. The bug with the highest score is selected, with ties broken lexicographically by bug identifier.

5. Using only rows with non-missing `error_code`, bugs are ranked first by descending risk index (error_code x severity_weight), then by recency (fewer days since creation relative to the most recent bug in the dataset), then by descending environment weight, and finally by lexicographically smallest bug identifier to guarantee a unique result.

# Code

```python
import pandas as pd
df = pd.read_csv("bugs.csv")

severity_map = {"Critical": 4, "High": 3, "Medium": 2, "Low": 1}
environment_map = {"Production": 2, "Staging": 1, "Development": 0}

df["severity_weight"] = df["severity"].map(severity_map)
df["environment_weight"] = df["environment"].map(environment_map)

# Any metric that depends on error_code excludes rows where error_code is missing.
df_error = df.dropna(subset=["error_code"]).copy()



# Compute the average level of risk associated with issues that did not occur in live systems and were handled by roles explicitly identified as developers.

# Compute risk index
df_error["risk_index"] = df_error["error_code"] * df_error["severity_weight"]

# Filter non-Production bugs with 'Developer' in developer_role
filtered = df_error[
    (df_error["environment"] != "Production") &
    (df_error["developer_role"].str.contains("Developer", na=False))
]

# Compute average risk index
q1 = round(filtered["risk_index"].mean(), 3)



# Determine how much the total weighted impact across the dataset increases

# For this question, "pre-release validation environments" means Staging only.
environment_map_new = {"Production": 2, "Development": 0}

# Compute original weighted severity
original_total = (df["severity_weight"] * df["environment_weight"]).sum()

# Reassign Staging → Production and recompute environment weight
df["env_weight_new"] = df["environment"].replace("Staging", "Production").map(environment_map_new)
new_total = (df["severity_weight"] * df["env_weight_new"]).sum()

# Net increase in total weighted severity
q2 = new_total - original_total



# Identify the issue with the highest MRC

# Compute risk
df_error["risk"] = df_error["error_code"] * df_error["severity_weight"]

# Filter bug_domains with more than one bug
valid_domains = df_error["bug_domain"].value_counts()
valid_domains = valid_domains[valid_domains > 1].index

df_valid = df_error[df_error["bug_domain"].isin(valid_domains)].copy()

# Compute total risk per bug_domain
domain_risk_sum = df_valid.groupby("bug_domain")["risk"].transform("sum")

# Compute Marginal Risk Contribution (MRC)
df_valid["MRC"] = df_valid["risk"] / domain_risk_sum

# Select bug with highest MRC (deterministic via bug_id tie-breaker)
q3 = (
    df_valid.sort_values(by=["MRC", "bug_id"], ascending=[False, True])
            .iloc[0]["bug_id"]
)



# Identify the issue that exhibits the greatest inconsistency as measured by the Clash Score.

# Min–max normalization
df_error["error_norm"] = (df_error["error_code"] - df_error["error_code"].min()) / (df_error["error_code"].max() - df_error["error_code"].min())
df_error["severity_norm"] = (df_error["severity_weight"] - df_error["severity_weight"].min()) / (df_error["severity_weight"].max() - df_error["severity_weight"].min())
df_error["environment_norm"] = (df_error["environment_weight"] - df_error["environment_weight"].min()) / (df_error["environment_weight"].max() - df_error["environment_weight"].min())

# Compute clash score
df_error["clash"] = (
    (df_error["error_norm"] - df_error["severity_norm"]).abs() +
    (df_error["severity_norm"] - df_error["environment_norm"]).abs()
)

# Select bug with maximum clash score (deterministic via bug_id tie-breaker)
q4 = (
    df_error.sort_values(by=["clash", "bug_id"], ascending=[False, True])
      .iloc[0]["bug_id"]
)



# Highest-priority bug by first favoring those with the greatest risk-index
# Ensure created_at is datetime
df_error["created_at"] = pd.to_datetime(df_error["created_at"])

# Use most recent bug as reference to keep days_since_creation deterministic
ref_date = df_error["created_at"].max()
df_error["days_since_creation"] = (ref_date - df_error["created_at"]).dt.days

# Compute primary score
df_error["priority_score"] = df_error["error_code"] * df_error["severity_weight"]

# Apply ordered selection rules
q5 = (
    df_error.sort_values(
        by=[
            "priority_score",
            "days_since_creation",
            "environment_weight",
            "bug_id"
        ],
        ascending=[False, True, False, True]
    )
    .iloc[0]["bug_id"]
)




# Answers
print(q1)
print(q2)
print(q3)
print(q4)
print(q5)
```

# Output

```
1110.28
12560
BUG_000315
BUG_000024
BUG_011307
```