Purpose. The main pipeline (AI_evaluation_anon_090726jn.R) analyses CWB as one 10-item composite. This file splits it into two subscales and reruns the same nine-cell Wald contrasts on each.

These analyses were not preregistered and should be reported as exploratory.

Subscale Items Content
CWB-O (organizational) cwb_org_1–cwb_org_5 waste supplies, complain, badmouth store, come late, fake sick
CWB-I (interpersonal) cwb_int_1–cwb_int_5 insult performance, mock personal life, ignore, argue, insult/make fun

Composites are item means with na.rm = FALSE, the same rule that produced the existing cwb composite (verified: cwb = mean of all 10 items, NA if any item is missing).

Setup

library(dplyr)
library(tidyr)
library(ggplot2)
library(knitr)
library(kableExtra)
library(effectsize)

BOOT_SEED <- 42L
fmt_p <- function(p) ifelse(p < .001, "< .001", sprintf("%.3f", p))
stars <- function(p) ifelse(p < .001, "***", ifelse(p < .01, "**", ifelse(p < .05, "*", "")))

df_cwb <- read.csv("~/Desktop/anonymized_data_named.csv", stringsAsFactors = FALSE) %>%
  mutate(
    evaluator = factor(evaluator, levels = c("AI", "Human", "Human_AI")),
    kpi_type  = factor(kpi_type,  levels = c("Operational", "Mixed", "Broader")),
    condition9 = factor(condition9, levels = c(
      "AI_Operational", "Human_Operational", "Human_AI_Operational",
      "AI_Mixed", "Human_Mixed", "Human_AI_Mixed",
      "AI_Broader", "Human_Broader", "Human_AI_Broader")),
    cwb_org = rowMeans(across(cwb_org_1:cwb_org_5)),
    cwb_int = rowMeans(across(cwb_int_1:cwb_int_5)),
    # Within-person difference: positive = more interpersonal than organizational
    cwb_int_minus_org = cwb_int - cwb_org
  )

# Sanity check: the two subscales average back to the existing composite
stopifnot(isTRUE(all.equal((df_cwb$cwb_org + df_cwb$cwb_int) / 2, df_cwb$cwb)))
cat("N =", nrow(df_cwb), "\n")
## N = 2402

Reliability and subscale overlap

cronbach_alpha <- function(items) {
  mat <- as.matrix(items[complete.cases(items), ])
  k <- ncol(mat)
  k / (k - 1) * (1 - sum(apply(mat, 2, var)) / var(rowSums(mat)))
}

rel <- data.frame(
  Scale = c("CWB total (10 items)", "CWB-O (5 items)", "CWB-I (5 items)"),
  alpha = c(cronbach_alpha(df_cwb[, c(paste0("cwb_org_", 1:5), paste0("cwb_int_", 1:5))]),
            cronbach_alpha(df_cwb[, paste0("cwb_org_", 1:5)]),
            cronbach_alpha(df_cwb[, paste0("cwb_int_", 1:5)])),
  n_valid = c(sum(!is.na(df_cwb$cwb)), sum(!is.na(df_cwb$cwb_org)), sum(!is.na(df_cwb$cwb_int)))
)

r_oi <- cor.test(df_cwb$cwb_org, df_cwb$cwb_int)

kable(rel, digits = 3, col.names = c("Scale", "Cronbach's α", "n (complete)"),
      caption = "Table 1. Internal consistency") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"))
Table 1. Internal consistency
Scale Cronbach’s α n (complete)
CWB total (10 items) 0.918 2369
CWB-O (5 items) 0.823 2386
CWB-I (5 items) 0.936 2385

Correlation between CWB-O and CWB-I: r = 0.67, 95% CI [0.65, 0.69], p < .001.

Figures

Each panel shows the distribution (violin), individual responses (grey points), and the cell mean ± 1 SE (black box). Same layout as the full-scale CWB figure.

