> ## Documentation Index
> Fetch the complete documentation index at: https://docs.amazingzebra.com/table-mutation-tracker/llms.txt
> Use this file to discover all available pages before exploring further.

# Change detection

> How two snapshots are compared, what counts as a change, and how the calendar and day view stay consistent.

Every change in the UI comes from comparing a snapshot with the one before it. Nothing is hand-entered, and no changelog files are stored. If the comparison logic improves, past days can be recomputed from the original snapshots.

## Matching assignments

An assignment is identified by its **name and due date**. For each class, the two snapshots' assignments are matched on that pair:

| In previous snapshot | In current snapshot | Result |
| - | - | - |
| No | Yes | **Added** |
| Yes | No | **Deleted** |
| Yes | Yes, with field differences | **Modified** |
| Yes | Yes, identical | No change |

> [!WARNING]
>
> Because name and due date form the identity, renaming an assignment or moving its due date appears as one deletion plus one addition, not as a modification. The deleted-assignments page will list the old version. This is expected behavior and worth knowing before raising a "deleted assignment" with a teacher.

If a class lists two assignments with the same name and due date, they share one identity and only one of them is compared.

## Fields compared

For matched assignments, these fields are compared:

* `category`
* `score_raw`
* `percent`
* `grade`
* `has_comments`
* each status flag on its own: `collected`, `late`, `missing`, `exempt`, `absent`, `incomplete`, `excluded`

A flag change is reported as a single field, so the day view shows a readable row such as:

```text theme={null}
missing: false → true
```

An assignment counts once as modified no matter how many of its fields changed.

## Class-level changes

Separately from assignments, each snapshot records:

* classes that appeared or disappeared
* classes whose `final_grade` changed

These are counted in `class_level` in the rolling index and kept out of the assignment totals.

## Two layers, one definition

Change detection runs in two places for performance reasons:

**1. Rolling index (Python, after each scrape)**

The scraper's `/append-index` endpoint diffs the new snapshot against the previous one and stores the counts. The calendar colors each day from these counts without fetching any snapshots.

**2. Day view (TypeScript, on demand)**

When you open a day, the browser fetches that snapshot and the previous one and diffs them field by field to produce the detail rows.

The two implementations must agree, or a day could be colored as changed with no detail rows to explain it. A test in the repository reads the field list from the TypeScript diff and fails if it differs from the Python one.

## Calendar colors

Each day takes the color of its most significant change:

| Color | Meaning |
| - | - |
| Red | At least one assignment deleted |
| Orange | At least one assignment modified, none deleted |
| Yellow | Assignments added only |
| Green | Scraped, no assignment changes. Class-level changes, such as a final grade update, do not color the day. |
| Gray | No snapshot that day |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.