@heroiclands/package-build 23.8.0 → 23.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/bin/content-commands.mjs +12 -4
  3. package/docs/api.md +328 -28
  4. package/docs/authoring/first-note.md +1 -1
  5. package/docs/authoring/links-and-markup.md +140 -56
  6. package/docs/commands.md +19 -10
  7. package/docs/content-format.md +2 -2
  8. package/docs/diagnostics.md +1 -1
  9. package/docs/guides/packs.md +2 -1
  10. package/docs/guides/reference-pages.md +86 -63
  11. package/docs/reference/format-details.md +269 -123
  12. package/docs/reference/note-types.md +184 -170
  13. package/engine/anchors.mjs +7 -20
  14. package/engine/compile-corpus.mjs +3 -2
  15. package/engine/content-format.yaml +1 -0
  16. package/engine/content-index.mjs +412 -11
  17. package/engine/content-links.mjs +43 -15
  18. package/engine/content-tables.mjs +8 -4
  19. package/engine/culture-reach.mjs +61 -34
  20. package/engine/data-keys.mjs +3 -1
  21. package/engine/dictionary-layout.mjs +151 -19
  22. package/engine/dictionary-rows.mjs +129 -79
  23. package/engine/foundry-entries.mjs +21 -3
  24. package/engine/glossary-entries.mjs +11 -11
  25. package/engine/heading-attributes.mjs +21 -28
  26. package/engine/helpers.mjs +12 -6
  27. package/engine/journals.mjs +4 -1
  28. package/engine/language-data.mjs +53 -0
  29. package/engine/language-terms.mjs +86 -0
  30. package/engine/language-words.mjs +2 -2
  31. package/engine/lexical-sections.mjs +247 -0
  32. package/engine/note-claims.mjs +2 -0
  33. package/engine/note-state.mjs +9 -3
  34. package/engine/note-vocabulary.mjs +7 -6
  35. package/engine/pdf-build.mjs +9 -9
  36. package/engine/site-build.mjs +16 -2
  37. package/engine/sql-tables.mjs +262 -43
  38. package/engine/stub-lint.mjs +6 -2
  39. package/engine/web-wikilinks.mjs +8 -6
  40. package/engine/word-rows.mjs +20 -12
  41. package/engine/word-terms.mjs +15 -6
  42. package/package.json +1 -1
  43. package/types/engine/content-index.d.mts +65 -1
  44. package/types/engine/content-tables.d.mts +2 -1
  45. package/types/engine/culture-reach.d.mts +22 -2
  46. package/types/engine/data-keys.d.mts +7 -0
  47. package/types/engine/dictionary-layout.d.mts +35 -4
  48. package/types/engine/dictionary-rows.d.mts +9 -0
  49. package/types/engine/foundry-entries.d.mts +3 -1
  50. package/types/engine/heading-attributes.d.mts +2 -2
  51. package/types/engine/helpers.d.mts +4 -1
  52. package/types/engine/language-terms.d.mts +7 -0
  53. package/types/engine/lexical-sections.d.mts +95 -0
  54. package/types/engine/note-state.d.mts +2 -1
  55. package/types/engine/site-build.d.mts +4 -1
  56. package/types/engine/sql-tables.d.mts +33 -3
  57. package/types/engine/word-rows.d.mts +9 -7
@@ -2297,10 +2297,13 @@ convention rather than declared in a field — see
2297
2297
 
2298
2298
  ### Three states of a note
2299
2299
 
2300
- Every typed note requires a nonempty body after its closing frontmatter fence.
2301
- An empty or whitespace-only body is an error, regardless of description or
2302
- `tags: [draft]`. This includes `folder` and `homepage` notes. Untyped vault
2303
- scaffolding is excluded. A nonempty body with fewer than 25 prose words warns
2300
+ Nonempty `data.words` on a language note (`skill`/`language`), or `data.glossary`
2301
+ on a culture or affiliation, supplies page content without an authored body.
2302
+ Absent or empty arrays supply no such exemption. Every other typed note
2303
+ requires a nonempty body after its closing frontmatter fence, including
2304
+ `folder` and `homepage`. An empty or whitespace-only body is otherwise an error,
2305
+ regardless of description or `tags: [draft]`. Untyped vault scaffolding is
2306
+ excluded. A nonempty body with fewer than 25 prose words warns
2304
2307
  unless tagged `draft`; the tag never exempts an empty body. A `folder` note is
2305
2308
  held only to the nonempty rule: any body, a placeholder or a single line
2306
2309
  included, passes with or without `draft`.
@@ -2309,14 +2312,14 @@ The `lint`, `content-index`, `package compile`, `site` and `pdf` commands enforc
2309
2312
  body errors. Write a short beginning and tag it `draft` when work is unfinished.
2310
2313
 
2311
2314
  The internal classification below describes records, including incomplete notes
2312
- that inspection APIs can still read. A **stub** is invalid authored content and
2313
- must receive a body before these commands can publish it.
2315
+ that inspection APIs can still read. A **stub** has neither an authored body nor
2316
+ automatic lexical content and must receive content before it can publish.
2314
2317
 
2315
- | State | Body | Marker | Page | Document | Link target |
2316
- | --------- | ------- | --------------- | ------------ | --------------------------------- | ----------- |
2317
- | **stub** | empty | none | no | yes, where one would not be empty | no |
2318
- | **draft** | written | `tags: [draft]` | yes, noticed | yes, noticed | yes |
2319
- | **full** | written | none | yes | yes | yes |
2318
+ | State | Content | Marker | Page | Document | Link target |
2319
+ | --------- | --------------- | --------------- | ------------ | --------------------------------- | ----------- |
2320
+ | **stub** | none | none | no | yes, where one would not be empty | no |
2321
+ | **draft** | body or lexical | `tags: [draft]` | yes, noticed | yes, noticed | yes |
2322
+ | **full** | body or lexical | none | yes | yes | yes |
2320
2323
 
2321
2324
  "Document" here is the document a note's frontmatter earns. A system's Actor or
2322
2325
  Item is earned by that system's block, in every state —