eval_labels  <- c(AI = "AI System", Human_AI = "Human + AI", Human = "Human Manager")
eval_palette <- c("AI System" = "#E9B949", "Human + AI" = "#8CCBEE", "Human Manager" = "#3DAE8C")
kpi_labels   <- c(Operational = "Operational\nKPIs", Mixed = "Mixed\nKPIs", Broader = "Broader\nKPIs")

cwb_violin <- function(data, var, y_label) {
  d <- data %>%
    filter(!is.na(.data[[var]])) %>%
    mutate(
      eval_lab = factor(eval_labels[as.character(evaluator)], levels = eval_labels),
      kpi_lab  = factor(kpi_labels[as.character(kpi_type)],  levels = kpi_labels),
      y = .data[[var]]
    )
  summ <- d %>%
    group_by(kpi_lab, eval_lab) %>%
    summarise(m = mean(y), se = sd(y) / sqrt(n()), .groups = "drop")

  set.seed(BOOT_SEED)  # reproducible jitter
  ggplot(d, aes(x = eval_lab, y = y)) +
    geom_violin(aes(fill = eval_lab), colour = NA, alpha = .75, trim = TRUE, scale = "width") +
    geom_jitter(width = .08, height = .03, size = .9, alpha = .35, colour = "grey35") +
    geom_crossbar(data = summ, aes(y = m, ymin = m - se, ymax = m + se),
                  width = .3, fill = "white", alpha = .9, colour = "black", linewidth = .4) +
    facet_wrap(~ kpi_lab) +
    scale_fill_manual(values = eval_palette, name = NULL) +
    scale_y_continuous(breaks = 1:7) +
    coord_cartesian(ylim = c(.9, 7.1)) +
    labs(x = NULL, y = y_label) +
    guides(fill = guide_legend(override.aes = list(alpha = 1))) +
    theme_bw(base_size = 12) +
    theme(
      legend.position = "bottom",
      panel.grid.major.x = element_blank(),
      panel.grid.minor = element_blank(),
      strip.background = element_rect(fill = "grey95"),
      panel.border = element_rect(colour = "grey30")
    )
}

Figure 1. Organizational CWB (CWB-O)

cwb_violin(df_cwb, "cwb_org", "Organizational CWB (1-7)")

Figure 2. Interpersonal CWB (CWB-I)

cwb_violin(df_cwb, "cwb_int", "Interpersonal CWB (1-7)")

Descriptives

cond_order <- c("Human_Operational", "AI_Operational", "Human_AI_Operational",
                "Human_Mixed", "AI_Mixed", "Human_AI_Mixed",
                "Human_Broader", "AI_Broader", "Human_AI_Broader")

