Skip to main content

Module spec

Module spec 

Source
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_documentcreatedupdated) 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:

  • Grouping is classification — how records become groups.
  • ViewSpec::under is 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::nest is the deliberate seam between them. It is not derived from Grouping::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.
ViewSpec
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::Initial also 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_entriesDaily 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’s views: block, in declaration order.