DocsReference

table

A Markdown table. The template body shows one example row; the validator checks the generated output, not the example. Close with `endtable`.

Leaf tag · open <!-- mdv: table … --> · close <!-- mdv: endtable -->

<!-- mdv: table cols=[Area, Owner, Status] minRows=1 -->
| Area      | Owner | Status |
| --------- | ----- | ------ |
| Warp Core | Scott | green  |
<!-- mdv: endtable -->

Props

PropSyntaxCategoryDescription
cellPercentcellPercent=<option>contentEvery n (p%) cell recomputes p from n and the column header's declared (N=…) denominator. Skips columns without an N header and non-matching cells; flags counts exceeding N. Warns only.
columnEquationcolumnEquation=<option>contentA target column must equal a ±-expression of other columns per row (unit=raw|pct|bps). Skips rows with blank/unparseable cells; reports invalid-option for a named column the table lacks. Warns only.
crossFootcrossFootcontentCross-foot a table: each numeric data column must sum to its declared Total row within tolerance. Skips columns with any unparseable cell; silent when there is no Total row. Warns only. Compose with crossFoot.totalLabel= (custom total-row label) and crossFoot.tolerance= (explicit absolute tolerance) on the same directive.
crossFoot.totalLabelcrossFoot.totalLabel=<option>contentModifier for crossFoot: the total row becomes the LAST row whose first cell contains this label (case-insensitive, Unicode-aware word-bounded — the same matching the default "Total"/"Totals" detection uses). Rows matching the label are excluded from the summed data rows. Quote labels with spaces, using either double or single quotes; either style may contain escaped ", ', and \ (only the quote that opened the atom closes it). Consumed by crossFoot on the same directive; an empty or whitespace-only value reports invalid-option, and so does malformed quoting — trailing text after the closing quote (e.g. "Net"x), or no valid closing quote at all — with its own dedicated message.
crossFoot.tolerancecrossFoot.tolerance=<option>contentModifier for crossFoot: an explicit absolute tolerance (a finite number ≥ 0, in the column's unit) replacing the auto-derived halfUlp(precision)×(cells+1) default; 0 = exact, up to the 1e-9 floating-point guard withinTolerance always applies. Absent, the auto-derived default applies unchanged. Consumed by crossFoot on the same directive; a malformed value reports invalid-option.
returnChainreturnChain=<option>contentThe product of (1+rᵢ) over named period rows must equal the stated cumulative row within tolerance. Silent when any named row/column is absent or unparseable. Warns only.
colcoltableConstrain a named column with col.<name>.<constraint>, including oneOf, required, matches, mask, and unique checks.
colscols=<option>tableRequire the table to contain these columns, in order; extra columns are allowed (pair with noExtraCols to forbid them).
noExtraColsnoExtraColsstrictnessReject header columns not listed in cols=; without cols=, this rule has no effect.
rows.inrows.in=<option>tableRequire every table body row to jointly equal one canon record from a records-projected source, matched by header text = field name.
minRowsminRows=<option>tableRequire the Markdown table to have at least N data rows (the header and separator rows do not count).
maxRowsmaxRows=<option>tableAllow the Markdown table to have at most N data rows (the header and separator rows do not count).

Prop details

cellPercent

Every n (p%) cell recomputes p from n and the column header's declared (N=…) denominator. Skips columns without an N header and non-matching cells; flags counts exceeding N. Warns only.

cellPercent=<option> · category: content · status: stable · src/pipeline/rules/numeric/table/cell-percent.ts

Recompute every n (p%) table cell against the denominator declared in its column header's (N=<int>) annotation: p must equal 100·n/N at the displayed precision. A column whose header carries no (N=...) is skipped whole; a cell that isn't <int> (<pct>%) is skipped; a count that exceeds its column's N is always flagged. Default tolerance is half a unit in the stated percent's last decimal; tol=<pp> overrides it. Warns only.

<!-- mdv: table cellPercent= -->
| Preferred term | Drug (N=120) | Placebo (N=118) |
| -------------- | ------------ | --------------- |
| Nausea         | 12 (10.0%)   | 6 (5.1%)        |
<!-- mdv: endtable -->

columnEquation

A target column must equal a ±-expression of other columns per row (unit=raw|pct|bps). Skips rows with blank/unparseable cells; reports invalid-option for a named column the table lacks. Warns only.

columnEquation=<option> · category: content · status: stable · src/pipeline/rules/numeric/table/column-equation.ts

Per-row column equation: a target column must equal a ±-expression of other columns, row by row. unit=raw (default) compares like-for-like (End=Begin+Flows+PnL); unit=pct/bps express the expression as a percent / basis-points of the SECOND operand (Excess=Fund-Benchmark;unit=bps). Every row with a blank or unparseable operand/target cell is skipped silently; a column the contract names but the table lacks is reported once as invalid-option. Warns only.

<!-- mdv: table columnEquation=End=Begin+Flows+PnL -->
| Period | Begin | Flows | PnL | End    |
| ------ | ----- | ----- | --- | ------ |
| Q1     | 1,000 | 200   | 50  | 1,250  |
<!-- mdv: endtable -->

crossFoot

Cross-foot a table: each numeric data column must sum to its declared Total row within tolerance. Skips columns with any unparseable cell; silent when there is no Total row. Warns only. Compose with crossFoot.totalLabel= (custom total-row label) and crossFoot.tolerance= (explicit absolute tolerance) on the same directive.

crossFoot · category: content · status: stable · src/pipeline/rules/numeric/table/cross-foot.ts

Cross-foot a table: every numeric data column must sum to its declared Total row (the last row whose first cell reads "Total"/"Totals" — a case-insensitive, word-bounded substring match), within a rounding-aware tolerance. Deliberately conservative — a column with ANY unparseable/ambiguous cell is skipped whole (never partially summed), a table with no Total row is a silent no-op, and the label column is never summed. Warns only; a contract hardens it with error=cross-foot-mismatch.

Two modifier atoms on the same directive compose it (both optional; defaults unchanged when absent): crossFoot.totalLabel="Grand Total" replaces the "Total"/"Totals" label detection (same case-insensitive word-bounded matching, last matching row wins), and crossFoot.tolerance=<n> replaces the auto-derived rounding tolerance with an explicit absolute one (0 = exact, up to the 1e-9 floating-point guard withinTolerance always applies).

<!-- mdv: table crossFoot -->
| Line     | Amount |
| -------- | ------ |
| Product  | 8,000  |
| Services | 2,000  |
| Total    | 10,000 |
<!-- mdv: endtable -->

crossFoot.totalLabel

Modifier for crossFoot: the total row becomes the LAST row whose first cell contains this label (case-insensitive, Unicode-aware word-bounded — the same matching the default "Total"/"Totals" detection uses). Rows matching the label are excluded from the summed data rows. Quote labels with spaces, using either double or single quotes; either style may contain escaped ", ', and \ (only the quote that opened the atom closes it). Consumed by crossFoot on the same directive; an empty or whitespace-only value reports invalid-option, and so does malformed quoting — trailing text after the closing quote (e.g. "Net"x), or no valid closing quote at all — with its own dedicated message.

crossFoot.totalLabel=<option> · category: content · status: stable · src/pipeline/rules/numeric/table/cross-foot.ts

<!-- mdv: table crossFoot crossFoot.totalLabel="Grand Total" -->
| Line     | Amount |
| -------- | ------ |
| Product  | 8,000  |
| Services | 2,000  |
| Grand Total | 10,000 |
<!-- mdv: endtable -->

crossFoot.tolerance

Modifier for crossFoot: an explicit absolute tolerance (a finite number ≥ 0, in the column's unit) replacing the auto-derived halfUlp(precision)×(cells+1) default; 0 = exact, up to the 1e-9 floating-point guard withinTolerance always applies. Absent, the auto-derived default applies unchanged. Consumed by crossFoot on the same directive; a malformed value reports invalid-option.

crossFoot.tolerance=<option> · category: content · status: stable · src/pipeline/rules/numeric/table/cross-foot.ts

Modifier for crossFoot: replaces the auto-derived rounding tolerance (half an ULP of the column's displayed precision per summed cell) with an explicit absolute tolerance, in the column's own unit. 0 means exact, up to the 1e-9 floating-point guard withinTolerance always applies (so binary-representation dust from summing floats never false-positives); a value can tighten or widen the default. Consumed by crossFoot via the shared FieldContract; never reports on its own except invalid-option for a malformed value.

<!-- mdv: table crossFoot crossFoot.tolerance=0 -->
| Line     | Amount |
| -------- | ------ |
| Product  | 8,000  |
| Services | 2,000  |
| Total    | 10,000 |
<!-- mdv: endtable -->

returnChain

The product of (1+rᵢ) over named period rows must equal the stated cumulative row within tolerance. Silent when any named row/column is absent or unparseable. Warns only.

returnChain=<option> · category: content · status: stable · src/pipeline/rules/numeric/table/return-chain.ts

Compounding check: the product of (1 + rᵢ/100) over named source rows must equal the stated cumulative row, within tolerance. Values are percents as displayed (1.2% or 1.2). Any named row or the value column being absent/unparseable is a SILENT skip — absence in the DOCUMENT is not misconfiguration; only a malformed option string is reported as invalid-option. Warns only.

<!-- mdv: table returnChain=Return;from=Jan|Feb|Mar;to=Q1 -->
| Period | Return |
| ------ | ------ |
| Jan    | 1.0%   |
| Feb    | 2.0%   |
| Mar    | 3.0%   |
| Q1     | 6.11%  |
<!-- mdv: endtable -->

col

Constrain a named column with col.<name>.<constraint>, including oneOf, required, matches, mask, and unique checks.

col · category: table · status: stable · src/pipeline/rules/table/col.ts

Checks constraints on named table columns; targets a table.

col.<name>.mask may embed a |in: membership filter (col.Version.mask="<semver|in: securityPolicy?>"): once a cell matches the mask shape, the captured value is checked against ctx.document.sources(ref) and reported as unknown-entity on a miss — same posture as heading.mask/pattern.mask: a shape mismatch never triggers membership on top of it, and no sources capability supplied degrades to a silent no-op (issue #1058 — this rule used to compile |in: filters, and even collect them as a declared dependency, without ever enforcing them).

<!-- mdv: table col.Status.oneOf=[open, done] col.ID.unique -->
| Area | Status |
| ---- | ------ |
| Docking | done   |
<!-- mdv: endtable -->

cols

Require the table to contain these columns, in order; extra columns are allowed (pair with noExtraCols to forbid them).

cols=<option> · category: table · status: stable · src/pipeline/rules/table/cols.ts

Checks that a table contains the named columns, in order; extra columns are allowed (the declared columns must appear as an ordered subsequence of the headers). Pair with noExtraCols to also forbid columns outside this list. Targets a table.

<!-- mdv: table cols=[Area, Owner, Status] -->
| Area | Owner | Status |
| ---- | ----- | ------ |
| Relay | Dana  | done   |
<!-- mdv: endtable -->

noExtraCols

Reject header columns not listed in cols=; without cols=, this rule has no effect.

noExtraCols · category: strictness · status: stable · src/pipeline/rules/table/no-extra-cols.ts

<!-- mdv: table cols=[Area, Owner] noExtraCols -->
| Area | Owner |
| ---- | ----- |
| Hangar | Dana  |
<!-- mdv: endtable -->

rows.in

Require every table body row to jointly equal one canon record from a records-projected source, matched by header text = field name.

rows.in=<option> · category: table · status: stable · src/pipeline/rules/table/rows-in.ts

Every table body row's columns, matched to a records-projected source's fields by HEADER TEXT = FIELD NAME, must jointly equal one canon record (row/cell diagnostics land on the DATA ROW's own line — E1a row-line threading). Header binding: for each projected field, exactly one table header must normalize to it (NFC, lowercase, outer-trimmed, internal-whitespace collapsed) — a missing field or a normalization collision emits ONE rows-header-mismatch at the table header (never a row flood) and suppresses row membership for the whole table. Reordered headers are fine; multiword headers work with no column-selector grammar (matching is by full header text). The target tuple is assembled in the source's OWN records: declaration order regardless of visible header order; extra table columns are ignored. Row equality uses the source's own compare mode (exact/folded/mention — default mention). Nearest-record hinting is bounded: the first projected field is the diagnostic key; a row whose first-field value matches one or more canon records under compare names the best candidate in that bucket (fewest differing fields, source order); no global fuzzy search. Honest-null without a sources capability, and when the bound source is not a records projection.

<!-- mdv: table rows.in=./metrics.json -->
| metric  | period | unit | value |
| ------- | ------ | ---- | ----- |
| Latency | Q1     | ms   | 120   |
<!-- mdv: endtable -->

minRows

Require the Markdown table to have at least N data rows (the header and separator rows do not count).

minRows=<option> · category: table · status: stable · src/pipeline/rules/table/rows.ts

<!-- mdv: table minRows=1 -->
| Area | Owner | Status |
| ---- | ----- | ------ |
| Reactor | Dana  | done   |
<!-- mdv: endtable -->

maxRows

Allow the Markdown table to have at most N data rows (the header and separator rows do not count).

maxRows=<option> · category: table · status: stable · src/pipeline/rules/table/rows.ts

<!-- mdv: table maxRows=3 -->
| Area | Owner | Status |
| ---- | ----- | ------ |
| Airlock | Dana  | done   |
<!-- mdv: endtable -->

On this page