@@ -2338,7 +2341,7 @@ link starts resolving.
2338
2341
 
2339
2342
  The rule is that severe because the test has to be one you can apply by looking
2340
2343
  at the file. Every softer rule makes two files that look different behave the
2341
- same.
2344
+ same. For a note without automatic lexical content:
2342
2345
 
2343
2346
  | After the fence | Empty? | What happens |
2344
2347
  | ----------------------- | ------ | --------------------------------------------------------------- |
@@ -2368,7 +2371,8 @@ It keeps everything else:
2368
2371
  > index then names no artefact: `uuid`, `path` and `address` are `null`, which
2369
2372
  > is how a record says one was not made.
2370
2373
 
2371
- The test is about the **output**, which is what lets one rule cover every case:
2374
+ The test is about the **output**. For a note with no generated Dictionary or
2375
+ Glossary content:
2372
2376
 
2373
2377
  | The note | The document | Made? |
2374
2378
  | ---------------------------------- | -------------------------------------- | ----- |
@@ -2400,6 +2404,11 @@ site's front door. The classification helpers retain their addresses and report
2400
2404
  **full** even when their bodies are empty. Validation still rejects an empty
2401
2405
  body for both types.
2402
2406
 
2407
+ Nonempty `data.words` on a language, or `data.glossary` on a culture or
2408
+ affiliation, supplies a generated Dictionary or Glossary page. These notes
2409
+ need no authored body. A nonempty authored body still follows the placeholder
2410
+ and short-prose rules.
2411
+
2403
2412
  Every type in the vocabulary declares whether an empty body suppresses its page,
2404
2413
  so adding a type means answering the question rather than inheriting a default.
2405
2414
 
@@ -2446,8 +2455,8 @@ any note they do not own, with no finding.
2446
2455
 
2447
2456
  **Prose is untouched by this.** A body with content still compiles into one
2448
2457
  JournalEntry, one web page and one PDF page, however many blocks the note
2449
- carries and whether or not it carries any; an empty body still compiles none of
2450
- the three. So a note has three states, and each reaches the next by one edit in
2458
+ carries and whether or not it carries any; without automatic lexical content,
2459
+ an empty body compiles none of the three. For these notes, each state reaches the next by one edit in
2451
2460
  one file, with its address, its id, its index record and every link into it
2452
2461
  unchanged:
2453
2462
 
@@ -3244,12 +3253,12 @@ value containing spaces with double quotes and escape an internal quote as
3244
3253
  `\"`. Boolean values are exactly `true` or `false`; other spellings are
3245
3254
  errors. Duplicate and unknown attributes are errors.
3246
3255
 
3247
- | Attribute | What it does |
3248
- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
3249
- | `allow-empty=true` | Permits a query selecting no rows. Default `false`. |
3250
- | `section-level=1` through `section-level=6` | Sets the heading level for `_section`. Default `2`. |
3251
- | `key=false` | Leaves the key out of a dictionary or a glossary. Default `true`. Refused on a table, as `key=true` is. |
3252
- | `key=only` | Prints a dictionary's or a glossary's key for its rows, and no letter heading or entry. Refused on a table. |
3256
+ | Attribute | What it does |
3257
+ | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
3258
+ | `allow-empty=true` | Permits a query selecting no rows. Default `false`. |
3259
+ | `section-level=1` through `section-level=6` | Sets the heading level for `_section`. Default `2`. |
3260
+ | `key=false` | Omits the key and any dictionary verb head table, retaining entries. Default `true`. Refused on a table, as `key=true` is. |
3261
+ | `key=only` | Prints a dictionary's or a glossary's key for its rows, and no letter heading or entry. Refused on a table. |
3253
3262
 
3254
3263
  ##### Page lists
3255
3264
 
@@ -3534,7 +3543,10 @@ A `follows[].event` resolves to exactly one event: a note holding one event, or
3534
3543
 
3535
3544
  #### Generated sections
3536
3545
 
3537
- The build appends sections to the end of a note's body, after everything the author wrote, each an H1 with a fixed anchor holding Markdown an author could have written. Every surface sets one as it sets an authored section: a page of the Foundry journal, a section of the website page listed in its table of contents, a section of the book.
3546
+ The build supplies sections from a note's frontmatter and the content
3547
+ relationships around it. Every surface receives the same text: the Foundry
3548
+ journal, the website and the book. Relationship lists and event views follow
3549
+ the authored text as H1 sections with fixed anchors, in this order:
3538
3550
 
3539
3551
  | Section | Anchor | On | Content |
3540
3552
  | ----------------- | ---------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
@@ -3548,13 +3560,23 @@ The build appends sections to the end of a note's body, after everything the aut
3548
3560
  | In song and story | `insongandstory` | any note | the `literature` works whose `data.subjects` name the note or one of its events, as list entries with each work's `data.form` |
3549
3561
  | From here | `fromhere` | a `place` that states, or is named in, a border or route | the map drawn from the place, as an image |
3550
3562
 
3551
- - **Sections follow the author's text in the order of the table.**
3563
+ - **Relationship and event sections follow the author's text in the table's order.**
3552
3564
  - **A section with nothing to show is not generated.**
3553
- - **An author's own section replaces a generated one.** A note whose body declares a prose anchor with the section's slug — `# Within {#within}`, or a block or span with that `id` — gets no generated section for it, and its own section is left exactly as written. This is the one way to turn a section off, and the way to choose different contents for it.
3554
- - **An entry is a link to the note it names**, written `[[<address>|]]` so each surface resolves it and shows the note's current name. An entry naming a stub, which publishes no page, is its name as plain text. The lists take in the places, affiliations and works a fetched index carries.
3565
+ - **An author's own relationship or event section replaces its generated one.** A note whose body declares a prose anchor with the section's slug — `# Within {#within}`, or a block or span with that `id` — gets no generated section for it, and its own section is left exactly as written. This is the one way to turn a section off, and the way to choose different contents for it.
3566
+ - **A relationship list entry links to the note it names**, written `[[<address>|]]` so each surface resolves it and shows the note's current name. An entry naming a stub, which publishes no page, is its name as plain text. The lists take in the places, affiliations and works a fetched index carries.
3555
3567
  - **The map is a drawing the build makes**, named `generated/from-<shortcode>.svg`. The website sets it inline so its place names are links, the Foundry compile stages it into the module at `assets/generated/`, and the book draws it beside its source. `generated/` is the build's: an authored image addressed there is an error. `site.maps: false` gives no place the section.
