Calc calling conventions
UW Markdown calculations are a small deterministic expression language. The notation and numeric model are normative (Protocol §VIII.1 and §VIII.5), and the metric dictionary uses them to define every builtin metric. The reference calc engine that evaluates them is a starter product; any engine that reproduces the quantized values will do. An agent may describe assumptions and extract facts, but never supplies financial math.
Write paths from the parsed record
Paths begin with a section id and are resolved against its JSON content.
noi_model.net_operating_income / debt_structure.annual_debt_serviceRegistered series use explicit period identity, independent of row position:
dcf.annual_cash_flows@Y1.net_operating_incomeOrdinary bracket access requires single-quoted string keys, such as ['0']. Numeric bracket syntax [0] is outside the expression grammar. See Protocol §VIII.2a for registered series, selectors and ambiguity refusal.
Use a path only when the owning section really stores that value. Missing input propagates as null; do not substitute a made-up zero.
Units and number conventions
Rates are fractions, never display percentages:
0.0551 # 5.51%
1000000 * 0.0551 # $55,100Use plain numbers for currency, counts, square feet, and periods. Units belong on the calculation declaration ($, %, x, count, $/sf), not inside the formula string.
Operators and builtins
Arithmetic operators are +, -, *, /, and %; comparisons and a ternary conditional are also supported. Available builtins are:
| Category | Functions |
|---|---|
| Aggregation | sum, avg, min, max |
| Logic and rounding | coalesce, if, round |
| Math | abs, floor, ceil, sqrt, pow, log, exp |
| Finance | pmt, fv, pv, nper, npv, irr |
| Validity | is_calendar_date |
sum treats null inputs as zero. avg, min, and max ignore null inputs and return null if every input is null. coalesce returns its first non-null argument. Other arithmetic propagates null, which keeps incomplete-data state visible instead of manufacturing a result.
is_calendar_date(value) is the exception. It answers a yes-or-no question and never returns null:
- It returns
trueonly for a string in the exact formYYYY-MM-DDthat names a real date, such as'2024-02-29'. - It returns
falsefor null, absent values, numbers, padded or date-time strings, and impossible dates such as'2026-02-30'. - To allow an absent date, write
x == null || is_calendar_date(x). - A module that calls it must require a Protocol version at or above the first release that contains it. That floor is assigned when the release is prepared.
Excel-emittable pack formulas
Every pack formula must be expressible in Excel from workbook named ranges. Arithmetic, comparisons, conditionals, and the following builtins emit cleanly:
sum min max if round abs floor ceil sqrt pow log exp pmt npv irr fv pv nperThe emitter deliberately rejects coalesce and avg with EXCEL-EMIT-FN. Their null semantics do not have a portable Excel equivalent. It rejects is_calendar_date the same way: Excel's date functions depend on locale and on the workbook date system, and its 1900 system accepts 1900-02-29. A missing named range produces EXCEL-EMIT-PATH instead. Treat either result as a pack-design error: add the required input mapping or rewrite the formula with equivalent Excel-safe logic.
Verify a formula from the command line
npm run cli -- calc examples/Parkview-Apts-Glendale-AZ.uwx.md "npv(0.1, -100, 60, 60)"The result is deterministic and has no network or model dependency. For error meanings and recovery, see the FAQ.