desc <- df_cwb %>%
  group_by(kpi_type, evaluator) %>%
  summarise(
    n = n(),
    org_M = mean(cwb_org, na.rm = TRUE), org_SD = sd(cwb_org, na.rm = TRUE),
    int_M = mean(cwb_int, na.rm = TRUE), int_SD = sd(cwb_int, na.rm = TRUE),
    tot_M = mean(cwb, na.rm = TRUE),     tot_SD = sd(cwb, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(evaluator = factor(evaluator, levels = c("Human", "AI", "Human_AI"))) %>%
  arrange(kpi_type, evaluator)

desc %>%
  mutate(kpi_type = as.character(kpi_type), evaluator = as.character(evaluator)) %>%
  kable(digits = 2, caption = "Table 2. Means and SDs by condition",
        col.names = c("KPI", "Evaluator", "n", "M", "SD", "M", "SD", "M", "SD")) %>%
  add_header_above(c(" " = 3, "CWB-O" = 2, "CWB-I" = 2, "CWB total" = 2)) %>%
  collapse_rows(columns = 1, valign = "top") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"))
Table 2. Means and SDs by condition
CWB-O
CWB-I
CWB total
KPI Evaluator n M SD M SD M SD
Operational Human 501 3.27 1.13 3.36 1.39 3.32 1.15
AI 500 3.38 1.07 3.31 1.35 3.34 1.08
Human_AI 200 3.23 1.08 3.29 1.32 3.26 1.07
Mixed Human 200 2.94 1.21 2.94 1.45 2.94 1.24
AI 200 3.28 1.16 3.22 1.34 3.24 1.15
Human_AI 200 3.12 1.04 3.05 1.27 3.08 1.05
Broader Human 200 2.92 1.10 2.73 1.23 2.82 1.07
AI 200 3.22 1.21 3.04 1.40 3.12 1.20
Human_AI 201 3.14 1.07 2.87 1.27 3.01 1.09

Nine-cell Wald contrasts

Same model and contrasts as Step 4 of the main script: outcome ~ 0 + condition9, nine planned contrasts. The Human_AI vs AI contrast is flipped to AI vs Human_AI, as in format_table5_wald(). Cohen’s d uses the pooled SD of the two cells.

wald_contrast <- function(fit, contrast_weights, label) {
  b <- coef(fit); V <- vcov(fit)
  L <- setNames(rep(0, length(b)), names(b))
  L[names(contrast_weights)] <- contrast_weights
  est <- sum(L * b)
  se  <- sqrt(as.numeric(t(L) %*% V %*% L))
  tv  <- est / se
  dfr <- df.residual(fit)
  data.frame(contrast = label, estimate = est, SE = se, t = tv, df = dfr,
             p = 2 * pt(abs(tv), dfr, lower.tail = FALSE))
}

contrast_specs <- list(
  list(a = "AI",       b = "Human",    lab = "AI vs Human"),
  list(a = "Human_AI", b = "Human",    lab = "Human_AI vs Human"),
  list(a = "AI",       b = "Human_AI", lab = "AI vs Human_AI")
)

pooled_d <- function(data, var, cell_a, cell_b) {
  xa <- na.omit(data[[var]][data$condition9 == cell_a])
  xb <- na.omit(data[[var]][data$condition9 == cell_b])
  sp <- sqrt(((length(xa) - 1) * var(xa) + (length(xb) - 1) * var(xb)) /
               (length(xa) + length(xb) - 2))
  (mean(xa) - mean(xb)) / sp
}

run_wald <- function(outcome, data, covariates = NULL) {
  rhs <- paste(c("0 + condition9", covariates), collapse = " + ")
  fit <- lm(as.formula(paste(outcome, "~", rhs)), data = data)
  out <- list()
  for (k in c("Operational", "Mixed", "Broader")) {
    for (s in contrast_specs) {
      ca <- paste0(s$a, "_", k); cb <- paste0(s$b, "_", k)
      w <- setNames(c(1, -1), paste0("condition9", c(ca, cb)))
      r <- wald_contrast(fit, w, paste(s$lab, "|", k))
      r$d <- pooled_d(data, outcome, ca, cb)
      r$kpi <- k; r$comparison <- s$lab
      out[[length(out) + 1]] <- r
    }
  }
  bind_rows(out) %>% mutate(outcome = outcome)
}

wald_table <- function(res, caption) {
  res %>%
    mutate(
      kpi = factor(kpi, levels = c("Operational", "Mixed", "Broader")),
      comparison = factor(comparison, levels = sapply(contrast_specs, `[[`, "lab"))
    ) %>%
    arrange(kpi, comparison) %>%
    transmute(KPI = as.character(kpi), Contrast = as.character(comparison),
              b = sprintf("%.2f%s", estimate, stars(p)), SE = sprintf("%.2f", SE),
              t = sprintf("%.2f", t), df = df, p = fmt_p(p), d = sprintf("%.2f", d)) %>%
    kable(caption = caption, align = "llrrrrrr") %>%
    collapse_rows(columns = 1, valign = "top") %>%
    kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed")) %>%
    footnote(general = "b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen's d with pooled SD.",
             general_title = "Note.", footnote_as_chunk = TRUE)
}

Main results

w_org <- run_wald("cwb_org", df_cwb)
w_int <- run_wald("cwb_int", df_cwb)
w_tot <- run_wald("cwb",     df_cwb)

wald_table(w_org, "Table 3a. Organizational CWB (CWB-O): planned contrasts")
Table 3a. Organizational CWB (CWB-O): planned contrasts
KPI Contrast b SE t df p d
Operational AI vs Human 0.11 0.07 1.50 2377 0.135 0.10
Human_AI vs Human -0.04 0.09 -0.40 2377 0.687 -0.03
AI vs Human_AI 0.14 0.09 1.53 2377 0.125 0.13
Mixed AI vs Human 0.33** 0.11 2.98 2377 0.003 0.28
Human_AI vs Human 0.18 0.11 1.60 2377 0.110 0.16
AI vs Human_AI 0.15 0.11 1.38 2377 0.166 0.14
Broader AI vs Human 0.30** 0.11 2.66 2377 0.008 0.26
Human_AI vs Human 0.22 0.11 1.95 2377 0.051 0.20
AI vs Human_AI 0.08 0.11 0.71 2377 0.478 0.07
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.
wald_table(w_int, "Table 3b. Interpersonal CWB (CWB-I): planned contrasts")
Table 3b. Interpersonal CWB (CWB-I): planned contrasts
KPI Contrast b SE t df p d
Operational AI vs Human -0.05 0.09 -0.57 2376 0.568 -0.04
Human_AI vs Human -0.08 0.11 -0.67 2376 0.505 -0.05
AI vs Human_AI 0.03 0.11 0.23 2376 0.816 0.02
Mixed AI vs Human 0.27* 0.14 2.03 2376 0.042 0.20
Human_AI vs Human 0.11 0.13 0.79 2376 0.430 0.08
AI vs Human_AI 0.17 0.14 1.24 2376 0.214 0.13
Broader AI vs Human 0.31* 0.14 2.26 2376 0.024 0.23
Human_AI vs Human 0.14 0.13 1.06 2376 0.290 0.11
AI vs Human_AI 0.16 0.14 1.22 2376 0.224 0.12
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.

Side-by-side: total vs. subscales

Quick comparison of where the total-scale effects come from.

side <- bind_rows(w_tot, w_org, w_int) %>%
  mutate(cell = sprintf("%.2f%s", estimate, stars(p)),
         outcome = recode(outcome, cwb = "Total", cwb_org = "CWB-O", cwb_int = "CWB-I")) %>%
  select(kpi, comparison, outcome, cell) %>%
  pivot_wider(names_from = outcome, values_from = cell) %>%
  mutate(kpi = factor(kpi, levels = c("Operational", "Mixed", "Broader")),
         comparison = factor(comparison, levels = sapply(contrast_specs, `[[`, "lab"))) %>%
  arrange(kpi, comparison) %>%
  mutate(kpi = as.character(kpi), comparison = as.character(comparison))

kable(side, col.names = c("KPI", "Contrast", "Total CWB", "CWB-O", "CWB-I"),
      caption = "Table 4. Contrast estimates (b) for total CWB and each subscale", align = "llrrr") %>%
  collapse_rows(columns = 1, valign = "top") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"))
Table 4. Contrast estimates (b) for total CWB and each subscale
KPI Contrast Total CWB CWB-O CWB-I
Operational AI vs Human 0.02 0.11 -0.05
Human_AI vs Human -0.06 -0.04 -0.08
AI vs Human_AI 0.08 0.14 0.03
Mixed AI vs Human 0.30** 0.33** 0.27*
Human_AI vs Human 0.15 0.18 0.11
AI vs Human_AI 0.16 0.15 0.17
Broader AI vs Human 0.30** 0.30** 0.31*
Human_AI vs Human 0.18 0.22 0.14
AI vs Human_AI 0.11 0.08 0.16

Does the effect differ by target? (within-person difference score)

Separate significance tests on CWB-O and CWB-I do not show that the two differ (a significant and a non-significant effect are not significantly different from each other). This tests that directly: the same nine contrasts on cwb_int − cwb_org. A significant contrast means the evaluator effect is larger for one target than the other (positive b = effect larger for interpersonal CWB).

w_diff <- run_wald("cwb_int_minus_org", df_cwb)
wald_table(w_diff, "Table 5. Difference score (CWB-I − CWB-O): planned contrasts")
Table 5. Difference score (CWB-I − CWB-O): planned contrasts
KPI Contrast b SE t df p d
Operational AI vs Human -0.17** 0.06 -2.61 2360 0.009 -0.16
Human_AI vs Human -0.04 0.09 -0.43 2360 0.666 -0.03
AI vs Human_AI -0.13 0.09 -1.55 2360 0.121 -0.12
Mixed AI vs Human -0.03 0.10 -0.26 2360 0.796 -0.03
Human_AI vs Human -0.06 0.10 -0.63 2360 0.531 -0.07
AI vs Human_AI 0.04 0.10 0.37 2360 0.714 0.04
Broader AI vs Human 0.01 0.10 0.13 2360 0.897 0.01
Human_AI vs Human -0.05 0.10 -0.47 2360 0.642 -0.05
AI vs Human_AI 0.06 0.10 0.60 2360 0.552 0.07
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.

Robustness A: covariates

Same covariate set as Step 5 of the main script (age, gender, education as factor, six capability ratings). Listwise deletion applies, so df differ from the main models.

covariates <- c("age", "gender", "education",
                "capability_operational_AI", "capability_operational_Human",
                "capability_operational_HumanAI", "capability_broader_AI",
                "capability_broader_Human", "capability_broader_HumanAI")

df_cwb_cov <- df_cwb %>%
  mutate(education = factor(education),
         gender = factor(gender, levels = c("Female", "Male", "Prefer not to say")),
         across(starts_with("capability_"), as.numeric))

w_org_cov <- run_wald("cwb_org", df_cwb_cov, covariates)
w_int_cov <- run_wald("cwb_int", df_cwb_cov, covariates)

wald_table(w_org_cov, "Table 6a. CWB-O with covariates")
Table 6a. CWB-O with covariates
KPI Contrast b SE t df p d
Operational AI vs Human 0.14* 0.07 2.04 2340 0.042 0.10
Human_AI vs Human -0.05 0.09 -0.55 2340 0.581 -0.03
AI vs Human_AI 0.19* 0.09 2.09 2340 0.037 0.13
Mixed AI vs Human 0.35** 0.11 3.24 2340 0.001 0.28
Human_AI vs Human 0.15 0.11 1.34 2340 0.181 0.16
AI vs Human_AI 0.21 0.11 1.91 2340 0.057 0.14
Broader AI vs Human 0.25* 0.11 2.28 2340 0.023 0.26
Human_AI vs Human 0.20 0.11 1.86 2340 0.063 0.20
AI vs Human_AI 0.05 0.11 0.43 2340 0.666 0.07
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.
wald_table(w_int_cov, "Table 6b. CWB-I with covariates")
Table 6b. CWB-I with covariates
KPI Contrast b SE t df p d
Operational AI vs Human -0.03 0.08 -0.40 2338 0.688 -0.04
Human_AI vs Human -0.09 0.11 -0.83 2338 0.406 -0.05
AI vs Human_AI 0.06 0.11 0.53 2338 0.596 0.02
Mixed AI vs Human 0.31* 0.13 2.31 2338 0.021 0.20
Human_AI vs Human 0.09 0.13 0.66 2338 0.510 0.08
AI vs Human_AI 0.22 0.13 1.65 2338 0.099 0.13
Broader AI vs Human 0.27* 0.13 1.98 2338 0.048 0.23
Human_AI vs Human 0.12 0.13 0.90 2338 0.370 0.11
AI vs Human_AI 0.15 0.13 1.10 2338 0.270 0.12
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.

Note: d in Tables 6a–6b is the unadjusted pooled-SD d (same as main results); only b, SE, t, and p are covariate-adjusted.

Robustness B: comprehension-check exclusions

Same rule as Step 6 of the main script: exclude participants who failed either comprehension check.

df_cwb_cc <- df_cwb %>%
  mutate(
    comp_check_evaluator = as.numeric(comp_check_evaluator),
    comp_check_kpi = as.numeric(comp_check_kpi),
    cc_manager_pass = case_when(
      evaluator == "AI"       & comp_check_evaluator == 4  ~ TRUE,
      evaluator == "Human"    & comp_check_evaluator == 41 ~ TRUE,
      evaluator == "Human_AI" & comp_check_evaluator == 42 ~ TRUE,
      TRUE ~ FALSE),
    cc_kpi_pass = case_when(
      kpi_type == "Operational" & comp_check_kpi == 4  ~ TRUE,
      kpi_type == "Mixed"       & comp_check_kpi == 48 ~ TRUE,
      kpi_type == "Broader"     & comp_check_kpi == 47 ~ TRUE,
      TRUE ~ FALSE)
  ) %>%
  filter(cc_manager_pass & cc_kpi_pass) %>%
  droplevels()

cat("N after comprehension-check exclusions:", nrow(df_cwb_cc), "\n")
## N after comprehension-check exclusions: 1669
w_org_cc <- run_wald("cwb_org", df_cwb_cc)
w_int_cc <- run_wald("cwb_int", df_cwb_cc)

wald_table(w_org_cc, "Table 7a. CWB-O, comprehension-check passers only")
Table 7a. CWB-O, comprehension-check passers only
KPI Contrast b SE t df p d
Operational AI vs Human 0.11 0.08 1.38 1650 0.167 0.10
Human_AI vs Human -0.05 0.11 -0.48 1650 0.632 -0.05
AI vs Human_AI 0.16 0.11 1.50 1650 0.134 0.15
Mixed AI vs Human 0.48*** 0.13 3.58 1650 < .001 0.40
Human_AI vs Human 0.15 0.14 1.14 1650 0.256 0.14
AI vs Human_AI 0.33* 0.13 2.44 1650 0.015 0.30
Broader AI vs Human 0.22 0.13 1.63 1650 0.103 0.20
Human_AI vs Human 0.15 0.14 1.07 1650 0.286 0.15
AI vs Human_AI 0.06 0.14 0.45 1650 0.650 0.06
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.
wald_table(w_int_cc, "Table 7b. CWB-I, comprehension-check passers only")
Table 7b. CWB-I, comprehension-check passers only
KPI Contrast b SE t df p d
Operational AI vs Human -0.12 0.10 -1.22 1646 0.222 -0.09
Human_AI vs Human -0.06 0.13 -0.43 1646 0.666 -0.04
AI vs Human_AI -0.06 0.13 -0.45 1646 0.654 -0.04
Mixed AI vs Human 0.42* 0.16 2.56 1646 0.011 0.30
Human_AI vs Human 0.06 0.17 0.35 1646 0.723 0.04
AI vs Human_AI 0.36* 0.16 2.21 1646 0.027 0.28
Broader AI vs Human 0.26 0.16 1.60 1646 0.110 0.21
Human_AI vs Human 0.24 0.18 1.37 1646 0.172 0.20
AI vs Human_AI 0.02 0.18 0.13 1646 0.893 0.02
Note. b = difference in cell means (first minus second group). * p < .05, ** p < .01, *** p < .001. d = Cohen’s d with pooled SD.

Summary across specifications

grid <- bind_rows(
  w_org %>% mutate(spec = "Main", sub = "CWB-O"),
  w_int %>% mutate(spec = "Main", sub = "CWB-I"),
  w_org_cov %>% mutate(spec = "Covariates", sub = "CWB-O"),
  w_int_cov %>% mutate(spec = "Covariates", sub = "CWB-I"),
  w_org_cc %>% mutate(spec = "CC excl.", sub = "CWB-O"),
  w_int_cc %>% mutate(spec = "CC excl.", sub = "CWB-I")
) %>%
  mutate(cell = sprintf("%.2f%s", estimate, stars(p)),
         col = paste(sub, spec, sep = " | ")) %>%
  select(kpi, comparison, col, cell) %>%
  pivot_wider(names_from = col, values_from = cell) %>%
  select(kpi, comparison,
         `CWB-O | Main`, `CWB-O | Covariates`, `CWB-O | CC excl.`,
         `CWB-I | Main`, `CWB-I | Covariates`, `CWB-I | CC excl.`) %>%
  mutate(kpi = factor(kpi, levels = c("Operational", "Mixed", "Broader")),
         comparison = factor(comparison, levels = sapply(contrast_specs, `[[`, "lab"))) %>%
  arrange(kpi, comparison) %>%
  mutate(kpi = as.character(kpi), comparison = as.character(comparison))

kable(grid, col.names = c("KPI", "Contrast", rep(c("Main", "Covariates", "CC excl."), 2)),
      caption = "Table 8. Contrast estimates (b) across specifications", align = "llrrrrrr") %>%
  add_header_above(c(" " = 2, "CWB-O" = 3, "CWB-I" = 3)) %>%
  collapse_rows(columns = 1, valign = "top") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "condensed"))