3556
3568
  - A stub publishes no page and is given no section.
3557
3569
 
3570
+ **Dictionary and Glossary sections come from the owner's declarations.** A
3571
+ language with nonempty `data.words` receives its full alphabetical dictionary,
3572
+ with letter headings, field tags and one key. A culture or affiliation with
3573
+ nonempty `data.glossary` receives only its declared entries, including an
3574
+ explicitly named rank or office. An absent or empty declaration produces no
3575
+ section. An authored `{#dictionary}` or `{#lexicon}` heading receives the
3576
+ Dictionary list after its introduction, and `{#glossary}` does the same for a
3577
+ Glossary list. Without that heading, the build appends the section at the end
3578
+ of the note. See [dictionaries and glossaries](#dictionaries-and-glossaries).
3579
+
3558
3580
  #### Event views
3559
3581
 
3560
3582
  The build appends sections to the end of a note's body that list the events concerning it — a region's chronology, the events a being took part in, the accounts a people gives, what followed an event. Each is an H1 with a fixed anchor holding a `sql` fence over the `events` relation, the same Markdown an author could write, so every surface sets it as it sets an authored section: a page of the Foundry journal, a section of the website page in its table of contents, a section of the book.
@@ -4800,9 +4822,9 @@ rank names the standing, and the standing says.
4800
4822
  | `language` | `Address` | The trade, temple or order tongue it keeps, naming a skill note with `subType: language` |
4801
4823
  | `glossary` | `{ name, name_sort?, common?, definition?, pronunciation?, language? }[]` | Its own glossary terms — see [glossary terms](#glossary-terms) |
4802
4824
  | `glossary[].name` | `string`, required | The headword |
4803
- | `glossary[].name_sort` | `string` | Its sort key; the name when unstated |
4804
- | `glossary[].common` | `boolean` | `true` for a word a player is expected to know by heart; `false` when unstated |
4805
- | `glossary[].definition` | `string` | The sense text; stated, it creates the term or replaces every sense its other sources give |
4825
+ | `glossary[].name_sort` | `string` | Its sort key; the matching word's, else the name, when unstated |
4826
+ | `glossary[].common` | `boolean` | `true` for a term in this owner's core vocabulary; `false` when unstated |
4827
+ | `glossary[].definition` | `string` | Its context meaning or own gloss; unstated, a matching dictionary word supplies its senses |
4806
4828
  | `glossary[].pronunciation` | `string` | A respelling, as `sol-MEH-reh`: letters, apostrophes and hyphens, at most one syllable in capitals |
4807
4829
  | `glossary[].language` | `Address` | The language the term is in, naming a skill note with `subType: language`; unstated, the affiliation's, its parents' or its culture's |
4808
4830
  | `relations` | `Map<Address, Standing>` | Standing with other affiliations, keyed by the other body's Address |
@@ -4816,14 +4838,14 @@ together with every place whose `data.government` names it. See
4816
4838
 
4817
4839
  **An affiliation may keep a tongue of its own.** A trade cant, a temple
4818
4840
  language or an order's tongue is named in the affiliation's `data.language`, and
4819
- it reaches the affiliation's culture: its words belong to that culture's
4820
- glossary as much as the words of the tongue the culture names itself. It is
4821
- also the language of the affiliation's own [glossary terms](#glossary-terms)
4822
- where an entry names none. In a tree that holds at least one culture note, an
4841
+ it supplies the language of the affiliation's own
4842
+ [glossary terms](#glossary-terms) where an entry names none. A culture can
4843
+ select a word of that tongue for its own glossary by naming the language on
4844
+ the entry. In a tree that holds at least one culture note, an
4823
4845
  affiliation that reaches no culture — naming none, inheriting none through
4824
4846
  `data.parents`, and, for a `polity`, taking none from its places — is a warning
4825
- at its `type:` line, because its ranks, offices and tongue enter no culture's
4826
- glossary.
4847
+ at its `type:` line, because its ranks and offices have no culture associations
4848
+ for term queries.
4827
4849
 
4828
4850
  A language needs no culture and no affiliation. A dead language, or one kept
4829
4851
  only by a church, is a language note like any other, and nothing requires a
@@ -5317,15 +5339,29 @@ SoHL sets `system.quantity` to `1` for each compendium item.
5317
5339
  | `names.<name>` | `string[]` | A list the placeholder of the same name draws from |
5318
5340
  | `family` | `Address` | `language` only: the parent language, naming a skill note with `subType: language`; this language reads the parent's words as its own — see [a language's words](#a-languages-words) |
5319
5341
  | `abbreviation` | `string` | `language` only: the tag a dictionary prints for it, as `Prov.`; its full name where unstated — see [dictionaries and glossaries](#dictionaries-and-glossaries) |
5342
+ | `grammar` | `{ plural?, verbs? }` | Optional dictionary noun plurals and one verb pattern; supplied shapes only are checked |
5343
+ | `grammar.plural` | `{ ending, becomes }[]` | Literal suffix replacements in authored order; the first match wins |
5344
+ | `grammar.plural[].ending` | `string`, required, may be empty | Bare suffix to replace; empty matches every noun |
5345
+ | `grammar.plural[].becomes` | `string`, required, may be empty | Bare replacement; empty deletes the matching suffix |
5346
+ | `grammar.verbs` | `{ invariant: true }` or `{ persons: { I, you, heShe, we, youAll, they } }` | One regular present pattern, printed once at the dictionary head |
5347
+ | `grammar.verbs.invariant` | `true` | Verbs do not change; excludes `persons` |
5348
+ | `grammar.verbs.persons` | a map of all six ending strings | Each ending is added to the citation form; excludes `invariant` |
5349
+ | `grammar.verbs.persons.I` | `string`, required, may be empty | Ending for I |
5350
+ | `grammar.verbs.persons.you` | `string`, required, may be empty | Ending for you |
5351
+ | `grammar.verbs.persons.heShe` | `string`, required, may be empty | Ending for he/she |
5352
+ | `grammar.verbs.persons.we` | `string`, required, may be empty | Ending for we |
5353
+ | `grammar.verbs.persons.youAll` | `string`, required, may be empty | Ending for you all |
5354
+ | `grammar.verbs.persons.they` | `string`, required, may be empty | Ending for they |
5320
5355
  | `classModifiers` | `string[]` | `language` only: the word class modifiers the language uses, each from the [master word classes](#word-classes); empty when unstated |
5321
5356
  | `fields` | `{ name, holds }[]` | `language` only: the fields its words are grouped under |
5322
5357
  | `fields[].name` | `string`, required | The field's name, which a word's `field` names |
5323
5358
  | `fields[].holds` | `string`, required | What the field holds |
5324
- | `words` | `{ form, class, field, gloss, … }[]` | `language` only: its words, one map each, in the order they print — see [a language's words](#a-languages-words) |
5359
+ | `words` | `{ form, class, field, gloss, … }[]` | `language` only: its words in authored order; its automatic dictionary sorts them alphabetically — see [a language's words](#a-languages-words) |
5325
5360
  | `words[].form` | `string`, required | The word as cited, bare: no backticks |
5326
5361
  | `words[].variants` | `string[]` | Its other forms, as a short form beside a long one; a marked use of one cites the word |
5327
5362
  | `words[].name_sort` | `string` | Its sort key; the form when unstated |
5328
5363
  | `words[].class` | `string`, required | A class from the master word classes, base first: `n I f` |
5364
+ | `words[].plural` | `string` | Optional explicit noun plural; the dictionary uses it before the language rule |
5329
5365
  | `words[].field` | `string`, required | One of the note's `fields` names |
5330
5366
  | `words[].gloss` | `string` or `string[]`, required | The meaning, in brief; a list states one sense per entry, which a dictionary numbers |
5331
5367
  | `words[].source` | `{ kind, language?, form? }` | Where the word comes from |
@@ -5539,6 +5575,7 @@ data:
5539
5575
  - {
5540
5576
  form: solmère,
5541
5577
  class: n m,
5578
+ pronunciation: sol-MEH-reh,
5542
5579
  field: Love and its conduct,
5543
5580
  gloss: "longing; the ache for a person, a place or a time that is gone",
5544
5581
  source: { kind: borrowed, language: skill-elvndrlng, form: sólmerë },
@@ -5563,15 +5600,67 @@ so a language's words, however many, add nothing to it.
5563
5600
  class I, feminine. A language declares the modifiers it uses in
5564
5601
  `data.classModifiers`, and a word may carry only those.
5565
5602
 
5603
+ ##### Optional noun and verb forms
5604
+
5605
+ A noun may carry gender through its existing class: `n m`, `n f` or `n n`,
5606
+ printed as _n. m._, _n. f._ or _n. nt._. It may state `plural` where its
5607
+ plural differs from the language's default. Neither is required.
5608
+
5609
+ ```yaml
5610
+ data:
5611
+ classModifiers: [m]
5612
+ fields:
5613
+ - { name: People, holds: People and their everyday words }
5614
+ grammar:
5615
+ plural:
5616
+ - { ending: os, becomes: oi }
5617
+ verbs:
5618
+ persons: { I: o, you: es, heShe: "", we: om, youAll: et, they: on }
5619
+ words:
5620
+ - { form: marendos, class: n m, field: People, gloss: an example noun }
5621
+ ```
5622
+
5623
+ The dictionary entry begins **marendos** _n. m., pl. marendoi_. An entry's
5624
+ nonempty explicit `plural` wins; otherwise the first matching
5625
+ `grammar.plural` replacement supplies its noun plural. Endings are bare,
5626
+ literal strings: `os` replaces the closing letters, with no regular
5627
+ expression or hyphen notation. An empty `ending` appends `becomes`; an empty
5628
+ `becomes` removes the ending. A noun matching no rule prints no plural.
5629
+ The raw `words` relation retains only the authored `plural`; the
5630
+ `dictionary` relation carries the displayed one.
5631
+
5632
+ `grammar.verbs` is either `{ invariant: true }`, where no verb changes, or
5633
+ the `persons` map shown above. A supplied `persons` map has all six string
5634
+ endings, each added to the citation form; `""` leaves that form unchanged.
5635
+ The dictionary prints the pattern once in a small table before its letter
5636
+ headings. A custom dictionary's default or `key=true` prints that table even
5637
+ when no abbreviation key is needed. `key=false` fragments omit both the key
5638
+ and table; `key=only` prints the abbreviation key alone. Separate results
5639
+ with their heads enabled each print their own tables.
5640
+ A language uses only its own stated grammar, including for words
5641
+ listed from an ancestor; an inherited word retains its explicit plural.
5642
+ Grammar is not inherited through `family`.
5643
+
5644
+ All grammar is optional. Only a supplied key's shape is checked: no language
5645
+ must supply a pattern, no noun must supply gender or plural, and no word is
5646
+ checked against a rule or required to provide an exception. There are no
5647
+ additional cases, tenses, moods or irregular verb forms. With none of these
5648
+ optional fields, dictionary output is unchanged. Grammar alone does not
5649
+ create a Dictionary section.
5650
+
5566
5651
  **A word's source** is closed to seven kinds. `borrowed` names the language the
5567
5652
  word came from in `language`, a language Address; `inherited`, `kept` and
5568
5653
  `worn` give the ancient `form` where the note knows it; `coined`, `substrate`
5569
5654
  and `island` give neither. A form is written bare: a renderer supplies its own
5570
5655
  italics and its own asterisk.
5571
5656
 
5572
- **`built` names the pieces a word is made of**, each as a word or an affix of
5573
- the same language writes it, stems included. A piece written with different
5574
- joining hyphens still matches (`am-` finds the word `am`).
5657
+ **`built` names the pieces a word is made of**. Each piece resolves against
5658
+ words, then affixes, then elements of its language, followed by each ancestor
5659
+ in `data.family` order. An element matches its `form` or an entry in `variants`
5660
+ and supplies its `sense` as the gloss. A piece written with different joining
5661
+ hyphens still matches (`am-` finds the word `am`); an exact spelling is checked
5662
+ first. An affix also matches its declared front-vowel form, `front`. Case and
5663
+ accents remain significant.
5575
5664
 
5576
5665
  **A gloss is one sense or a list of them.** A list states one sense per entry,
5577
5666
  and a dictionary numbers them: `zethu` glossed `[writing, a scribe]` prints
@@ -5636,7 +5725,7 @@ Each finding is located at the key at fault:
5636
5725
  | A language Address naming something other than a language skill | error |
5637
5726
  | A pronunciation that is not a respelling | error |
5638
5727
  | A `frame` that no `sounds.frames` of the language or an ancestor names | error |
5639
- | A `built` piece no word or affix of the language glosses | warning |
5728
+ | A `built` piece no word, affix or element in its lineage glosses | warning |
5640
5729
 
5641
5730
  The `words` relation holds one row per word — see
5642
5731
  [Content tables](#content-tables) — and a table of them is an `sql` fence over
@@ -6216,7 +6305,7 @@ not a different cultural identity. See
6216
6305
  | `form` | `string` | `literature` only: the kind of work in its people's own terms — `epic`, `saga`, `praise-song`, `elegy`. Free text |
6217
6306
  | `subjects` | `Address[]` | `literature` only: the beings, places, gods and other notes the work concerns, and any event, as `note#id` |
6218
6307
  | `parents` | `Address[]` | `culture` only: the larger cultures this one belongs to; each target is a culture lore note — see [culture parents](#culture-parents-and-inherited-fields) |
6219
- | `language` | `Address` | `literature` and `culture` only: the tongue a work is composed in, or a culture's people speak, naming a skill note with `subType: language`; `package-build npc new` draws a culture's names from that language's [name lists](#name-lists), and the words of that language belong to the culture's glossary |
6308
+ | `language` | `Address` | `literature` and `culture` only: the tongue a work is composed in, or a culture's people speak, naming a skill note with `subType: language`; `package-build npc new` draws a culture's names from that language's [name lists](#name-lists); glossary entries whose own `language` is unstated resolve to it |
6220
6309
  | `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
6221
6310
  | `appearanceProfile` | `{ frame, eye_color, hair_color, skin_color, complexion, height }` | `culture` only: what its people look like, for `package-build npc new` — see [appearance profiles](#appearance-profiles) |
6222
6311
  | `appearanceProfile.frame` | map of `frame` words to positive weights, required | How often each frame is drawn |
@@ -6229,9 +6318,9 @@ not a different cultural identity. See
6229
6318
  | `appearanceProfile.height.<name>.max` | height in metres or feet and inches, required | The tallest height drawn for that gender |
6230
6319
  | `glossary` | `{ name, name_sort?, common?, definition?, pronunciation?, language? }[]` | `culture` only: the culture's own glossary terms — see [glossary terms](#glossary-terms) |
6231
6320
  | `glossary[].name` | `string`, required | The headword |
6232
- | `glossary[].name_sort` | `string` | Its sort key; the name when unstated |
6233
- | `glossary[].common` | `boolean` | `true` for a word a player is expected to know by heart; `false` when unstated |
6234
- | `glossary[].definition` | `string` | The sense text; stated, it creates the term or replaces every sense its other sources give |
6321
+ | `glossary[].name_sort` | `string` | Its sort key; the matching word's, else the name, when unstated |
6322
+ | `glossary[].common` | `boolean` | `true` for a term in this owner's core vocabulary; `false` when unstated |
6323
+ | `glossary[].definition` | `string` | Its context meaning or own gloss; unstated, a matching dictionary word supplies its senses |
6235
6324
  | `glossary[].pronunciation` | `string` | A respelling, as `sol-MEH-reh`: letters, apostrophes and hyphens, at most one syllable in capitals |
6236
6325
  | `glossary[].language` | `Address` | The language the term is in, naming a skill note with `subType: language`; unstated, the note's language |
6237
6326
 
@@ -6239,54 +6328,74 @@ not a different cultural identity. See
6239
6328
 
6240
6329
  #### Glossary terms
6241
6330
 
6242
- A culture and an affiliation each state their own glossary terms in
6243
- `data.glossary`: the terms that belong to the people or the members who use
6244
- them rather than to a language's grammar — euphemisms, idioms, terms of art,
6245
- and titles that are not ranks. A culture's glossary draws on three sources: the
6246
- words of every language that reaches it — its own `data.language`, and the
6247
- `data.language` of each affiliation whose culture it is — the ranks and offices
6248
- of those affiliations, and the culture's own `data.glossary`. An affiliation's
6249
- draws on its own ranks and offices, the words of its language, and its own
6250
- `data.glossary`. `data.glossary` is the primary source, and it is the only one
6251
- the note writes:
6331
+ **A dictionary belongs to a language; a glossary belongs to a culture or an
6332
+ affiliation.** A language note with nonempty `data.words` receives its full Dictionary
6333
+ section automatically, with grammar, senses, etymology and pronunciation,
6334
+ field tags, letter headings and one key in a single alphabetical list. A
6335
+ culture or affiliation with nonempty `data.glossary` receives a Glossary section
6336
+ containing only its explicitly declared entries. Ranks and offices stand in
6337
+ the affiliation's own sections; the glossary selects one only through an
6338
+ explicit entry. A note without the relevant frontmatter receives no such
6339
+ section. These sections appear on the site, in the Foundry journal and in
6340
+ the book. Dictionaries and glossaries have no setting-wide pages.
6341
+
6342
+ A glossary entry belongs for one of three reasons:
6343
+
6344
+ 1. **A common word** is part of the owner's core vocabulary, the words a
6345
+ player needs to adventure there. It states `common: true` and takes the
6346
+ dictionary's senses when it gives no `definition`.
6347
+ 2. **A dictionary word with a context meaning** states that meaning in
6348
+ `definition`.
6349
+ 3. **A term outside the dictionary** — a phrase, a hyphenated compound or a
6350
+ term of art — states its gloss in `definition`.
6351
+
6352
+ `common` belongs to an entry in its owner's glossary. A culture and an
6353
+ affiliation using the same language choose independently: a word may be
6354
+ common in one glossary and absent from another. A language's dictionary
6355
+ marks nothing common.
6356
+
6357
+ This culture glossary uses the words from [the Provenzal language
6358
+ example](#a-languages-words). `solmère` is a common word with its dictionary
6359
+ sense, `amère` takes the context's song sense, and `blood-field` is a term
6360
+ outside the dictionary. `Knight-Captain` names a rank that reaches the
6361
+ culture:
6252
6362
 
6253
6363
  ```yaml
6364
+ shortcode: provenzianclt
6365
+ name: { full: Provenzia }
6254
6366
  type: lore
6255
6367
  subType: culture
6256
6368
  data:
6257
- language: skill-sinalelng
6369
+ language: skill-provnzlng
6258
6370
  glossary:
6259
- - { name: síladòr, common: true }
6260
- - { name: Knight-Captain, common: true }
6371
+ - { name: solmère, common: true }
6372
+ - { name: amère, definition: "a sweetheart, in the songs" }
6261
6373
  - {
6262
6374
  name: blood-field,
6263
6375
  definition: "ground where a battle tore the boundary with the spirit world, and it did not close",
6264
6376
  }
6265
- - { name: meet a man about a horse, definition: "to leave without saying why", common: true }
6377
+ - { name: Knight-Captain, common: true }
6266
6378
  ```
6267
6379
 
6268
- **An entry with a `definition` creates a term**, or replaces every sense the
6269
- term's other sources give it. **An entry without one changes no sense**: it marks
6270
- a term the note already has as common, gives it a sort key or a
6271
- pronunciation. A word of class `name`, `stem` or `pref` is no term, because
6272
- those classes stand in no glossary.
6380
+ **An entry naming a word of its resolved language, without a `definition`,
6381
+ carries that word's senses and class.** Its headword links to the word's
6382
+ entry in the language's dictionary. An entry with a `definition` carries that
6383
+ meaning instead, keeping its word link and class when it names a dictionary
6384
+ word.
6273
6385
 
6274
6386
  **Every entry resolves to a language**, and the first match wins:
6275
6387
 
6276
6388
  1. the entry's own `language`;
6277
- 2. the note it is written on, where that note is a language — which is how
6278
- every word in a language note's `data.words` is in that language;
6279
- 3. on an affiliation, its own `data.language`, then the nearest parent
6389
+ 2. on an affiliation, its own `data.language`, then the nearest parent
6280
6390
  affiliation's, nearest first and parents in the order `data.parents` lists
6281
6391
  them, then its culture's `data.language`;
6282
- 4. on a culture, its own `data.language`.
6392
+ 3. on a culture, its own `data.language`.
6283
6393
 
6284
6394
  An affiliation's culture is the one it states or inherits, as
6285
6395
  [Culture in the index](#culture-in-the-index) describes, and a culture's
6286
6396
  `data.language` includes one it inherits from its
6287
- [parent cultures](#culture-parents-and-inherited-fields). An idiom glossed in
6288
- the setting's common tongue, such as the last entry above, takes the culture's
6289
- language and is marked `common`.
6397
+ [parent cultures](#culture-parents-and-inherited-fields). An entry in another
6398
+ tongue names that language explicitly:
6290
6399
 
6291
6400
  ```yaml
6292
6401
  # Affiliations/Wardens.md — an order with a cant of its own
@@ -6310,76 +6419,114 @@ Each finding is located at the entry's key:
6310
6419
  - An entry that resolves to no language is an error at the entry: state its
6311
6420
  `language`, or `data.language` on the note.
6312
6421
  - An entry's `language` that names no language skill is an error at the value.
6313
- - An entry with no `definition` whose name is no word, rank or office of the
6314
- note is an error at its `name`: it names nothing.
6422
+ - An entry with no `definition` naming neither a word of its resolved
6423
+ language, including inherited words, nor a rank or office that reaches its
6424
+ owner is an error at its `name`. State the word's `language`, or give the
6425
+ term its own `definition`.
6315
6426
  - A pronunciation that is not a respelling is an error at the value.
6316
6427
  - A `definition` that only repeats the one sense it replaces is a warning at the
6317
6428
  definition, because the entry changes nothing.
6318
6429
 
6319
- The `glossary` relation holds one row per entry, with the language it resolves
6320
- to — see [Content tables](#content-tables).
6430
+ The `glossary` relation holds one row per entry as authored, with the language
6431
+ it resolves to. The `terms` relation supplies its senses and class for a
6432
+ `layout=glossary` fence — see [Content tables](#content-tables).
6321
6433
 
6322
6434
  #### Dictionaries and glossaries
6323
6435
 
6324
- Two relations hold what a dictionary and a glossary set, and the query that
6325
- reads them decides what a page shows. **A dictionary sets words**: the words
6326
- of language notes, each with a class, an etymology, its senses and its
6327
- citations. **A glossary sets terms**: the `data.glossary` entries of cultures
6328
- and affiliations, and the ranks and offices of affiliations, each sense tagged
6329
- with the body or culture it comes from, and none with a class. Any note may
6330
- carry either kind of fence, with any `WHERE` clause — see
6331
- [dictionaries and glossaries](../authoring/links-and-markup.md#dictionaries-and-glossaries)
6332
- for the layouts and the queries.
6436
+ **A language's dictionary sets its words**, with their class, field,
6437
+ etymology, pronunciation, senses and citations. A language note with
6438
+ `data.words` receives that full dictionary automatically as one alphabetical
6439
+ list, with letter headings and one key. **A culture's or an affiliation's
6440
+ Glossary section sets its explicit `data.glossary` entries only**: common
6441
+ words, dictionary words with a context meaning, and phrases, compounds or
6442
+ terms of art with their own glosses. A note with absent or empty `data.words` or
6443
+ `data.glossary`, respectively, receives no such section. The site, Foundry
6444
+ journals and the book show the same sections.
6445
+
6446
+ An authored heading with `{#dictionary}` or `{#lexicon}` receives the
6447
+ Dictionary list after its authored text; `{#glossary}` does the same for a
6448
+ Glossary list. The heading and its introduction stay in place, with a single
6449
+ list under it. Otherwise the build appends a **Dictionary** or **Glossary**
6450
+ heading and its entries at the end of the note. There are no setting-wide
6451
+ dictionary or glossary pages.
6452
+
6453
+ `layout=dictionary` and `layout=glossary` remain available for custom SQL
6454
+ views of the same relations. The `terms` relation holds governance rows as
6455
+ well as declared glossary entries; the default Glossary section selects only
6456
+ the owner's explicitly declared entries. See [dictionaries and
6457
+ glossaries](../authoring/links-and-markup.md#dictionaries-and-glossaries) for
6458
+ the layouts and custom queries.
6333
6459
 
6334
6460
  **`dictionary`** is one row per word per language it is listed under. A
6335
6461
  language lists its own words at `depth` 0 and the words it inherits through
6336
- `data.family` above that, nearest first, so `WHERE language = '<Address>'` is a
6337
- language's whole word list, and `WHERE depth = 0` lists every word once, under
6338
- the language that states it. Where a daughter and a parent state the same
6462
+ `data.family` above that, nearest first, so `WHERE language = '<Address>'` is
6463
+ that language's full dictionary. Where a daughter and a parent state the same
6339
6464
  form, the daughter's own word is the one listed. Words of class `name`, `stem`
6340
- and `pref` are no entry.
6465
+ and `pref` are no entry. Nonempty `data.words` containing only these classes
6466
+ still supplies the Dictionary heading, with no entries or key; a stated verb
6467
+ pattern still supplies its head table. A word's sort
6468
+ key and pronunciation come from its declaration; a glossary's choices belong
6469
+ to its own entries.
6341
6470
 
6342
6471
  | Column | What it holds |
6343
6472
  | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
6344
6473
  | `language` | The language the word is listed under. |
6345
6474
  | `language_tag` | That language note's `data.abbreviation`, or its full name where it states none. |
6346
6475
  | `name` | The word's form. |
6347
- | `name_sort` | Its sort key: a glossary entry's that names it, else the word's, else the form. |
6476
+ | `name_sort` | The word's sort key, or its form where unstated. |
6348
6477
  | `letter` | The heading letter: the first letter of `name_sort`, accents taken off and apostrophes skipped, in capitals. |
6349
- | `pronunciation` | A glossary entry's that names it, else the word's; `NULL` where neither states one. |
6478
+ | `pronunciation` | The word's respelling; `NULL` where unstated. |
6350
6479
  | `class` | The word's class, as written. |
6480
+ | `plural` | The noun's explicit plural, else its listed language's first matching replacement; `NULL` where unavailable or not a noun. |
6481
+ | `field` | The word's field, printed as a tag beside the entry; `NULL` where unstated. |
6351
6482
  | `etymology` | `{ kind, language, language_tag, form, parts, root, frame }` from the word's `source`, `built`, `root` and `frame`; an inherited word's is `inherited` from the language that states it. `NULL` where there is none. |
6352
6483
  | `senses` | A list of `{ text, bodies }`: one per sense of the word's gloss, with no bodies. A dictionary numbers a word's senses where it has more than one. |
6353
6484
  | `usage` | The Addresses of the notes whose prose cites the word, as the language that states it records them. |
6354
- | `common` | Whether a glossary entry that names the word marks it a word a player is expected to know by heart. |
6485
+ | `verbs` | The listed language's stated `{ invariant: true }` or six-person pattern, repeated as metadata for one head table; `NULL` where unstated. |
6355
6486
  | `depth` | How far up the language's lineage the word is stated: `0` for its own. |
6356
6487
 
6488
+ A daughter language with no own words has no automatic Dictionary section.
6489
+ A glossary word in that resolved language links to its visible defining
6490
+ ancestor's dictionary entry. The glossary's `language` remains the resolved
6491
+ daughter language.
6492
+
6357
6493
  **`terms`** is one row per term per note that owns it: an entry of a culture's
6358
6494
  or an affiliation's `data.glossary`, or an affiliation's rank or office.
6359
6495
 
6360
- | Column | What it holds |
6361
- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
6362
- | `owner` | The Address of the culture or affiliation that owns the term. |
6363
- | `owner_kind` | `culture` or `affiliation`. |
6364
- | `language` | The language the term is in: a glossary entry's, as it resolves; a rank's or office's, the language its body's glossary resolves to. `NULL` where none resolves. |
6365
- | `language_tag` | That language note's `data.abbreviation`, or its full name where it states none. |
6366
- | `name` | The headword. |
6367
- | `name_sort` | Its sort key: a glossary entry's, else the name. |
6368
- | `letter` | The heading letter, as for a word. |
6369
- | `pronunciation` | A glossary entry's; `NULL` where none states one. |
6370
- | `senses` | A list of `{ text, bodies }`, each sense naming the owner. |
6371
- | `usage` | The Addresses the term is cited from: a rank's body and every being at that level, an office's body, holders and every being holding it, an entry's owner. |
6372
- | `common` | Whether a glossary entry marks it a word a player is expected to know by heart. |
6373
- | `origins` | Which sources gave it: `rank`, `office`, `glossary`. |
6374
- | `cultures` | Every culture the term reaches, as a list of Addresses. |
6496
+ | Column | What it holds |
6497
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
6498
+ | `owner` | The Address of the culture or affiliation that owns the term. |
6499
+ | `owner_kind` | `culture` or `affiliation`. |
6500
+ | `language` | The language the term is in: a glossary entry's, as it resolves; a rank's or office's, the language its body's glossary resolves to. `NULL` where none resolves. |
6501
+ | `language_tag` | That language note's `data.abbreviation`, or its full name where it states none. |
6502
+ | `name` | The headword. |
6503
+ | `name_sort` | The glossary entry's sort key, else the dictionary word's, else the headword. |
6504
+ | `letter` | The heading letter, as for a word. |
6505
+ | `pronunciation` | The glossary entry's respelling, else the dictionary word's; `NULL` where neither states one. |
6506
+ | `class` | The matching dictionary word's class, as written; `NULL` where no word matches. |
6507
+ | `word` | The matching word's anchored dictionary entry: the resolved language's when it has own words, else the visible defining language's; `NULL` where no word matches. |
6508
+ | `senses` | A list of `{ text, bodies }`: a dictionary word's gloss senses with no bodies, or the entry's definition with its owner, or a rank's or office's descriptions with their bodies. |
6509
+ | `usage` | Citation Addresses: governance usage, inherited dictionary usage or the defining owner; a copied reached title also cites its selecting owner. |
6510
+ | `common` | Whether this owner's glossary entry marks the term part of its core vocabulary. |
6511
+ | `origins` | Which sources gave it: `rank`, `office`, `glossary`. |
6512
+ | `cultures` | The cultures associated through the owner and its parents, as a list of Addresses for selecting reached ranks and offices. |
6513
+
6514
+ A standalone word entry without a definition uses the dictionary's
6515
+ citations; an explicit term cites its owner. A rank or office keeps its
6516
+ body's and members' or holders' citations, including when its owner's
6517
+ glossary names a matching word or supplies a definition. An owner selecting
6518
+ a reached title also joins its own Address to that title's citations.
6375
6519
 
6376
6520
  **A term reaches the cultures its owner reaches.** A culture's own terms reach
6377
6521
  the culture. An affiliation's terms — its ranks, its offices and its own
6378
6522
  glossary entries alike — reach its culture, its own or one the index resolves
6379
6523
  for it, and the culture of every affiliation above it through `data.parents`.
6380
- A culture's glossary is therefore `WHERE list_contains(cultures, '<Address>')`,
6381
- and an affiliation's is `WHERE owner = '<Address>'`. An affiliation that
6382
- reaches no culture has an empty list.
6524
+ `cultures` records those associations for custom queries. The default
6525
+ Glossary section selects its own owner's declared `data.glossary` entries;
6526
+ it adds no other rows from this reach. A custom view that includes reached
6527
+ governance rows can select `origins` containing `rank` or `office` and prints
6528
+ `common` only for the owner's own rows. An affiliation that reaches no culture
6529
+ has an empty list.
6383
6530
 
6384
6531
  **A rank and an office of one title in one body are one row**, the rank's
6385
6532
  sense first, and where their descriptions are identical, one sense.
@@ -6390,23 +6537,22 @@ of a culture it reaches, names it, or where it is a word of its language,
6390
6537
  compared without case. A title of several words, as `Knight-Captain` or
6391
6538
  `Lord Steward`, always is.
6392
6539
 
6393
- **A glossary entry with a `definition`** replaces the senses of its owner's own
6540
+ **A glossary entry with a `definition`** carries that definition instead of a
6541
+ matching dictionary word's senses. It replaces the senses of its owner's own
6394
6542
  rank or office of that name. Otherwise it is a term of its owner's own, cited
6395
6543
  from the owner, so a culture's definition of a rank one of its affiliations
6396
- holds is a second row beside the rank's, and a glossary of that culture sets
6397
- both senses under one headword.
6398
-
6399
- **A glossary entry without a `definition`** changes no sense. It marks what it
6400
- names: the word or the rank or office of its name in the language it resolves
6401
- to, among what reaches its note — for a culture, the words of its language and
6402
- of each affiliation's language, and the ranks and offices of the affiliations
6403
- that reach it; for an affiliation, its own ranks and offices and the words of
6404
- its language — and failing that, the one of its name in any language that
6405
- reaches the note. Names are compared after NFC normalisation, with case kept.
6406
- Marking sets `common`, and replaces `name_sort` and `pronunciation`, on the
6407
- word's row in that language or on the rank's or office's row, and lets a
6408
- one-word title in. Where several entries state one of these, the first in the
6409
- order of the owner's Address wins.
6544
+ holds is a second row beside the rank's. A glossary of that culture combines
6545
+ the senses under one headword where the rows share a language.
6546
+
6547
+ **A glossary entry without a `definition`** names a word of its resolved
6548
+ language, or a rank or office that reaches its owner. A dictionary word gives
6549
+ the entry all its senses, its class and a link to its entry on the language
6550
+ page; a rank or office gives its descriptions. Where the owner has a rank or
6551
+ office of the same title as the word, its distinct descriptions follow the
6552
+ dictionary senses. The glossary entry can state its own `name_sort` or
6553
+ `pronunciation`. Names are compared after NFC normalisation, with case kept. Its `common` value belongs to its owner, so a
6554
+ culture entry naming an affiliation's rank does not mark the affiliation's
6555
+ entry common. Naming the rank also admits a title of one word.
6410
6556
 
6411
6557
  **The datafiles.** `package-build content-index` writes each relation beside
6412
6558
  the index: `<package>-dictionary.jsonl`, sorted by `language`, `name_sort` and
@@ -7358,7 +7504,7 @@ the map for the pack it is writing and falls back to `default` when there is no
7358
7504
  such key, so a mistyped `journal:` files the folder wherever the default puts it
7359
7505
  — exactly the hierarchy the key was written to override, and silently.
7360
7506
 
7361
- **A folder note requires a body**, like every typed note. Its body does not
7507
+ **A folder note requires a body.** Its body does not
7362
7508
  produce a documentation journal or take part in `docEntryTypes`.
7363
7509
  In a compiled Foundry journal, a wikilink to a folder prints its label as text:
7364
7510
  the folder can materialise in several packs and has no single compendium UUID.