@heroiclands/package-build 25.5.4 → 25.6.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 (108) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +7 -0
  3. package/assets/styles/content-base.css +1 -1
  4. package/bin/content-commands.mjs +32 -8
  5. package/docs/api.md +81 -32
  6. package/docs/authoring/frontmatter.md +1 -1
  7. package/docs/authoring/links-and-markup.md +59 -10
  8. package/docs/commands.md +60 -17
  9. package/docs/configuration.md +3 -2
  10. package/docs/content-format.md +50 -1
  11. package/docs/diagnostics.md +17 -0
  12. package/docs/guides/module-project.md +11 -3
  13. package/docs/guides/reference-pages.md +4 -1
  14. package/docs/guides/site.md +13 -3
  15. package/docs/guides/writing-in-invented-scripts.md +5 -2
  16. package/docs/reference/format-details.md +233 -138
  17. package/docs/reference/note-types.md +165 -152
  18. package/docs/reference/theme-pages.md +1 -0
  19. package/e2e.mjs +1 -1
  20. package/engine/base-compiler.mjs +2 -0
  21. package/engine/compile-corpus.mjs +6 -2
  22. package/engine/content-charset.mjs +1 -1
  23. package/engine/content-format.yaml +9 -7
  24. package/engine/content-html.mjs +3 -2
  25. package/engine/content-index.mjs +23 -0
  26. package/engine/content-links.mjs +8 -0
  27. package/engine/content-render.mjs +14 -2
  28. package/engine/content-scripts.mjs +44 -6
  29. package/engine/content-session.mjs +11 -7
  30. package/engine/content-spans.mjs +3 -4
  31. package/engine/content-tables.mjs +12 -5
  32. package/engine/content-verse.mjs +52 -10
  33. package/engine/core-report.mjs +27 -18
  34. package/engine/culture-reach.mjs +3 -0
  35. package/engine/declared-sections.mjs +100 -0
  36. package/engine/derived-sections.mjs +36 -2
  37. package/engine/dictionary-rows.mjs +2 -1
  38. package/engine/generated-sections.mjs +2 -0
  39. package/engine/holdings.mjs +107 -3
  40. package/engine/index-records.mjs +3 -1
  41. package/engine/index.mjs +1 -1
  42. package/engine/language-data.mjs +0 -1
  43. package/engine/language-names.mjs +53 -23
  44. package/engine/language-rows.mjs +1 -3
  45. package/engine/language-terms.mjs +7 -10
  46. package/engine/map-dot.mjs +22 -0
  47. package/engine/markdown-blocks.mjs +23 -8
  48. package/engine/markdownlint-run.mjs +1 -1
  49. package/engine/markup-validation.mjs +2 -0
  50. package/engine/metadata-index.mjs +1 -0
  51. package/engine/note-addresses.mjs +16 -0
  52. package/engine/note-vocabulary.mjs +29 -13
  53. package/engine/npc-generate.mjs +52 -7
  54. package/engine/office-holders.mjs +76 -0
  55. package/engine/page-breaks.mjs +143 -0
  56. package/engine/pdf-build.mjs +12 -4
  57. package/engine/pdf-render.mjs +12 -2
  58. package/engine/place-kinds.mjs +106 -0
  59. package/engine/preview-index.mjs +4 -2
  60. package/engine/settlement-tables.mjs +410 -675
  61. package/engine/settlement-terms.mjs +118 -0
  62. package/engine/site-build.mjs +14 -7
  63. package/engine/site-preview.mjs +3 -0
  64. package/engine/site-render.mjs +18 -4
  65. package/engine/site-root.mjs +10 -1
  66. package/engine/site-serve-http.mjs +151 -0
  67. package/engine/site-serve.mjs +196 -126
  68. package/engine/sql-tables.mjs +101 -7
  69. package/engine/standing-terms.mjs +9 -5
  70. package/engine/standings.mjs +83 -31
  71. package/engine/unique-items.mjs +85 -0
  72. package/engine/verse-metre.mjs +50 -5
  73. package/engine/verse-regions.mjs +16 -0
  74. package/package.json +9 -4
  75. package/site-theme/data/banner-kinds.yaml +2 -0
  76. package/sohl/actors.mjs +4 -3
  77. package/types/e2e.d.mts +1 -1
  78. package/types/engine/content-html.d.mts +2 -1
  79. package/types/engine/content-scripts.d.mts +9 -1
  80. package/types/engine/content-verse.d.mts +11 -2
  81. package/types/engine/core-report.d.mts +6 -2
  82. package/types/engine/culture-reach.d.mts +3 -0
  83. package/types/engine/declared-sections.d.mts +30 -0
  84. package/types/engine/derived-sections.d.mts +5 -1
  85. package/types/engine/holdings.d.mts +34 -2
  86. package/types/engine/index-records.d.mts +2 -1
  87. package/types/engine/language-names.d.mts +18 -6
  88. package/types/engine/language-terms.d.mts +5 -1
  89. package/types/engine/markdown-blocks.d.mts +5 -1
  90. package/types/engine/npc-generate.d.mts +3 -0
  91. package/types/engine/office-holders.d.mts +33 -0
  92. package/types/engine/page-breaks.d.mts +38 -0
  93. package/types/engine/pdf-render.d.mts +2 -0
  94. package/types/engine/place-kinds.d.mts +18 -0
  95. package/types/engine/settlement-tables.d.mts +25 -158
  96. package/types/engine/settlement-terms.d.mts +53 -0
  97. package/types/engine/site-build.d.mts +3 -1
  98. package/types/engine/site-render.d.mts +6 -2
  99. package/types/engine/site-root.d.mts +3 -1
  100. package/types/engine/site-serve-http.d.mts +1 -0
  101. package/types/engine/site-serve.d.mts +12 -6
  102. package/types/engine/sql-tables.d.mts +35 -3
  103. package/types/engine/standing-terms.d.mts +3 -2
  104. package/types/engine/standings.d.mts +14 -2
  105. package/types/engine/unique-items.d.mts +12 -0
  106. package/types/engine/verse-metre.d.mts +2 -1
  107. package/types/engine/verse-regions.d.mts +8 -0
  108. package/vendor/markdownlint.mjs +855 -569
@@ -1444,8 +1444,8 @@ complete address here; `folder-poisonsandtoxins` and the fully qualified
1444
1444
  `sohl-none-folder-poisonsandtoxins` name the same folder. An address no folder
