Calculation slicing and model audit for Excel files, written in MoonBit.
moon run --target native cmd/main -- slice model.xlsx --target "Summary!B3" --out slice.xlsx --manifest slice.json
moon run --target native cmd/main -- verify-slice slice.xlsx --manifest slice.jsonmoon update
moon check --target native
moon test --target native
moon run --target native cmd/main -- audit fixtures/bad_model.xlsxSheetSentry: fixtures/bad_model.xlsx
sheets: 5 formula cells: 17 findings: 14
high: 4 medium: 7 low: 3
[medium] SS005 Opex!C6 Formula lives on a hidden row.
[medium] SS003 Summary!B2 Formula embeds numeric constant 1.05; prefer a named input cell.
[high] SS001 Summary!B4 Cell contains error value #REF!.
...# Terminal report
moon run --target native cmd/main -- audit model.xlsx
# JSON
moon run --target native cmd/main -- audit model.xlsx --format json --out findings.json
# SARIF for code scanning
moon run --target native cmd/main -- audit model.xlsx --format sarif --out results.sarif
# Self-contained HTML report
moon run --target native cmd/main -- audit model.xlsx --format html --out report.html
# Trace precedents (what this cell depends on)
moon run --target native cmd/main -- trace model.xlsx --cell "Summary!B7" --direction precedents --depth 4
# Trace dependents (what breaks if this cell changes)
moon run --target native cmd/main -- trace model.xlsx --cell "Inputs!B2" --direction dependents --depth 4
# Fail CI if any high-severity finding exists
moon run --target native cmd/main -- audit model.xlsx --fail-on high
# Create a baseline for existing findings
moon run --target native cmd/main -- audit model.xlsx --write-baseline baseline.json
# Fail only on new findings
moon run --target native cmd/main -- audit model.xlsx --baseline baseline.json --fail-on low
# Show only high-severity findings
moon run --target native cmd/main -- audit model.xlsx --min-severity high
# Disable noisy rules for a specific run
moon run --target native cmd/main -- audit model.xlsx --disable SS003,SS004
# Load a project config
moon run --target native cmd/main -- audit model.xlsx --config sheetsentry.json| ID | Severity | Rule | Why it matters |
|---|---|---|---|
| SS001 | High | Error value | #REF!, #DIV/0!, #VALUE!, #N/A, #NAME?, #NUM! silently poison downstream results. |
| SS002 | Medium | Formula inconsistency | One cell in a copied row/column uses a different formula pattern. |
| SS003 | Medium | Hardcoded constant | A numeric constant is embedded in a formula instead of living in an input cell. |
| SS004 | Low | Volatile function | TODAY, NOW, RAND, RANDBETWEEN, OFFSET, INDIRECT, INFO, CELL make results time- or environment-dependent. |
| SS005 | Medium | Hidden formula | Formulas on hidden sheets or hidden rows are easy to miss during review. |
| SS006 | High | Circular reference | A dependency cycle makes calculation order undefined or unstable. |
| SS007 | Low | Dynamic reference | INDIRECT / OFFSET prevent complete static dependency tracing. |
| SS008 | Medium | External workbook | Formula references another workbook, making the model non-self-contained. |
| SS009 | Low | Whole-axis reference | A:A / 1:1 can be expensive and ambiguous. |
| SS010 | Low | Missing cached value | Some readers may show a blank until the workbook is recalculated. |
{
"min_severity": "medium",
"disabled_rules": ["SS004"],
"ignore_cells": ["Summary!B2"],
"fail_on": "high"
}moon run --target native cmd/main -- audit model.xlsx --config sheetsentry.jsonmoon run --target native cmd/main -- audit model.xlsx --write-baseline sheetsentry.baseline.json
moon run --target native cmd/main -- audit model.xlsx --baseline sheetsentry.baseline.json --fail-on low- name: Audit Excel model
run: |
moon run --target native cmd/main -- \
audit model.xlsx --format sarif --out results.sarif --fail-on high
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifflowchart LR
XLSX[XLSX bytes] --> Reader[mbtexcel reader]
Reader --> Cells[Formula cells + cached values + visibility]
Cells --> Refs[Formula reference parser]
Refs --> Graph[Cross-sheet dependency graph]
Graph --> Rules[Rule engine]
Cells --> Rules
Rules --> Report[Terminal / JSON / SARIF / HTML]
Graph --> Trace[Precedents / dependents]moon test --target nativePYTHONPATH=../tools/pylib python3 scripts/make_fixtures.pypub(all) struct CellRef {
start : Int
end : Int
sheet : String?
row : Int
col : Int
end_row : Int
end_col : Int
abs_row : Bool
abs_col : Bool
}pub(all) struct ExternalRef {
workbook : String
sheet : String
row : Int
col : Int
start : Int
end : Int
}pub(all) enum Severity {
High
Medium
Low
}pub(all) struct SliceManifest {
source_file : String
target : String
targets : Array[SliceTarget]
source_sha256 : String
slice_sha256 : String
included_cells : Array[String]
included_sheets : Array[String]
unresolved : Array[String]
external_workbooks : Array[String]
external_cells : Array[String]
total_used_cells : Int
included_used_cells : Int
excluded_used_cells : Int
reduction_ratio : String
minimality_verified : Bool
unreachable_included : Array[String]
missing_required : Array[String]
excluded_reachable : Array[String]
target_value_before : String?
target_value_after : String?
verified : Bool
calc_verified : Bool
complete : Bool
}pub(all) struct SliceTarget {
target : String
before : String?
after : String?
calculated : String?
verified : Bool
calc_verified : Bool
}pub(all) struct SliceVerification {
target : String
before : String?
after : String?
verified : Bool
hash_verified : Bool
targets_total : Int
targets_verified : Int
targets_calc_verified : Int
calc_verified : Bool
source_hash_verified : Bool
minimality_verified : Bool
error : String?
}pub(all) struct TableInfo {
name : String
sheet : String
start_row : Int
start_col : Int
end_row : Int
end_col : Int
columns : Array[String]
}fn filter_report(report : AuditReport, min_severity : String, disabled_rules : Array[String]) -> AuditReportfn normalize_formula(formula : StringView, current_sheet : StringView, row : Int, col : Int) -> Stringfn rewrite_dynamic_refs(formula : StringView, current_sheet : String, _current_row : Int) -> String raise XlsxErrorfn slice_bytes(source_bytes : Bytes, source_file : String, target : String, max_depth : Int) -> SliceResult raise XlsxErrorfn slice_bytes_many(source_bytes : Bytes, source_file : String, targets : Array[String], max_depth : Int, external_workbooks : Map[String, Bytes]) -> SliceResult raise XlsxErrorfn slice_bytes_with_external(source_bytes : Bytes, source_file : String, target : String, max_depth : Int, external_workbooks : Map[String, Bytes]) -> SliceResult raise XlsxErrorfn verify_slice_bytes(slice_bytes : Bytes, manifest_text : String) -> SliceVerification raise ParseErrorfn verify_slice_with_source(source_bytes : Bytes, slice_bytes : Bytes, manifest_text : String) -> SliceVerification raise ParseErrorInstall
Download zipCalculation slicing and model audit for Excel files, written in MoonBit.