# SaC Assertions

Use `assertions/**/*.assertions.ts` to express the workbook-visible final-state contract for the target workbook. `univer sac verify` loads matching global assertion entrypoints, copies the target univerfile into the resolved hidden sidecar `runs/<run-id>/artifacts/` directory, reads workbook state through the Facade API, and writes the report path returned in JSON.

`univer sac verify` does not mutate the live target univerfile.

## Assertion File

Place active assertion entrypoints under `assertions/` and name them `*.assertions.ts`:

```text
.Budget.univer.sac/migrations/
  20260526090000-add-revenue-model/
    pack.ts
.Budget.univer.sac/assertions/
  workbook.assertions.ts
  formatting.assertions.ts
  helpers/
    ranges.ts
```

Only `*.assertions.ts` files are discovered as active suites. Other `.ts` files under `assertions/` are helpers and run only when imported by an active entrypoint. Split entrypoints by workbook concern, such as values, formulas, formatting, resources, or sheet-specific contracts; do not split them by historical migration pack.

Import the helper from the CLI-owned virtual module:

```ts
import { defineAssertions } from "univer:sac/assertions";

export default defineAssertions(({ sheet, range }) => {
  sheet("Revenue").exists();
  sheet("Revenue").usedRange("A1:C4");
  range("Revenue!A1:C2").values([
    ["Region", "Q1", "Q2"],
    ["West", 1200, 1400]
  ]);
  range("Revenue!B2:C2").displayValues([["1,200", "1,400"]]);
  range("Revenue!B2:C2").numberFormats([["#,##0", "#,##0"]]);
  range("Revenue!C2:C4").backgroundColors([["#FFF2CC"], ["#D9EAD3"], ["#F4CCCC"]]);
  range("Revenue!C2:C4").styles([[{ backgroundColor: "#FFF2CC", bold: true }], [{}], [{}]]);
  range("Revenue!C2:C4").conditionalFormats([{ ranges: ["C2:C4"], rule: { type: "colorScale" } }]);
  sheet("Revenue").filter({ range: "A1:C4" });
  sheet("Revenue").tables([{ name: "RevenueTable", range: "A1:C4", showHeader: true }]);
  range("Revenue!C4").formula("=SUM(C2:C3)");
});
```

Supported helpers:

- `sheet(name).exists()` verifies that a sheet exists.
- `sheet(name).usedRange(a1)` verifies the used range reported for that sheet.
- `range(a1).values(matrix)` verifies logical stored cell values for a sheet-qualified A1 range.
  When cell model data is available, this uses `cellData.v` so formatted numeric/date cells stay
  numeric instead of becoming display text.
- `range(a1).rawValues(matrix)` verifies raw cell values from `getRawValues()`.
- `range(a1).displayValues(matrix)` verifies formatted display strings from `getDisplayValues()`.
- `range(a1).cellData(matrix)` verifies Facade cell model data from `getCellDataGrid()`.
  Do not use `cellData` to assert raw style snapshots such as `s` or style objects; use semantic
  style helpers instead.
- `range(a1).numberFormats(matrix)` verifies number format patterns from `getNumberFormats()`.
- `range(a1).styles(matrix)` verifies normalized static style traits for the range. Expected style
  objects are partial: include only fields that matter, such as `backgroundColor`, `fontColor`,
  `bold`, `fontFamily`, `fontSize`, `horizontalAlignment`, `verticalAlignment`, `wrap`, `wrapStrategy`,
  or `border`.
- `range(a1).backgroundColors(matrix)` verifies background color strings from `getBackgrounds()`.
- `range(a1).conditionalFormats(rules)` verifies canonical conditional formatting rule resources
  visible to the range. Volatile ids are ignored; range, rule type/config, colors, operators, and
  priority when present are semantic.
- `sheet(name).filter(filter)` verifies the sheet filter range and available criteria semantics.
- `sheet(name).tables(tables)` verifies table resources such as name, range, header/footer flags,
  style id, and available filter/column semantics.
- `range(a1).formula(formula)` verifies one formula cell.
- `range(a1).formulas(matrix)` verifies a formula matrix.

Choose the helper that matches the contract. Use `values` when numeric/date/text identity matters,
`displayValues` when presentation strings are the contract, `numberFormats` when formatting affects
interpretation, and `cellData` only when the cell model shape itself is the evidence needed. Do not
write numeric/date values as formatted strings merely to satisfy visible text; keep the stored value
typed and assert display/formatting separately. For `displayValues`, blank cells are asserted as
empty strings (`""`) because display readback returns strings; use raw/value assertions when
null-like storage identity is the contract. Keep assertions deterministic and representative.
Prefer stable workbook-visible facts over broad snapshots. Do not inspect `.univer` storage
internals as assertion evidence.

Style assertions are semantic contracts. Expected style objects must not contain raw runtime/storage
identifiers such as `s`, `styleId`, `style.id`, generated resource ids, or raw `cellData` style
snapshots. Supported color strings are `#RRGGBB` and `rgb(r, g, b)`; invalid values such as `#E2EFD`
fail setup before runtime readback. Style and background color matrices must match the target range
dimensions. Style mismatch reports include the first differing cell and semantic trait path, such as
`backgroundColor` or `border.top.color`.

Resource helpers verify Facade-visible resources, not final rendered or effective visual output.
When a required readback surface is unavailable, verification fails with setup `error` instead of
passing, skipping, or falling back to raw workbook internals.

## Verify

Run apply before verification when a migration is not yet applied:

```bash
univer sac apply ./Budget.univer
univer sac verify ./Budget.univer --json
```

The JSON summary includes status, `assertionSources[]`, assertion counts, failure summaries, target paths, and the report path. Read the referenced report for detailed failure evidence:

```text
Read `reportPath` from `univer sac verify ./Budget.univer --json`.
```

Status interpretation:

- `passed`: every global assertion passed.
- `failed`: at least one assertion ran and observed workbook-visible state that did not match the expected contract.
- `error`: verification setup failed before a reliable assertion result, such as target state, applied state, source validation, bundling, or runtime setup.

Missing `assertions/**/*.assertions.ts` entrypoints are a setup error. Assertions are loaded only from matching sidecar-global entrypoints.

## Repair Loop

For `failed` reports, inspect each failure for assertion kind, target, expected value, actual value, and first difference when present.

Then decide whether the workbook final state is wrong or the global assertion expectation is wrong. Repair migration source or the relevant `*.assertions.ts` entrypoint, rerun apply when the target univerfile needs to change, then rerun:

```bash
univer sac verify ./Budget.univer --json
```

For `error` reports, repair setup first. Do not treat setup errors as proof that workbook behavior is wrong.

Apply success is not a Spreadsheet TDD completion gate. The completion gate is a relevant `univer sac verify <univerfile> --json` run with global assertions and status `passed`, plus the report path recorded in the handoff.
