Expand description
The view format: what a workspace declares under views.<name>.
§Why a view is not a field declaration
A declared field (fields.<name>) already makes a lens: the workspace says
it files things by people, so a frontend groups by people. That covers a
lens whose groups are one field’s values, over the whole corpus.
It cannot express the four things a real archive needs. Scope: a lens
over every file in the workspace buries the entries among the notes, drafts
and READMEs that happen to carry the same field. Grain: “by year” is a
rule about how a value becomes a group, and a field declaration has nowhere
to put it. Fallback: the value worth grouping on is often the first of
several fields that is filled in. Conditions: not everything in scope
belongs in every lens (see crate::filter).
So a view is its own declaration:
views:
daily:
label: Daily
icon: calendar
group: [date_of_document, created, updated]
by: month
under: '[Daily](/Daily/daily_index.md)'
where:
not: { has: draft }
nest: month§There is no date grouping
An earlier form of this format spelled the above group: date, a token that
meant “the date chain” — and the chain itself (date_of_document →
created → updated) was hardcoded in whichever program was reading. Three
field names no workspace had agreed to, blessed by the tool.
Here Grouping is one shape: an ordered list of field keys, first
non-empty wins, optionally cut at a grain. A date view is that
shape with date fields in it, and nothing in this crate knows the word
“date” — the chain above is a declaration a workspace writes, which is
what makes it reviewable, diffable, and different for a workspace that files
by taken_on or received.
A Grain is not a calendar either — it is any coarsening (see
Grain::cut), and the date grains are one family beside
Initial’s A–Z index. It applies to a value, never to a
declared type, so it works on the 2026-07-24 that YAML hands back as a
string without this crate resolving the workspace’s fields.<name>.type
declarations. A value the grain cannot cut does not group at all, rather
than grouping wrongly.
§Classification is not aggregation
The remaining shape is MoReq2010’s, not an invention. ISO 15489 calls classification the identification of a record by the context that produced it; MoReq2010 §1.4.5 separates that from aggregation, “the activity of assembling related records together”, which “may be based on any organisational requirement or criteria, not business context alone”. It permits conjoining the two into one hierarchy and warns what happens when you do: schemes hybridize, and naturally occurring aggregations get split apart to fit the classification.
That maps onto this struct exactly:
Groupingis classification — how records become groups.ViewSpec::underis aggregation — the index the records actually hang under, resolved through the spanning relation rather than by matching a path or a title, so it survives a rename, a move and a retitle.ViewSpec::nestis the deliberate seam between them. It is not derived fromGrouping::by, because a lens must never become a reason to move a file: changing how a view groups is a reading decision, and it would be a poor bargain if a picker that reads like a display setting silently changed where tomorrow’s entry lands.
§Inheritance and override
under: is inherited: a view covers the whole subtree below its anchor, not
just the anchor’s direct children. This is MoReq2010 §201.2.3 — a class
applied at a root aggregation “is inherited as the default classification
for all descendants”. §201.2.4 then allows a class applied directly to a
child to break that chain, which is what keeps aggregations from having to
be homogeneous. That override is a document-level concern and is not part of
this struct; the scope walk in select is the inheritance half.
Structs§
- Grouping
- What a view sorts records by — MoReq2010’s classification.
- View
Spec - One view a workspace declares for itself.
Enums§
- Grain
- A coarsening: how finely a value is cut into groups.
Constants§
- GRAINS
- The grain spellings that are a bare word — what a near-miss diagnostic
offers.
Grain::Initialalso takes a parameterized form ({ initial: 2 }) that is not a spelling to suggest. - VIEWS_
KEY - The config block views are declared in — a top-level axis, so every prov tool reads the same views rather than each app namespacing its own.
- VIEW_
KEYS - The keys valid inside one
views.<name>entry.
Functions§
- humanize
daily_entries→Daily entries: a key is written for a file, a label for a person.- views_
from - Read every
views.<name>entry out of a config surface’sviews:block, in declaration order.