1445
1445
  note answers to is a build error naming the folders the package does declare.
1446
1446
 
1447
- Note this is the _pack_ folder, not the note's directory. The directory is
1448
- `file.path` / `file.folder`, which a content table reads separately.
1447
+ Note this is the _pack_ folder, and a note's directory has no bearing on it
1448
+ or on any query.
1449
1449
 
1450
1450
  **Where a folder materialises is derived from what references it.** Every pack
1451
1451
  holding a document that names a folder gets that folder, and its ancestors with
@@ -2104,6 +2104,11 @@ keys makes a separate presentation choice. `enc=default` inside an encoded
2104
2104
  parent keeps the inherited language but does not inherit its inferred script
2105
2105
  face. An explicitly authored font remains a font choice.
2106
2106
 
2107
+ The content charset admits characters in every registered setting-script block,
2108
+ including the format controls those scripts use. The selected native face must
2109
+ still draw each character. In a language run, write native characters through
2110
+ literal codage; pasting a native character directly is a finding.
2111
+
2107
2112
  A name's braces use the shared name controls. Resolved references encode only
2108
2113
  their visible labels, retaining URLs and presentation cues. These keys apply
2109
2114
  to spans, divs and scroll fences. A scroll's selected font must
@@ -2282,11 +2287,14 @@ counted.
2282
2287
  The fence states `lang=` with a language whose `note` names a language note
