---
title: "detect_anomalies"
---

[< Back to Reference](../reference.qmd) | [View source](https://codeberg.org/usrbinr/tidychain/src/branch/main/R/detect_anomalies.R#L47)

# `detect_anomalies()`

Detect Anomalies in Calculation Chain Order

## Usage

```r
detect_anomalies(xlsx, threshold = 1)
```

## Arguments

| Argument | Description |
|----------|-------------|
| `xlsx` | An xlsx_workbook object from `parse_xlsx()`, or a file path. |
| `threshold` | Minimum number of positions a row must be out of order to be flagged as anomalous. Default is 1 (flag any out-of-order cell). |

## Value

A tibble containing anomalous cells with:

- `sheet_name`: Sheet name

- `cell_ref`: Cell reference

- `row`: Current row number

- `col`: Column letter (e.g., "A", "B")

- `col_num`: Column number (A=1, B=2, etc.)

- `calc_order`: Position in calculation chain

- `expected_order`: Expected position if rows were in order

- `order_diff`: Difference between calc_order and expected_order

- `anomaly_type`: Type of anomaly ("moved_up", "moved_down")

## Description

Analyzes a calculation chain to detect cells where the order in calcChain.xml
differs from what would be expected based on row positions. This can reveal
rows that have been moved or inserted after formulas were originally created.

## Details

The forensic insight is that Excel's calcChain.xml records cells in the
order their formulas were created. If a row containing formulas is moved,
those cells retain their original position in the chain. By comparing
the chain order to the current row order, we can detect manipulation.

Anomaly Types

- **moved_up**: Cell appears later in calcChain than its row suggests. This means
the cell was created after cells that are now below it. The row was likely moved
up (to a smaller row number) or inserted between existing rows.

- **moved_down**: Cell appears earlier in calcChain than its row suggests. This means
the cell was created before cells that are now above it. The row was likely moved
down (to a larger row number).

## Examples

```r
## Not run: 
xlsx <- parse_xlsx("spreadsheet.xlsx")
anomalies <- detect_anomalies(xlsx)

# Get summary
summarize_anomalies(anomalies)

## End(Not run)
```

