# Invoice 2026/09/014
Invoice 2026/09/014
**Seller:** EPSI sp. z o.o., ul. Bura 21, 00-000 Burowce, NIP PL9998877666 **Buyer:** Northwind Logistics GmbH, Hafenstraße 8, 22222 Hamburg, USt-IdNr. DE881188118
Seller: EPSI sp. z o.o., ul. Bura 21, 00-000 Burowce, NIP PL9998877666 Buyer: Northwind Logistics GmbH, Hafenstraße 8, 22222 Hamburg, USt-IdNr. DE881188118
**Issued:** 2026-09-03 **Delivered:** 2026-08-31 **Payment due:** 2026-09-17
Issued: 2026-09-03 Delivered: 2026-08-31 Payment due: 2026-09-17
## Services rendered
Services rendered
```vmark #lines from example-invoice-csv-import.csv labelled Item, Unit, Qty, Rate [PLN], Net [PLN], VAT [PLN], Gross [PLN] at sha256:e6667fb8dda6801721d885c259e2456a9e6c92f1ec89af7f14330e0c54c6ac14 net_total [PLN] = SUM(Net) vat_total [PLN] = SUM(VAT) gross_total [PLN] = SUM(Gross) ```
net_total [PLN] = SUM(Net)
vat_total [PLN] = SUM(VAT)
gross_total [PLN] = SUM(Gross)
Net of tax the engagement comes to **23300.00**<!--vmark=lines.net_total--> PLN. VAT at 23% adds **5359.00**<!--vmark=lines.vat_total--> PLN, giving a total due of **28659.00**<!--vmark=lines.gross_total--> PLN.
Net of tax the engagement comes to 23300.00 PLN. VAT at 23% adds 5359.00 PLN, giving a total due of 28659.00 PLN.
---
## Appendix — how this differs from the inline version
Appendix — how this differs from the inline version
This is [example-invoice.md](example-invoice.md) with the `#lines` sheet's rows moved out to [example-invoice-csv-import.csv](example-invoice-csv-import.csv) and declared with a `from` clause instead of a preceding GFM table. Everything else about the sheet is unchanged: `net_total`, `vat_total` and `gross_total` are the same `SUM` reduces over the same column names, and the anchored numbers below the block are the same values.
This is example-invoice.md with the #lines sheet's rows
moved out to example-invoice-csv-import.csv
and declared with a from clause instead of a preceding GFM table. Everything
else about the sheet is unchanged: net_total, vat_total and gross_total
are the same SUM reduces over the same column names, and the anchored
numbers below the block are the same values.
Three things are different because the sheet is now imported rather than inline:
Three things are different because the sheet is now imported rather than inline:
**No column rules.** The original document computes `Net`, `VAT` and `Gross` per row inside the `vmark` block (`Net = Qty * Rate`, and so on). An imported sheet has no cell for a column rule to write to — its columns are read-only inputs taken straight from the CSV header row — so `Net`, `VAT` and `Gross` are already computed values *in the CSV*, produced by whatever generated it, not by VisiMark. Only the aggregate reduces (`SUM`) still run here.
No column rules. The original document computes Net, VAT and Gross
per row inside the vmark block (Net = Qty * Rate, and so on). An imported
sheet has no cell for a column rule to write to — its columns are read-only
inputs taken straight from the CSV header row — so Net, VAT and Gross
are already computed values in the CSV, produced by whatever generated it,
not by VisiMark. Only the aggregate reduces (SUM) still run here.
**The `at sha256:…` stamp.** The clause on the fence line pins the CSV's exact bytes. `visimark check` recomputes the digest on every run and fails with `STALE` if the file has changed underneath the document, or `IMPORT` if the clause is missing entirely — an inline table has no analogous guard, because its data lives in the same text `check` is already reading. Editing `example-invoice-csv-import.csv` and running `visimark fmt` rewrites only this `at` clause; the CSV itself is never touched by any VisiMark command.
The at sha256:… stamp. The clause on the fence line pins the CSV's exact
bytes. visimark check recomputes the digest on every run and fails with
STALE if the file has changed underneath the document, or IMPORT if the
clause is missing entirely — an inline table has no analogous guard, because
its data lives in the same text check is already reading. Editing
example-invoice-csv-import.csv and running visimark fmt rewrites only this
at clause; the CSV itself is never touched by any VisiMark command.
**`labelled` asserts the header.** `labelled Item, Unit, Qty, Rate [PLN], Net [PLN], VAT [PLN], Gross [PLN]` checks the CSV's header row matches this exact name and order before anything is evaluated, so a column renamed or reordered upstream is a loud `IMPORT` finding instead of a silent misread.
labelled asserts the header. labelled Item, Unit, Qty, Rate [PLN], Net [PLN], VAT [PLN], Gross [PLN] checks the CSV's header row matches this exact
name and order before anything is evaluated, so a column renamed or reordered
upstream is a loud IMPORT finding instead of a silent misread.
**Units come from the declaration.** The CSV header row stays `Item,Unit,Qty, Rate,Net,VAT,Gross`, so its bytes and the `sha256` stamp are untouched; the brackets in the `labelled` list attach `PLN` to the money columns. A CSV that carried `Rate [PLN]` in its own header would work too, and a header and a declaration that disagree is a `UNIT` finding. The three totals then declare `[PLN]`, which `check` verifies against the unit the `SUM`s derive.
Units come from the declaration. The CSV header row stays Item,Unit,Qty, Rate,Net,VAT,Gross, so its bytes and the sha256 stamp are untouched; the
brackets in the labelled list attach PLN to the money columns. A CSV that
carried Rate [PLN] in its own header would work too, and a header and a
declaration that disagree is a UNIT finding. The three totals then declare
[PLN], which check verifies against the unit the SUMs derive.
See `docs/design/declared-local-data-imports-spec.md` for the full syntax and semantics.
See docs/design/declared-local-data-imports-spec.md for the full syntax and
semantics.
## Attachment: example-invoice-csv-import.csv
Attachment: example-invoice-csv-import.csv
```csv Item,Unit,Qty,Rate,Net,VAT,Gross Discovery workshop,day,2,1800.00,3600.00,828.00,4428.00 Backend implementation,hour,64,220.00,14080.00,3238.40,17318.40 Code review retainer,month,1,2500.00,2500.00,575.00,3075.00 On-call support,hour,12,260.00,3120.00,717.60,3837.60 ```
Item,Unit,Qty,Rate,Net,VAT,Gross
Discovery workshop,day,2,1800.00,3600.00,828.00,4428.00
Backend implementation,hour,64,220.00,14080.00,3238.40,17318.40
Code review retainer,month,1,2500.00,2500.00,575.00,3075.00
On-call support,hour,12,260.00,3120.00,717.60,3837.60