2283
2288
  stating `data.sounds.stress` (see [a language's register, sounds and
2284
2289
  history](#a-languages-register-sounds-and-history)). A word has one beat on its
2285
- stressed syllable when it has two or more syllables; a one-syllable word has a
2290
+ stressed syllable when it has two or more syllables, but may go unstressed
2291
+ when all its lexicon classes have bases outside `n`, `v`, `adj`, `num` and
2292
+ `name`; a multi-syllable word with any of those bases, or no lexicon entry,
2293
+ keeps its beat. A one-syllable word has a
2286
2294
  beat when the `class` base of its lexicon entry is `n`, `v`, `adj`, `num` or
2287
2295
  `name`, and none when it is any other base; a one-syllable word the lexicon
2288
- does not hold is counted as a content word; a word whose entries differ in
2289
- class is a beat that may be left out; and a word of four or more syllables
2296
+ does not hold is counted as a content word; a one-syllable word with both
2297
+ content and function classes has a beat that may be left out; and a word of four or more syllables
2290
2298
  whose stress is not on its first may take a second beat there. A line scans when
2291
2299
  its count can be the metre's.
2292
2300
 
@@ -3396,7 +3404,7 @@ ORDER BY sohl.kbcat, name.full
3396
3404
  **`FROM notes`** is the content index: one row per note, plus one per
3397
3405
  documentation entry, so `type = 'miscgear'` selects the items and never their
3398
3406
  journals. A nested field is addressed exactly as a note authors it —
3399
- `sohl.weight`, `name.full`, `file.path` — because the index is read as JSON and
3407
+ `sohl.weight`, `name.full`, `data.culture` — because the index is read as JSON and
3400
3408
  every nested object is inferred as a struct. A field a note type does not carry
3401
3409
  reads `NULL` rather than failing. `data.culture` is the one field that reads as
3402
3410
  a derived value: the note's own culture, or the one it inherits. See
@@ -3526,7 +3534,7 @@ for the keys.
3526
3534
  | `register` | `data.register` | `name`, `tongue`, `kind`, `built` (a list), `gloss`, `why`, `built_text` (the pieces joined with `+`), and `notes`: every note of the package carrying the name, derived from the index, `NULL` where none does |
3527
3535
  | `tongues` | `data.tongues` | `tag`, `meaning`, and `tongue_language`, the tongue's `language` |
3528
3536
  | `retired` | `data.retired` | `form`, `instead` (always a list, `NULL` where nothing is written instead), `why` |
3529
- | `scope` | `data.scope` | No `position`: `kind`, the key the value is under (`folders`, `cultures`, `lore`, `parents`, `addresses`, `paths`, `types` or `skip`), and `value`, an Address in its canonical form or a path or a type |
3537
+ | `scope` | `data.scope` | No `position`: `kind`, the key the value is under (`folders`, `cultures`, `lore`, `parents`, `addresses`, `types` or `skip`), and `value`, an Address in its canonical form or a type |
3530
3538
  | `letters` | `data.sounds.letters` | `letters` (a list), `kind`, `like`, `place`, `ipa`, `tongue` (a list, `NULL` for every tongue); a [spelling guide's](#a-spelling-guides-sounds) rows too, keyed by the guide |
3531
3539
  | `edges` | `data.sounds.edges` | `edge`, `sounds` (a list: `[any]` for every sound, empty for none) |
3532
3540
  | `clusters` | `data.sounds.clusters` | No `position`: `max`, one row per language stating it |
@@ -3675,8 +3683,9 @@ relational operations:
3675
3683
  `_section` is why one query replaces the forty near-identical blocks a grouped
3676
3684
  table would otherwise need: the authored `ORDER BY` decides the section order too.
3677
3685
 
3678
- **Beware `packFolder`.** It is a note's _pack_ folder, not its directory — the
3679
- directory is `file.folder`.
3686
+ **Beware `packFolder`.** It is a note's _pack_ folder. A query never selects by
3687
+ the directory a note sits in: `file.path`, `file.folder` and `file.name` are
3688
+ refused wherever a query names them.
3680
3689
 
3681
3690
  ##### Culture parents and inherited fields
3682
3691
 
@@ -4009,6 +4018,30 @@ the tag and, where the directive restricts one, the type. An empty list under
4009
4018
  an authored heading is how a misspelled tag survives a build, so the
4010
4019
  directive's silence is what is refused rather than its output.
4011
4020
 
4021
+ ##### Book page breaks
4022
+
4023
+ Write `--- {.page-break}` on its own line between blocks, with blank lines around it:
4024
+
4025
+ ```markdown
4026
+ The first passage ends here.
4027
+
4028
+ --- {.page-break}
4029
+
4030
+ The next passage starts on a fresh book page.
4031
+ ```
4032
+
4033
+ The book starts a fresh page without drawing a rule. If the marker already
4034
+ falls at the top of a page, it adds no blank page. The website, Foundry and
4035
+ both editor preview views omit the marker. Plain `---`, `***` and `___` keep
4036
+ their ordinary horizontal rules. Code blocks and verse divs keep the marker
4037
+ as literal text.
4038
+
4039
+ Only `---` accepts `.page-break`; `*** {.page-break}` and `___ {.page-break}`
4040
+ are findings. Other classes, ids and attributes on an attributed `---` line
4041
+ are findings too. A page break stands between blocks at the top level of a
4042
+ note: putting one inside a list, block quote, alert, footnote definition,
4043
+ secret block or fenced div is a finding at the marker's line and column.
4044
+
4012
4045
  ##### Captions and numbered references
4013
4046
 
4014
4047
  Write a caption on its own line **before** the item it describes, with a blank line before and after the caption. `:` produces an unnumbered caption; `:@` produces a numbered caption. One or more spaces separate the marker from its text. An optional attribute block at the end accepts an identifier, classes and named attributes:
@@ -4273,6 +4306,7 @@ the authored text as H1 sections with fixed anchors, in this order:
4273
4306
  | Within | `within` | a `place` | the places whose `data.parents` names it, one paragraph to each kind of place, in the order the place vocabulary lists its `subType`s |
4274
4307
  | Governed by | `governedby` | a `place` | the affiliation its `data.government` names, as a list entry with the affiliation's kind |
4275
4308
  | Governed places | `governedplaces` | an `affiliation` | the places whose `data.government` names it, grouped as **Within** groups them |
4309
+ | Office holders | `officeholders` | an `affiliation` | each office of its `governance.offices` held by a living being, one line each, with the beings whose `office` names it |
4276
4310
  | Chronology | `chronology` | a `place` | an [event view](#event-views) |
4277
4311
  | Events | `events` | a `being`, an `affiliation`, a `lore` note of `culture` | an event view |
4278
4312
  | Accounts | `accounts` | an `affiliation`, a `place`, a `lore` note of `culture` | an event view |
@@ -4922,10 +4956,11 @@ language:
4922
4956
  - **a map of `gender` words** to a pattern or a list of them, for a tongue
4923
4957
  whose forms differ by gender. A gender with no pattern of its own takes
4924
4958
  every pattern stated.
4925
- - `given` maps a `gender` word to a list of given names. `female` and `male`
4926
- are required. `{given}` draws from the list for the person's gender, or from
4927
- every given list together where that gender has none. `{given.<gender>}`
4928
- draws from that gender's list whatever the person's gender, as a patronymic
4959
+ - `given` is one list of names for everyone, or a map of `gender` words to
4960
+ lists. A shared list supplies every gender. A map requires `female` and
4961
+ `male`; `{given}` draws from the person's gender's list, or every given list
4962
+ together where that gender has none. `{given.<gender>}` draws from the shared
4963
+ list or that gender's list whatever the person's gender, as a patronymic
4929
4964
  draws a father's name.
4930
4965
  - `en` holds English names, in groups of lists. A group is named by letters,
4931
4966
  digits and underscores, beginning with a letter, and a pattern reaches it by
@@ -4941,6 +4976,18 @@ Each placeholder draws one name from its list, each name as likely as any
4941
4976
  other, and a drawn name takes one of its gender's patterns, each as likely as
4942
4977
  any other.
4943
4978
 
4979
+ A tongue whose given names suit anyone states one list:
4980
+
4981
+ ```yaml
4982
+ data:
4983
+ names:
4984
+ pattern: "{given} {clan}"
4985
+ given: [Nara, Taro]
4986
+ clan: [Mori, Sela]
4987
+ ```
4988
+
4989
+ `Nara Mori` and `Taro Sela` fit every gender; each draw uses the same list.
4990
+
4944
4991
  A tongue whose people are named by standing states each form in a list:
4945
4992
 
4946
4993
  ```yaml
@@ -5021,8 +5068,8 @@ names, an empty name, a missing `pattern` or `given`, a missing `female` or
5021
5068
 
5022
5069
  #### The bodies a being belongs to, and its standing in each
5023
5070
 
5024
- **Membership**: `{rank: number, office: string, societies: string[]}` — `rank`
5025
- required, `office` and `societies` not.
5071
+ **Membership**: `{rank: number, office: string | string[], societies: string[]}` —
5072
+ `rank` required, `office` and `societies` not.
5026
5073
 
5027
5074
  `data.affiliations` is a **map keyed by the body's Address**, and each entry is
5028
5075
  the standing the being holds in that body. The key is what makes the pair
@@ -5036,7 +5083,8 @@ An entry carries three keys and nothing else:
5036
5083
  every rung, so a number indexes into it and the body stays the single source
5037
5084
  for what its level 5 is called.
5038
5085
  - **`office`** — optional, a **string**, matched against the keys of that body's
5039
- `governance.offices` map.
5086
+ `governance.offices` map, or a **list** of them where one being holds several
5087
+ posts in the same body, such as treasurer and chancellor of one council.
5040
5088
  - **`societies`** — optional, a **list of names**, the societies the membership
5041
5089
  is held in. It is always a list, even with one name; a bare string is an
5042
5090
  error at the key.
@@ -5065,13 +5113,15 @@ data:
5065
5113
  Both values are checked against the body the entry is keyed by. A `rank` that
5066
5114
  is not a level the body confers and an `office` that is not one of its keys are
5067
5115
  each an error naming the file, line and column — so a rung or a post that does
5068
- not exist fails on every being pointing at it. Naming one body twice, by its short
5116
+ not exist fails on every being pointing at it. Each post of a list is checked
5117
+ and located on its own. Naming one body twice, by its short
5069
5118
  and full Address, still names one body and is an error.
5070
5119
 
5071
5120
  The infobox prints one line per membership, in the order the note writes them,
5072
5121
  in a section of its own titled **Affiliations**: the office where one is held, then the rung's
5073
5122
  title with its level in parentheses, then the body — `War Chief, Hárár (5), of
5074
- Vrystwald Tribes`, or `Hárár (5), of Vrystwald Tribes` with no office. The title
5123
+ Vrystwald Tribes`, or `Hárár (5), of Vrystwald Tribes` with no office. Several
5124
+ posts lead in the order written: `Treasurer, Chancellor, Hárár (5), of …`. The title
5075
5125
  is read from the body's own `governance.ranks`; where the body declares no rung
5076
5126
  at that level, or its ladder is not available, the rung reads as `Rank 5` —
5077
5127
  `Rank 5, of Vrystwald Tribes`. The body's name links to its page, and is plain
@@ -5079,10 +5129,11 @@ text where it publishes none. A membership stating no
5079
5129
  standing is the body's name alone. The lines are the same on the website, in
5080
5130
  a Foundry journal and in the book. On the body's own page each office is a row
5081
5131
  anchored by its name, so the post a being holds is described where the body
5082
- declares it.
5132
+ declares it, and its **Office holders** section lists who holds each post.
5083
5133
 
5084
5134
  For SoHL, a being embeds one affiliation item per entry: `rank` **is** that
5085
- item's `system.level`, `office` its `system.office`, and the first name in
5135
+ item's `system.level`, `office` its `system.office` (several posts joined by
5136
+ commas), and the first name in
5086
5137
  `societies` its `system.society`. The SoHL item holds one society, so only the
5087
5138
  first name reaches it. A standing is a fact
5088
5139
  about the setting rather than about one system, so the `sohl:` block states
@@ -5645,7 +5696,33 @@ data:
5645
5696
  - { being: being-mara, start: "datefrom vrcal 2 Lusenar 725 VR" }
5646
5697
  ```
5647
5698
 
5648
- **Governed places are derived from place notes.** Each place names one governing affiliation in `data.government`. The affiliation's **Governed places** [generated section](#generated-sections) lists the places whose explicit references resolve to it, across local notes and fetched indexes, grouped by kind; with none, it has no such section. No affiliation-side list supplies government, and neither geographic containment nor organizational parents expands it.
5699
+ **Office holders are derived from beings.** Nothing names a holder on the
5700
+ office itself: a being states the post it holds in its own
5701
+ `data.affiliations.<body>.office`. For each office in `governance.offices`, the
5702
+ body's **Office holders** [generated section](#generated-sections) lists every
5703
+ being naming it whose `data.died` is unset, so several holders at once, a post
5704
+ held jointly, a vacant post that lists no one and a former holder who has died
5705
+ all need no further key. Offices follow the body's order, and holders are
5706
+ ordered by name; an office nobody living holds has no line, and a body with no
5707
+ held office has no section. A public body lists only public beings. The
5708
+ content index carries the same list on the body's record as `officeHolders`, one
5709
+ `{ office, holders }` entry per held office, each holder a being Address:
5710
+
5711
+ ```json
5712
+ {
5713
+ "officeHolders": [
5714
+ {
5715
+ "office": "War Chief",
5716
+ "holders": [{ "address": "thalorna-note-being-hrothgar", "anchor": null, "anchorKind": null }]
5717
+ }
5718
+ ]
5719
+ }
5720
+ ```
5721
+
5722
+ `holders`, the dated roster above, is a separate record of terms a body may
5723
+ keep; the derived list reads only the beings.
5724
+
5725
+ **Governed places are derived from place notes.** Each place names one governing affiliation in `data.government`. The affiliation's **Governed places** [generated section](#generated-sections) lists the places whose explicit references resolve to it, across local notes and fetched indexes, grouped by kind, and every district that states no government and falls under one of those places; with none, it has no such section. No affiliation-side list supplies government, organizational parents never expand it, and geographic containment expands it only to a district stating none.
5649
5726
 
5650
5727
  If `sohl` is present, this becomes an `affiliation` item.
5651
5728
 
@@ -5793,6 +5870,7 @@ Note: `data.quantity` may not be specified. Quantity is always 1.
5793
5870
  | `durability` | `number` | Gear durability |
5794
5871
  | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
5795
5872
  | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
5873
+ | `unique` | `boolean` | `true` for a one-of-a-kind item; its note links a place or a being |
5796
5874
 
5797
5875
  If a `sohl` property is present, a SoHL item of type "armorgear" is created.
5798
5876
 
@@ -5815,6 +5893,15 @@ without an `id`, a note holding none, an anchor the note does not declare, or
5815
5893
  a `prose` anchor is an error at that key. Neither reaches a system field, an
5816
5894
  infobox row or a page: each is a fact a content table can read.
5817
5895
 
5896
+ `unique: true` marks a one-of-a-kind item — a named hammer, a crown, a sword
5897
+ in a tomb — and an item without it is common, like ten feet of rope. No key says
5898
+ who holds or owns a unique item: possession changes in play, where Foundry
5899
+ tracks it in an actor's inventory, and ownership is a claim that can be
5900
+ disputed. Where the item lies and who claims it are prose in its note, linked
5901
+ to the places and beings involved, so a unique item whose note links no `place`
5902
+ and no `being` — in a body wikilink, or in a `made` or `lost` event Address — is
5903
+ an error at `unique`. Neither system reads the key; the infobox shows it as a **Unique** row.
5904
+
5818
5905
  ### type: armorlocation
5819
5906
 
5820
5907
  | `data` property | Values | Description |
@@ -5855,6 +5942,7 @@ if a `sohl` property is present, a SoHL item of type "attribute" is created.
5855
5942
  | `durability` | `number` | Gear durability |
5856
5943
  | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
5857
5944
  | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
5945
+ | `unique` | `boolean` | `true` for a one-of-a-kind item; its note links a place or a being |
5858
5946
  | `quantity` | `number` | Gear quantity (default: 1) |
5859
5947
  | `potency` | `na \| mild \| strong \| great` | Concoction Potency (mundane/exotic concoctions) |
5860
5948
  | `strength` | `number` | Strength: higher the number, greater the strength |
@@ -5885,6 +5973,7 @@ Note: `data.quantity` may not be specified; quantity is always set to 1.
5885
5973
  | `durability` | `number` | Gear durability |
5886
5974
  | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
5887
5975
  | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
5976
+ | `unique` | `boolean` | `true` for a one-of-a-kind item; its note links a place or a being |
5888
5977
  | `capacity` | `number` | HM3 container capacity (in lbs) |
5889
5978
 
5890
5979
  if a `sohl` property is present, a SoHL item of type "containergear" is created.
@@ -5912,6 +6001,7 @@ SoHL reads a container’s capacity in pounds from `sohl.maxCapacity`.
5912
6001
  | `durability` | `number` | Gear durability |
5913
6002
  | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
5914
6003
  | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
6004
+ | `unique` | `boolean` | `true` for a one-of-a-kind item; its note links a place or a being |
5915
6005
  | `quantity` | `number` | HM3 gear quantity (default: 1) |
5916
6006
 
5917
6007
  if a `sohl` property is present, a SoHL item of type "miscgear" is created.
@@ -6031,6 +6121,7 @@ the item’s base mastery and level from `sohl.masteryLevelBase` and
6031
6121
  | `durability` | `number` | Gear durability |
6032
6122
  | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
6033
6123
  | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
6124
+ | `unique` | `boolean` | `true` for a one-of-a-kind item; its note links a place or a being |
6034
6125
  | `quantity` | `number` | HM3 gear quantity (default: 1) |
6035
6126
 
6036
6127
  if a `sohl` property is present, a SoHL item of type "projectilegear" is created.
@@ -6074,7 +6165,7 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6074
6165
  | `parentSkill` | `Address` | Parent skill this skill specializes |
6075
6166
  | `names` | `{ pattern, given, en?, <name>... }` | `language` only: how its speakers are named, for `package-build npc new` — see [name lists](#name-lists) |
6076
6167
  | `names.pattern` | `string`, `string[]` or map of `gender` words to either, required | Placeholders such as `{given}`, `{given.male}` and `{clan}`, each naming a list, with literal text around them; a list states several forms, a map each gender's forms |
6077
- | `names.given` | map of `gender` words to lists of names, required | Given names by gender; `female` and `male` are required |
6168
+ | `names.given` | list of names or map of `gender` words to lists, required | One shared list for every gender, or a map requiring `female` and `male` |
6078
6169
  | `names.given.<name>` | `string[]` | The given names of one gender |
6079
6170
  | `names.en` | map of list names to lists of English names | English names, never encoded in the tongue's script; a pattern draws from one list as `{en.<list>}` |
6080
6171
  | `names.en.<name>` | `string[]` | A list of English names, such as `epithet` |
@@ -6082,7 +6173,7 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6082
6173
  | `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) |
6083
6174
  | `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) |
6084
6175
  | `core` | `boolean` | `language` only: `true` where the language must cover the [core vocabulary](#the-core-vocabulary) |
6085
- | `roman` | literal NFC string, may be empty | Exact permitted Roman source characters, including both cases, accents, digits and punctuation; required on each configured language note. No family inheritance or range syntax. |
6176
+ | `roman` | literal NFC string, may be empty | Additions: letters in accepted cases, accents, catch signs and digits. Listing shared punctuation or whitespace is an error. Required per configured language note; no inheritance or ranges. |
6086
6177
  | `grammar` | `{ plural?, verbs?, agreement?, participles? }` | Optional noun plurals, one verb pattern, agreement and participles; supplied shapes only are checked |
6087
6178
  | `grammar.plural` | `{ ending, becomes }[]` | Literal suffix replacements in authored order; the first match wins |
6088
6179
  | `grammar.plural[].ending` | `string`, required, may be empty | Bare suffix to replace; empty matches every noun |
@@ -6160,13 +6251,12 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6160
6251
  | `retired[].form` | `string`, required | The form the setting does not write |
6161
6252
  | `retired[].instead` | `string` or `string[]` | What is written in its place; absent where nothing is |
6162
6253
  | `retired[].why` | `string`, required | Why the setting does not write it |
6163
- | `scope` | `{ folders?, cultures?, lore?, parents?, addresses?, paths?, types?, skip? }` | `language` only: the notes the register covers |
6254
+ | `scope` | `{ folders?, cultures?, lore?, parents?, addresses?, types?, skip? }` | `language` only: the notes the register covers |
6164
6255
  | `scope.folders` | `Address[]` | Every note whose `packFolder` is one of these folders |
6165
6256
  | `scope.cultures` | `Address[]` | Every note whose `culture` is one of these cultures |
6166
6257
  | `scope.lore` | `Address[]` | Every note whose `lore` names one of these notes |
6167
6258
  | `scope.parents` | `Address[]` | Every note whose `parents` names one of these notes |
6168
6259
  | `scope.addresses` | `Address[]` | These notes themselves |
6169
- | `scope.paths` | `string[]` | Every note whose file sits below one of these content paths, as `Regions/Aelwyth/` |
6170
6260
  | `scope.types` | `string[]` | The note types covered; a note of another type is out of scope whatever else catches it |
6171
6261
  | `scope.skip` | `Address[]` | Notes out of scope whatever else catches them |
6172
6262
  | `sounds` | `{ letters?, edges?, clusters?, stress?, finals?, syllables?, joining?, joins?, marks?, skeleton?, frames?, readPast? }` | `language` only: the letters it writes and the rules its words keep |
@@ -6224,7 +6314,7 @@ SoHL sets `system.quantity` to `1` for each compendium item.
6224
6314
  | `sounds.marks` | `{ mark, letters, kind, limit }[]` | The marks the language writes on its letters |
6225
6315
  | `sounds.marks[].mark` | `string`, required | The mark's name, as `acute` |
6226
6316
  | `sounds.marks[].letters` | `string[]`, required | The letters that carry it |
6227
- | `sounds.marks[].kind` | `stress`, `length` or `apart`, required | What it says of its letter |
6317
+ | `sounds.marks[].kind` | `stress`, `length`, `apart` or `quality`, required | What it says of its letter |
6228
6318
  | `sounds.marks[].limit` | `one` or `any`, required | How many a word may carry |
6229
6319
  | `sounds.skeleton` | `{ second, third?, between? }[]` | The vowel set between a root's second and third consonants |
6230
6320
  | `sounds.skeleton[].second` | `string[]` or `any`, required | The second consonants the row holds for; `any` for every other |
@@ -6652,8 +6742,13 @@ meaning, `built` may name its existing pieces, and `concept` may name every
6652
6742
  concept those senses support. The report counts declared ids; it does not
6653
6743
  prove an expression's meaning or infer coverage from grammar or untagged prose.
6654
6744
 
6655
- `package-build core` is the report. A concept no word serves is never a lint
6656
- finding; the report lists it so the language can be filled in. See
6745
+ `package-build core` measures only language notes that state `data.core: true`.
6746
+ It ends with `Not covered (no data.core): …`, naming the other language notes
6747
+ in name order, when any exist. The JSON report includes the same names in its
6748
+ `notCovered` array. `--language <name>` measures that language whether or not
6749
+ it states `data.core`, with an empty `notCovered` array and no skip line.
6750
+ A concept no word serves is never a lint finding; the report lists it so the
6751
+ language can be filled in. See
6657
6752
  [`package-build core`](../commands.md#package-build-core).
6658
6753
 
6659
6754
  #### A language's register, sounds and history
@@ -6875,7 +6970,7 @@ closed list where its values are words:
6875
6970
  - `joins`: what happens where a consonant or a vowel meets another (`C+C`,
6876
6971
  `V+C`, `V+V`): `merge`, `insert` the `letters` between, `drop` the first, or
6877
6972
  `double` the consonant, everywhere or `where` stated.
6878
- - `marks`: the marks written on letters, each saying `stress`, `length`, or `apart` (the mark sets a vowel to be said apart from its neighbour, as a diaeresis does), and
6973
+ - `marks`: the marks written on letters, each saying `stress`, `length`, `apart` (the mark sets a vowel to be said apart from its neighbour, as a diaeresis does) or `quality` (the mark changes which vowel is said, as a grave writing the short vowel of _cat_ does), and
6879
6974
  whether a word carries `one` at most or `any`.
6880
6975
  - `skeleton`: the vowel set between a root's second and third consonants, by
6881
6976
  the second consonant and, where a row states `third`, the third; nothing
@@ -7163,6 +7258,7 @@ Note: `data.quantity` may not be specified. Quantity is always 1.
7163
7258
  | `durability` | `number` | Gear durability |
7164
7259
  | `made` | an event Address | The event in which it was made — `lore-forging`, or `place-ironfells#raising` |
7165
7260
  | `lost` | an event Address | The event in which it was lost — `lore-flood`, or `place-ironfells#sack` |
7261
+ | `unique` | `boolean` | `true` for a one-of-a-kind item; its note links a place or a being |
7166
7262
 
7167
7263
  if a `sohl` property is present, a SoHL item of type "weapongear" is created,
7168
7264
  carrying every strike mode the weapon has — melee and missile alike — on
@@ -7757,12 +7853,34 @@ level with no background prints nothing.
7757
7853
 
7758
7854
  - world: A self-contained whole in which places exist — a planet, plane, or realm.
7759
7855
  - region: A bounded division of a world or larger region — continents, marches, uplands, provinces.
7856
+ - district: A recognised division of a settlement or a region, usually administrative — a city's quarter, a town's ward, a kingdom's shire.
7760
7857
  - settlement: A place where folk dwell together — cities, towns, villages, holdings, camps.
7761
7858
  - site: A place significant by what was made or done there — ruins, monoliths, henges, works, battlefields.
7762
7859
  - structure: A single building or habitation — halls, keeps, temples, inns, towers.
7763
- - feature: A place significant by its terrain — forests, rivers, falls, passes, fords.
7860
+ - feature: A place significant by its terrain — forests, rivers, falls, fords.
7861
+ - route: A way travelled between places — a road, a pass, a sea lane.
7764
7862
  - celestial: A body observed from a world rather than located on one — a sun, a planet, a comet.
7765
7863
 
7864
+ A region is land defined by its geography or its people; a district is a
7865
+ division drawn by those who govern it. A valley crossing two shires is a
7866
+ region, and each shire is a district. **A district always stands within a
7867
+ `settlement` or a `region`**, named in `data.parents`: a district naming no
7868
+ parent is an error at its `subType`, and one whose parents all resolve and none
7869
+ is a settlement or a region is an error at `parents`. A district may name its
7870
+ own governing affiliation in `data.government`, a ward's governor or council;
7871
+ without the key it falls under its parent's government. The content index gives
7872
+ such a district the `data.government` of its nearest parent that states the key,
7873
+ reading `data.parents` in order and upward through parents that state none, so
7874
+ the district's **Governed by** section, the governing body's **Governed
7875
+ places** and every reader of the index name that body, and the "missing
7876
+ government" advisory does not fire. An explicit value on the district,
7877
+ `null` (complete anarchy) included, is its own and stands; a parent's explicit
7878
+ `null` is inherited as anarchy. **A route carries its
7879
+ journeys in `data.routes`**, at least one, and one stating none is an error at
7880
+ its `subType`; rivers stay features. Both compile as every place does, to a
7881
+ journal entry filed by `data.pack` and `data.packFolder`, and both are listed
7882
+ in their parent's **Within** section under **Districts** and **Routes**.
7883
+
7766
7884
  | `data` property | Values | Description |
7767
7885
  | --------------------------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
7768
7886
  | `events` | event entries — see [Events](#events) | What happened to or at this subject: dated, attributed events |
@@ -7773,6 +7891,15 @@ level with no background prints nothing.
7773
7891
  | `culture` | `Address` | The people this place belongs to, naming a lore note with `subType: culture` |
7774
7892
  | `population` | `number` | Approximate population (precision 2 significant digits) |
7775
7893
  | `government` | `Address` or `null` (default type: `affiliation`) | Governing affiliation; explicit null means complete anarchy. Omission warns only for positive population. |
7894
+ | `settlements` | `{ rows, tail }` | Declared settlement rows and the sentence saying what the table leaves out |
7895
+ | `settlements.rows` | list of row maps | One row per settlement |
7896
+ | `settlements.rows[].place` | `Address` | Existing settlement note; exclusive with name |
7897
+ | `settlements.rows[].name` | `string` | A settlement without a note; exclusive with place |
7898
+ | `settlements.rows[].market` | integer, required | Market class, 1 to 6 |
7899
+ | `settlements.rows[].population` | positive integer, required | People living here |
7900
+ | `settlements.rows[].heldBy` | `Address` | What holds the land, where it is held; an affiliation or a being |
7901
+ | `settlements.rows[].for` | `string` | Optional reason the settlement exists |
7902
+ | `settlements.tail` | `string`, required | Sentence stating what the table leaves out |
7776
7903
  | `market` | `number` | Market class, 1 to 6 — what trade a settlement supports |
7777
7904
  | `borders` | `{ to, bearing }[]` | Places sharing a frontier with this one, and where each lies from here |
7778
7905
  | `borders[].to` | `Address`, required | The other place; the type defaults to `place` |
@@ -8019,7 +8146,7 @@ Write `government: null` for **complete anarchy**. Omitting the key leaves gover
8019
8146
  | Any | Explicit `null` | None; complete anarchy |
8020
8147
  | Any | Affiliation Address | None; the reference must resolve |
8021
8148
 
8022
- These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `parents`, containment and capitals do not supply a government.
8149
+ These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `parents`, containment and capitals do not supply a government, except to a `district` that omits the key, which falls under its nearest parent's government as [type: place](#type-place) describes.
8023
8150
 
8024
8151
  #### Population figures
8025
8152
 
@@ -8076,120 +8203,81 @@ languages belong to a polity's `sohl.system.commonSkills`, while the note's
8076
8203
 
8077
8204
  #### A region's settlements table
8078
8205
 
8079
- A region lists its settlements in a table on its own note: one row for each
8080
- settlement, stating what its market is, how many people it holds and who holds
8081
- it. **A row is the whole record of a settlement that has no note.** Where a
8082
- note exists the row links it, and the two must agree. A package that writes no
8083
- such table is not affected by anything in this section.
8084
-
8085
- The table is a markdown table under a level-two `## Settlements` heading on the
8086
- region's `place` note. Its header is exactly these columns, in this order. `For`
8087
- may be left out; the header carries no other column:
8206
+ A region declares its table in `data.settlements: { rows, tail }`. The rows
8207
+ carry the settlement's `population` and numeric `market`, and either `place`
8208
+ (the existing note's Address, default type `place`) or `name` (plain text where
8209
+ no note exists), never both. Where the region's culture holds land, a row's
8210
+ optional `heldBy` names what holds it by Address (an affiliation or a being,
8211
+ default type `affiliation`), and what that note is says how the land is held: a
8212
+ temple, a lineage, the city, a kin group. A people who hold no land state no
8213
+ `heldBy`, and their table has no Held by column. Optional `for` states why the
8214
+ settlement exists. `tail` is the sentence stating what the table leaves out.
8215
+
8216
+ The guard reads indexed rows. A linked row's population and market agree with
8217
+ its note, and every settlement note covered through `parents` has one row in
8218
+ the nearest declaring region. `government` states who governs; it never supplies
8219
+ who holds the land. HTML, Foundry and Typst render the declared table once.
8220
+ A body table under `## Settlements` is an error at its header, naming
8221
+ `data.settlements`; no facts are read from it.
8222
+
8223
+ The rendered columns are fixed, in this order; `Held by` appears when any row
8224
+ states `heldBy`, and `For` when any row states `for`:
8088
8225
 
8089
8226
  | Name | Market | People | Held by | For |
8090
8227
  | ---- | ------ | ------ | ------- | --- |
8091
8228
 
8092
- - **Name** — the settlement. Where it has a note, a link to it with the pipe
8093
- escaped for the table, `[[place-ashford\|Ashford]]`; otherwise plain text.
8094
- - **Market** — the market class as its number and its name, lower case:
8095
- `1 hamlet`, `2 village`, `3 town`, `4 market town`, `5 city`, `6 great city`.
8096
- The scale is the one [`data.market`](#what-a-settlements-market-supports)
8097
- states.
8098
- - **People** — the population, a whole number, grouped with commas or not:
8099
- `60`, `420`, `3,400`.
8100
- - **Held by** — who holds it, written in the region's holding model. Link the
8101
- holder where it has a note.
8102
- - **For** — a short phrase saying why the place is there: the ford, the mine,
8103
- the shrine.
8104
-
8105
- At least one sentence of prose follows the table, before the next heading,
8106
- saying what the table leaves out. A section filled by an `sql` fence is
8107
- generated from the notes and is not read as a settlements table.
8108
-
8109
- **The region names its holding model as a tag.** A note carrying a settlements
8110
- table carries at least one of these tags; a region whose countryside is held
8111
- two ways carries both. Tags stay open, so a misspelled model is not reported as
8112
- such: the table's note is reported for naming no model.
8113
-
8114
- | `holdingModel` value | the Held by cell names |
8115
- | -------------------- | ---------------------- |
8116
- | `held` | a person or a house |
8117
- | `endowed` | an institution |
8118
- | `registered` | an office |
8119
- | `kin` | a kindred |
8120
- | `polis` | the city |
8121
-
8122
- A linked holder is an `affiliation` or a `being`, and a `being` is a person: it
8123
- may hold land only in a region tagged `held`.
8124
-
8125
- **A settlement belongs to one table** — that of the nearest place above it, by
8126
- `parents`, that carries a settlements table. Every `settlement` note that table
8127
- covers has a row there and nowhere else.
8128
-
8129
- A worked example. `Vale.md`:
8130
-
8131
- ```markdown
8132
- ---
8133
- shortcode: vale
8134
- name: { full: The Vale }
8135
- type: place
8136
- subType: region
8137
- tags: [region, held]
8138
- data:
8139
- population: 100000
8140
- government: crown
8141
- ---
8142
-
8143
- ## Settlements
8229
+ `population` is a positive whole number. `market` is an integer from 1 to 6;
8230
+ the generated Market cell includes the class name (`4 market town`). A holder
8231
+ is an affiliation or a being, and its note says what kind of holding it is: a
8232
+ temple holds its endowment, a lineage its fiefs, the city its own fields. A row
8233
+ naming no holder leaves its Held by cell empty.
8144
8234
 
8145
- | Name | Market | People | Held by | For |
8146
- | -------------------------- | ------------- | -----: | ---------------------------------------- | -------------------------- |
8147
- | [[place-ashford\|Ashford]] | 4 market town | 3,400 | [[affiliation-crown\|the Crown]] | the ford on the drove road |
8148
- | Weyshott | 2 village | 420 | [[being-aldwyn\|Sir Aldwyn of Brynwold]] | the manor's mill |
8149
- | Cold Hatch | 1 hamlet | 60 | Sir Aldwyn of Brynwold | the sheepwalk |
8235
+ A worked example: the following `data` block belongs to `Vale.md`, whose
8236
+ `type` is `place`, `subType` is `region` and `shortcode` is `vale`:
8150
8237
 
8151
- Some four hundred further villages lie in the vale, none of them named here.
8238
+ ```yaml
8239
+ data:
8240
+ settlements:
8241
+ rows:
8242
+ - place: ashford
8243
+ market: 4
8244
+ population: 3400
8245
+ heldBy: affiliation-crown
8246
+ for: the ford on the drove road
8247
+ - name: Weyshott
8248
+ market: 2
8249
+ population: 420
8250
+ heldBy: being-aldwyn
8251
+ for: the manor's mill
8252
+ - name: Cold Hatch
8253
+ market: 1
8254
+ population: 60
8255
+ tail: Some four hundred further villages lie in the vale, none of them named here.
8152
8256
  ```
8153
8257
 
8154
8258
  `Ashford.md` states `parents: [vale]`, `population: 3400` and `market: 4`, so its
8155
- row agrees with it. Weyshott and Cold Hatch have no notes; their rows are their
8156
- whole record. Change Ashford's row to `3,000` and `package-build lint` reports:
8157
-
8158
- ```text
8159
- assets/content/Vale.md:16:49: error: figure disagrees: Ashford is carried at 3,000 here and 3,400 on its own note
8160
- ```
8161
-
8162
- `package-build lint` reports each of these as an error, each named by the
8163
- phrase its message begins with:
8164
-
8165
- - **`settlements columns`** — the header is not the declared columns in
8166
- order. The table's rows are not read until it is.
8167
- - **`no holding model`** — the note carries a settlements table and none of
8168
- the holding-model tags. Reported at its `tags`.
8169
- - **`market class`** — a Market cell is not a class written as its number and
8170
- its name.
8171
- - **`people figure`** — a People cell is not a positive whole number.
8172
- - **`no holder`** — a Held by cell is empty.
8173
- - **`not a holder`** — a Held by link names a note that is neither an
8174
- affiliation nor a being.
8175
- - **`holder out of model`** — a Held by link names a being in a region not
8176
- tagged `held`.
8177
- - **`not a settlement`** — a Name link names a note that is not a place.
8178
- - **`figure disagrees`** — a linked row's People differs from its note's
8179
- `data.population`, or the note states none.
8180
- - **`market disagrees`** — a linked row's Market differs from its note's
8181
- `data.market`, or the note states none.
8182
- - **`unlinked settlement`** — an unlinked Name is the name or an alias of a
8183
- settlement note the table covers. The finding gives the link to write.
8184
- - **`missing row`** — a settlement note the table covers has no row. Reported
8185
- at the table's header.
8186
- - **`duplicate settlement`** — a settlement has a second row in one table, or
8187
- a row in a table other than the one covering it.
8188
- - **`no tail`** — no sentence follows the table before the next heading.
8189
- Reported at the table's last row.
8190
-
8191
- A cell's finding is located at the cell. A link in a cell that resolves to no
8192
- note is reported by the link check, once, and not again here.
8259
+ row agrees. `affiliation-crown` names the existing Crown note; `being-aldwyn`
8260
+ names Sir Aldwyn's existing note. Weyshott and Cold Hatch have no notes; these
8261
+ rows hold their complete settlement record, and Cold Hatch names no holder. The generated table uses the
8262
+ current note names for its links and prints `3,400` and `4 market town`.
8263
+ Changing Ashford's row population to `3000` produces `figure disagrees` at
8264
+ that YAML value; removing its row produces `missing row` at `rows`.
8265
+
8266
+ Every semantic finding is an error, located where its YAML changes:
8267
+
8268
+ - **`body settlements table`** — A body table under Settlements is refused; declare data.settlements.
8269
+ - **`settlements shape`** — A region declares rows and tail, with one name or place per row.
8270
+ - **`unresolved settlement reference`** — A place or heldBy Address does not resolve.
8271
+ - **`market class`** — A row market is not an integer from 1 to 6.
8272
+ - **`people figure`** — Population is not a positive whole number.
8273
+ - **`not a holder`** — A heldBy Address names neither an affiliation nor a being.
8274
+ - **`not a settlement`** — A place Address names a subject that is not a place.
8275
+ - **`figure disagrees`** — A linked population differs from its note, or the note states none.
8276
+ - **`market disagrees`** — A linked market differs from its note, or the note states none.
8277
+ - **`unlinked settlement`** — A plain name has an existing settlement note in this region.
8278
+ - **`missing row`** — A covered settlement note has no row.
8279
+ - **`duplicate settlement`** — A settlement has another row here or in another region.
8280
+ - **`no tail`** — The declaration has no sentence stating what it leaves out.
8193
8281
 
8194
8282
  ### type: scenario
8195
8283
 
@@ -8201,6 +8289,14 @@ Content prepared to be played — a situation with its cast, places, and possibl
8201
8289
  - adventure: A self-contained undertaking with a specific objective, playable in a few sessions.
8202
8290
  - encounter: A single scene or challenge, reusable within an adventure or on its own.
8203
8291
 
8292
+ A scenario's state is two independent signals. The `draft` tag is the author's
8293
+ judgement that it still needs work, lifted when it is finished whether or not
8294
+ it has been played. An optional `## Playtest {#playtest}` section, absent until
8295
+ the scenario is first run at a table, records each run: the date, the table's
8296
+ size, the party's makeup and the scenes covered, the difficulty as played scene
8297
+ by scene, adjustments a GM can make, and what the party did that the scenario
8298
+ did not foresee. Holes found in play are fixed in the scenario itself.
8299
+
8204
8300
  | `data` property | Values | Description |
8205
8301
  | ------------------ | -------------------------------------------- | ------------------------------------------------------------------------------ |
8206
8302
  | `parents` | `Address[]` | List of parent scenarios of this scenario (campaigns, etc.) |
@@ -8208,7 +8304,6 @@ Content prepared to be played — a situation with its cast, places, and possibl
8208
8304
  | `cast` | `Address[]` | individuals associated with this scenario |
8209
8305
  | `factions` | `Address[]` | Affiliations associated with this scenario |
8210
8306
  | `follows` | `Address[]` | Prerequisite scenarios that should be completed before beginning this scenario |
8211
- | `status` | `draft \| playtested \| published` | Playability status of this scenario |
8212
8307
  | `party.size` | `solo \| small \| standard \| large \| host` | Suggested party size (solo=1, small=2-3, standard=4-6, large=6-7, host=7+) |
8213
8308
  | `party.archetypes` | `Archetype[]` | Archetypes of characters suitable for completion |
8214
8309
 
@@ -8288,7 +8383,7 @@ Content prepared to be played — a situation with its cast, places, and possibl
8288
8383
  | `sounds.marks` | `{ mark, letters, kind, limit }[]` | The marks written on the letters, each row's keys as a language note's `sounds.marks` |
8289
8384
  | `sounds.marks[].mark` | `string`, required | The mark's name, as `acute` |
8290
8385
  | `sounds.marks[].letters` | `string[]`, required | The letters that carry it |
8291
- | `sounds.marks[].kind` | `stress`, `length` or `apart`, required | What it says of its letter |
8386
+ | `sounds.marks[].kind` | `stress`, `length`, `apart` or `quality`, required | What it says of its letter |
8292
8387
  | `sounds.marks[].limit` | `one` or `any`, required | How many a word may carry |
8293
8388
 
8294
8389
  A setting guide introduces one culture's view of the setting, so it names that