Table 8. Contrast estimates (b) across specifications
CWB-O
CWB-I
KPI Contrast Main Covariates CC excl. Main Covariates CC excl.
Operational AI vs Human 0.11 0.14* 0.11 -0.05 -0.03 -0.12
Human_AI vs Human -0.04 -0.05 -0.05 -0.08 -0.09 -0.06
AI vs Human_AI 0.14 0.19* 0.16 0.03 0.06 -0.06
Mixed AI vs Human 0.33** 0.35** 0.48*** 0.27* 0.31* 0.42*
Human_AI vs Human 0.18 0.15 0.15 0.11 0.09 0.06
AI vs Human_AI 0.15 0.21 0.33* 0.17 0.22 0.36*
Broader AI vs Human 0.30** 0.25* 0.22 0.31* 0.27* 0.26
Human_AI vs Human 0.22 0.20 0.15 0.14 0.12 0.24
AI vs Human_AI 0.08 0.05 0.06 0.16 0.15 0.02
sessionInfo()
## R version 4.5.0 (2025-04-11)
## Platform: aarch64-apple-darwin20
## Running under: macOS 26.5.2
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Europe/Madrid
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] effectsize_1.0.2 kableExtra_1.4.1 knitr_1.50       ggplot2_3.5.2   
## [5] tidyr_1.3.1      dplyr_1.1.4     
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10        generics_0.1.4     xml2_1.5.2         stringi_1.8.7     
##  [5] lattice_0.22-6     digest_0.6.37      magrittr_2.0.3     evaluate_1.0.3    
##  [9] grid_4.5.0         estimability_1.5.1 RColorBrewer_1.1-3 mvtnorm_1.3-3     
## [13] fastmap_1.2.0      jsonlite_2.0.0     purrr_1.2.2        viridisLite_0.4.2 
## [17] scales_1.4.0       textshaping_1.0.1  jquerylib_0.1.4    cli_3.6.5         
## [21] rlang_1.2.0        withr_3.0.2        cachem_1.1.0       yaml_2.3.10       
## [25] tools_4.5.0        datawizard_1.3.1   coda_0.19-4.1      bayestestR_0.17.0 
## [29] vctrs_0.7.3        R6_2.6.1           lifecycle_1.0.4    emmeans_2.0.3     
## [33] stringr_1.5.1      insight_1.5.1      pkgconfig_2.0.3    pillar_1.10.2     
## [37] bslib_0.9.0        gtable_0.3.6       glue_1.8.0         systemfonts_1.3.2 
## [41] xfun_0.52          tibble_3.3.0       tidyselect_1.2.1   rstudioapi_0.19.0 
## [45] parameters_0.29.0  xtable_1.8-4       farver_2.1.2       htmltools_0.5.8.1 
## [49] rmarkdown_2.29     svglite_2.2.2      compiler_4.5.0