@heroiclands/package-build 20.3.1 → 20.5.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 (195) hide show
  1. package/CHANGELOG.md +351 -0
  2. package/CONTENT.md +322 -110
  3. package/README.md +21 -10
  4. package/bin/content-build.mjs +204 -92
  5. package/bin/package-build.mjs +48 -15
  6. package/config.mjs +6 -8
  7. package/content-config.mjs +518 -151
  8. package/docs/api.md +1352 -0
  9. package/docs/commands.md +1609 -0
  10. package/docs/configuration.md +1432 -0
  11. package/docs/content-format.md +73 -74
  12. package/docs/diagnostics.md +356 -0
  13. package/docs/getting-started.md +813 -0
  14. package/docs/project-setup.md +469 -0
  15. package/e2e.mjs +4 -4
  16. package/engine/actor-compiler.mjs +64 -61
  17. package/engine/address-charset.mjs +6 -6
  18. package/engine/address-diff.mjs +57 -52
  19. package/engine/anchored-sections.mjs +1 -1
  20. package/engine/anchors.mjs +1 -1
  21. package/engine/base-compiler.mjs +42 -38
  22. package/engine/bundle-notes.mjs +4 -4
  23. package/engine/bundles.mjs +17 -8
  24. package/engine/code-fences.mjs +3 -3
  25. package/engine/compendiums.mjs +8 -8
  26. package/engine/compile-corpus.mjs +4 -5
  27. package/engine/content-address.mjs +24 -24
  28. package/engine/content-charset.mjs +1 -1
  29. package/engine/content-format-check.mjs +24 -25
  30. package/engine/content-format.mjs +8 -8
  31. package/engine/content-html.mjs +202 -0
  32. package/engine/content-icons.mjs +196 -165
  33. package/engine/content-index.mjs +61 -40
  34. package/engine/content-links.mjs +74 -41
  35. package/engine/content-lint.mjs +64 -34
  36. package/engine/content-package.mjs +7 -9
  37. package/engine/content-slug.mjs +2 -2
  38. package/engine/content-tables.mjs +38 -34
  39. package/engine/content-tree.mjs +1 -1
  40. package/engine/derived-fields.mjs +174 -0
  41. package/engine/diagnostics.mjs +3 -4
  42. package/engine/document-subtypes.mjs +6 -7
  43. package/engine/field-reference.mjs +8 -8
  44. package/engine/field-spec.mjs +29 -30
  45. package/engine/folder-notes.mjs +18 -16
  46. package/engine/foreign-catalog.mjs +8 -9
  47. package/engine/foundry-entries.mjs +19 -20
  48. package/engine/frontmatter-lint.mjs +95 -103
  49. package/engine/frontmatter.mjs +11 -11
  50. package/engine/generate.mjs +44 -39
  51. package/engine/helpers.mjs +147 -84
  52. package/engine/homepage.mjs +20 -22
  53. package/engine/ids.mjs +15 -15
  54. package/engine/index-records.mjs +4 -4
  55. package/engine/index.mjs +26 -10
  56. package/engine/item-compiler.mjs +54 -29
  57. package/engine/item-docs.mjs +11 -13
  58. package/engine/item-registry.mjs +13 -13
  59. package/engine/journals.mjs +24 -15
  60. package/engine/macros.mjs +3 -3
  61. package/engine/map-notes.mjs +6 -6
  62. package/engine/metadata-index.mjs +5 -5
  63. package/engine/note-claims.mjs +51 -41
  64. package/engine/note-ids.mjs +5 -5
  65. package/engine/note-package.mjs +4 -4
  66. package/engine/note-renames.mjs +3 -3
  67. package/engine/note-schemas.mjs +3 -8
  68. package/engine/note-vocabulary.mjs +56 -54
  69. package/engine/pack-config.mjs +39 -25
  70. package/engine/pack-router.mjs +0 -0
  71. package/engine/pdf-build.mjs +464 -0
  72. package/engine/pdf-fonts.mjs +420 -0
  73. package/engine/pdf-render.mjs +798 -0
  74. package/engine/pdf-toc.mjs +525 -0
  75. package/engine/prose-config.mjs +9 -9
  76. package/engine/prose-lint.mjs +12 -13
  77. package/engine/region-events.mjs +2 -2
  78. package/engine/retired-fields.mjs +24 -22
  79. package/engine/runtime-only-fields.mjs +1 -1
  80. package/engine/scene-levels.mjs +1 -1
  81. package/engine/scenes.mjs +33 -25
  82. package/engine/schema-check.mjs +21 -21
  83. package/engine/schema-extract.mjs +1 -1
  84. package/engine/site-build.mjs +66 -50
  85. package/engine/site-index.mjs +17 -18
  86. package/engine/sql-tables.mjs +21 -13
  87. package/engine/subtype-registry.mjs +5 -4
  88. package/engine/system-block.mjs +18 -19
  89. package/engine/systems.mjs +2 -2
  90. package/engine/web-wikilinks.mjs +41 -38
  91. package/engine/wikilink-syntax.mjs +16 -16
  92. package/engine/wikilinks.mjs +40 -42
  93. package/hm3/actors.mjs +30 -22
  94. package/hm3/document-subtypes.mjs +5 -5
  95. package/hm3/index.mjs +2 -2
  96. package/hm3/item-builders.mjs +1 -1
  97. package/hm3/item-fields.mjs +3 -3
  98. package/hm3/items.mjs +28 -8
  99. package/hm3/template-priority.mjs +2 -2
  100. package/lang.mjs +3 -3
  101. package/manifest.mjs +17 -20
  102. package/package.json +1 -2
  103. package/release.mjs +66 -6
  104. package/sohl/actors.mjs +36 -28
  105. package/sohl/affiliation-standings.mjs +2 -2
  106. package/sohl/being-info.mjs +5 -5
  107. package/sohl/default-item-art.mjs +5 -5
  108. package/sohl/document-subtypes.mjs +5 -5
  109. package/sohl/index.mjs +3 -3
  110. package/sohl/item-builders.mjs +7 -7
  111. package/sohl/item-fields.mjs +8 -9
  112. package/sohl/items.mjs +28 -6
  113. package/sohl/kb-passes.mjs +5 -5
  114. package/sohl/note-schemas.mjs +12 -12
  115. package/sohl/skill-base.mjs +1 -1
  116. package/types/content-config.d.mts +91 -39
  117. package/types/e2e.d.mts +3 -3
  118. package/types/engine/actor-compiler.d.mts +45 -40
  119. package/types/engine/address-charset.d.mts +6 -6
  120. package/types/engine/address-diff.d.mts +60 -6
  121. package/types/engine/base-compiler.d.mts +27 -21
  122. package/types/engine/bundle-notes.d.mts +3 -3
  123. package/types/engine/bundles.d.mts +10 -1
  124. package/types/engine/code-fences.d.mts +3 -3
  125. package/types/engine/compendiums.d.mts +3 -3
  126. package/types/engine/compile-corpus.d.mts +1 -1
  127. package/types/engine/content-address.d.mts +20 -20
  128. package/types/engine/content-format-check.d.mts +6 -6
  129. package/types/engine/content-format.d.mts +2 -2
  130. package/types/engine/content-html.d.mts +78 -0
  131. package/types/engine/content-icons.d.mts +139 -92
  132. package/types/engine/content-index.d.mts +59 -15
  133. package/types/engine/content-links.d.mts +8 -8
  134. package/types/engine/content-lint.d.mts +8 -6
  135. package/types/engine/content-package.d.mts +6 -8
  136. package/types/engine/content-tables.d.mts +49 -18
  137. package/types/engine/derived-fields.d.mts +101 -0
  138. package/types/engine/diagnostics.d.mts +2 -2
  139. package/types/engine/document-subtypes.d.mts +3 -3
  140. package/types/engine/field-spec.d.mts +37 -39
  141. package/types/engine/folder-notes.d.mts +4 -5
  142. package/types/engine/foreign-catalog.d.mts +3 -3
  143. package/types/engine/foundry-entries.d.mts +6 -7
  144. package/types/engine/frontmatter-lint.d.mts +10 -9
  145. package/types/engine/frontmatter.d.mts +7 -7
  146. package/types/engine/generate.d.mts +7 -7
  147. package/types/engine/helpers.d.mts +128 -56
  148. package/types/engine/homepage.d.mts +16 -18
  149. package/types/engine/ids.d.mts +13 -13
  150. package/types/engine/index-records.d.mts +3 -3
  151. package/types/engine/index.d.mts +6 -0
  152. package/types/engine/item-compiler.d.mts +21 -5
  153. package/types/engine/item-docs.d.mts +2 -2
  154. package/types/engine/item-registry.d.mts +6 -6
  155. package/types/engine/journals.d.mts +12 -3
  156. package/types/engine/map-notes.d.mts +2 -2
  157. package/types/engine/metadata-index.d.mts +4 -4
  158. package/types/engine/note-claims.d.mts +30 -22
  159. package/types/engine/note-ids.d.mts +4 -4
  160. package/types/engine/note-package.d.mts +1 -1
  161. package/types/engine/note-renames.d.mts +3 -3
  162. package/types/engine/note-vocabulary.d.mts +31 -203
  163. package/types/engine/pack-config.d.mts +7 -7
  164. package/types/engine/pack-router.d.mts +1 -1
  165. package/types/engine/pdf-build.d.mts +42 -0
  166. package/types/engine/pdf-fonts.d.mts +30 -0
  167. package/types/engine/pdf-render.d.mts +144 -0
  168. package/types/engine/pdf-toc.d.mts +114 -0
  169. package/types/engine/prose-config.d.mts +9 -9
  170. package/types/engine/prose-lint.d.mts +3 -4
  171. package/types/engine/region-events.d.mts +2 -2
  172. package/types/engine/retired-fields.d.mts +10 -9
  173. package/types/engine/scenes.d.mts +10 -1
  174. package/types/engine/schema-check.d.mts +13 -13
  175. package/types/engine/site-build.d.mts +52 -25
  176. package/types/engine/site-index.d.mts +3 -4
  177. package/types/engine/sql-tables.d.mts +11 -5
  178. package/types/engine/subtype-registry.d.mts +3 -3
  179. package/types/engine/system-block.d.mts +3 -3
  180. package/types/engine/web-wikilinks.d.mts +7 -7
  181. package/types/engine/wikilink-syntax.d.mts +17 -17
  182. package/types/engine/wikilinks.d.mts +14 -14
  183. package/types/hm3/actors.d.mts +9 -1
  184. package/types/hm3/document-subtypes.d.mts +1 -1
  185. package/types/hm3/items.d.mts +9 -2
  186. package/types/hm3/template-priority.d.mts +1 -1
  187. package/types/manifest.d.mts +8 -8
  188. package/types/release.d.mts +15 -4
  189. package/types/sohl/actors.d.mts +12 -4
  190. package/types/sohl/affiliation-standings.d.mts +2 -2
  191. package/types/sohl/being-info.d.mts +2 -2
  192. package/types/sohl/document-subtypes.d.mts +1 -1
  193. package/types/sohl/items.d.mts +9 -2
  194. package/types/sohl/note-schemas.d.mts +1 -1
  195. package/MIGRATING.md +0 -608
@@ -80,7 +80,7 @@ A tag that classifies the subject is different, because something queries it. A
80
80
  settlement tagged `village` appears in the list of villages and an untagged one
81
81
  does not, so `vilage` does not merely look wrong: it removes the note from an
82
82
  index, silently, and the index still renders. That is the same failure a
83
- misspelled `data:` key used to be, and it gets the same answer — the vocabulary
83
+ misspelled `data:` key is, and it gets the same answer — the vocabulary
84
84
  is declared, so a near miss is a finding that names what you probably meant.
85
85
 
86
86
  | group | applies to | tags |
@@ -146,9 +146,9 @@ the corpus moves, with the block winning. A field says so by naming each: its
146
146
  shared source, and the legacy in-block key it is being swept off. Reading it
147
147
  from the legacy position is _reported_, so the sweep has a progress signal, and
148
148
  the note compiles to the identical document either way — the same read-both,
149
- report-one shape every other retirement in this format uses. Until #305 the two
150
- were one declaration, so a field could name only one of them, and a row this
151
- table stated was reachable only by a note that had already moved.
149
+ report-one shape every other retirement in this format uses. As one
150
+ declaration the two would let a field name only one of them, and a row this
151
+ table states would be reachable only by a note that had already moved.
152
152
 
153
153
  **A field whose spelling means something else at the note level has no shared
154
154
  source.** The fallback assumes the two vocabularies agree about what a name
@@ -166,8 +166,8 @@ them.** A data model declares everything a document stores, and part of that is
166
166
  what _play_ writes: an affliction's `onsetDate` is the world time its onset
167
167
  fired at. Writing `<system>.system.<field>` reaches such a field as directly as
168
168
  any other — the block is a verbatim passthrough, and the field really is in the
169
- schema — so until #330 a note could stamp one, and the compiled pack shipped one
170
- world's play state to every world that installed it.
169
+ schema — so a note left free to stamp one ships that world's play state to
170
+ every world that installs the compiled pack.
171
171
 
172
172
  So a field the document writes for itself is **declared as such**, and the
173
173
  declaration says both halves of the fact: authoring it is an error naming the
@@ -225,7 +225,7 @@ is a gap in the vocabulary rather than something to write into every note: an
225
225
  override that thousands of notes need is a missing subType value.
226
226
 
227
227
  **A type's `subType` values are stated in one shape**, so that they can be read
228
- and compared to the vocabulary that enforces them (#345). Under the type's
228
+ and compared to the vocabulary that enforces them. Under the type's
229
229
  heading, write `**subType**:` on a line of its own, then one bullet per value —
230
230
  `- <value>` or `- <value>: <definition>` — and nothing else between the marker
231
231
  and the list. A type that has no `subType`, or whose values are not enumerated
@@ -295,7 +295,7 @@ at the note's top level and `portrait` moved under `data:`, because a note's
295
295
  token art is a fact about the _note as a published artefact_ while the portrait
296
296
  is a fact about the _subject_.
297
297
 
298
- **A `data:` source is still read at the top level, for now.** `data:` (#128) did
298
+ **A `data:` source is still read at the top level, for now.** `data:` did
299
299
  not invent the facts it holds — it gathered them out of the top level, where
300
300
  `portrait:` sat beside `img:` — so every key it collected has a **pre-`data:`
301
301
  spelling** that is read after the declared one and reported as retiring. Write
@@ -328,7 +328,7 @@ NA on both sides for that type, and its table says so.
328
328
  template priority on an Actor and not on an Item: `hm3/actors.mjs` writes
329
329
  `flags.hm3.templatePriority`, and HM3's Item pass writes no equivalent, so an HM3
330
330
  item compiled from a template note loses the fact that it is one
331
- (`HeroicLands/package-build#283`). The row states the mapping the format makes;
331
+ The row states the mapping the format makes;
332
332
  the gap is in the pass, not in the table.
333
333
 
334
334
  #### An asset path's first segment says which package owns it
@@ -346,7 +346,10 @@ there are exactly three answers:
346
346
 
347
347
  `<assetRoot>` is `<packageKind>/<foundryPackage>/assets`, derived from the
348
348
  configuration — `systems/sohl/assets` for the system,
349
- `modules/sohl-thalorna/assets` for that module. So one authored
349
+ `modules/sohl-thalorna/assets` for that module. A `documentation` package has
350
+ no asset root at all, because Foundry installs no such package and serves no
351
+ files for it: there, the third row is refused, and a note names the owning
352
+ package (`systems/…`, `modules/…`) or a URL. So one authored
350
353
  `icons/relic.svg` means "my own `assets/icons/relic.svg`" in whichever package
351
354
  writes it, while an authored `systems/sohl/assets/icons/noun/shield.svg` names
352
355
  the system's file and is left exactly as written wherever it appears. That
@@ -449,7 +452,7 @@ The shared mapping table above names it `data.templatePriority`, targeting
449
452
 
450
453
  > **`archetype` is the retiring spelling.** It is still read, in the `sohl:`
451
454
  > block and at the top level, so a tree sweeps on its own schedule
452
- > (`HeroicLands/package-build#266`) — but the frontmatter linter refuses it, and
455
+ > — but the frontmatter linter refuses it, and
453
456
  > what is compiled and emitted is `templatePriority` on all three sides.
454
457
  >
455
458
  > It is more than a rename, and the collision is **already live** rather than
@@ -481,7 +484,7 @@ real priority** — the one SoHL's own templates ship at — not an absence.
481
484
  it.** SoHL records it in `system`; HM3 keeps it under its own flag scope,
482
485
  `flags.hm3`, and a note that is not a template writes nothing there rather than a
483
486
  `null` nothing reads. Both of HM3's passes write it — an Item's flag was missing
484
- until `HeroicLands/package-build#283`, which made an item note's priority reach
487
+ until an item note's priority reached
485
488
  SoHL and stop at HM3, with nothing said on either side.
486
489
 
487
490
  **How a winner is chosen.** Opening a Create dialog gathers every candidate
@@ -543,7 +546,7 @@ folder pass for a folder, the journals pass for a documentation journal, this
543
546
  rule for everything else. Re-deriving one from the `canonical` key alone reads
544
547
  correctly and is wrong for a folder, and wrong in a way nothing outside the
545
548
  build can detect: the result is a plausible 16-character id that resolves to
546
- nothing (#310).
549
+ nothing.
547
550
 
548
551
  **Why the address and not an authored string.** A note used to declare an
549
552
  opaque 16-character `id` — 6,343 of them across the four content trees — which
@@ -674,7 +677,7 @@ the journals pack having to declare anything. A folder nothing references
674
677
  materialises nowhere.
675
678
 
676
679
  That derivation is what makes a whole class of defect unrepresentable. The
677
- folder used to be declared twice, once per pack, in two files free to disagree:
680
+ folder declared twice, once per pack, sits in two files free to disagree:
678
681
  `sohl-thalorna` was missing 57 of its item folders from its journal folder file
679
682
  and `sohl-kethira-basic` had no journal folder file at all, so both emitted
680
683
  documentation journals into folders their own pack never declared — silently.
@@ -689,7 +692,7 @@ the first.
689
692
 
690
693
  > **`folder:` was a Foundry id**, resolved against a per-pack
691
694
  > `*-folders.yaml` — five files per tree. Both halves are **retired** together
692
- > (#260): the id spelling has nothing left to resolve against once the YAML is
695
+ > : the id spelling has nothing left to resolve against once the YAML is
693
696
  > gone, and the YAML has no reader once the spelling is refused. A note that
694
697
  > still writes `folder:` fails the build, naming `packFolder` and the line to
695
698
  > rewrite, rather than being ignored — a retired field left ignored reads to
@@ -812,26 +815,26 @@ Only a type whose own document carries a system is redirected this way. A
812
815
  documents are core ones already at `none`, so `macro-autoattack` names the Macro
813
816
  and `docmacro-autoattack` its journal — two live addresses.
814
817
 
815
- **An address is lowercase throughout** (#340). Every segment — package,
818
+ **An address is lowercase throughout**. Every segment — package,
816
819
  system, type and shortcode alike — is `^[a-z0-9]+$`, so a capital anywhere in an
817
820
  address is an error naming the lowercase form.
818
821
 
819
- The shortcode was the exception until #340: it was case-sensitive and routinely
822
+ The shortcode is the one that would otherwise be case-sensitive and routinely
820
823
  mixed (`Clb`, `LtShoe`, `HsTunic`) while the address built from it was lowercased
821
824
  wholesale, so the authored name and its address disagreed. Two names differing
822
825
  only in case are two names nobody can tell apart, and they collapsed onto one
823
826
  address, one `_id` and one URL with nothing to report it.
824
827
 
825
828
  **Parsing is positional counting from the right, and nothing else.** Every
826
- segment is alphanumeric — shortcodes, **types** and **subTypes** are all
827
- `^[a-z0-9]+$`, systems come from a closed registry, and `contentPackage` is
828
- alphanumeric — so the hyphen is purely a separator. There is no longest-match
829
+ segment is lowercase alphanumeric — shortcodes, **types** and **subTypes** are
830
+ all `^[a-z0-9]+$`, systems come from a closed registry, and `contentPackage` is
831
+ `^[a-z0-9]+$` too — so the hyphen is purely a separator. There is no longest-match
829
832
  against a roster and no vocabulary check before splitting.
830
833
 
831
834
  **`type` and `subType` are held to that charset, not merely expected to meet
832
- it** (#206). A type is the first segment of every address, so a hyphen in one is
835
+ it**. A type is the first segment of every address, so a hyphen in one is
833
836
  read back as a segment boundary that was never meant as one. A `subType` reaches
834
- no address since #204 retired sections, but it is held to the same rule all the
837
+ no address, sections being retired, but it is held to the same rule all the
835
838
  same: it is a vocabulary term the whole toolchain keys on, one closed set away
836
839
  from being an address again, and a charset that holds for two of the three
837
840
  segments and half of a fourth is a rule nobody can state. Both are checked
@@ -846,7 +849,7 @@ One declared value broke the rule and has been renamed: a `doc`'s `user-guide`
846
849
  is now **`userguide`**. The old spelling was accepted for one transitional
847
850
  release, as a warning naming the replacement, so the 43 `sohl` notes authoring
848
851
  it were not invalidated by the release that renamed them. Every consumer tree
849
- has swept, so the acceptance is gone (#210) and `user-guide` is refused by the
852
+ has swept, so the acceptance is gone and `user-guide` is refused by the
850
853
  charset check — it contains a hyphen, which is the reason that always applied.
851
854
  No retirement-specific code outlived the sweep.
852
855
 
@@ -870,17 +873,17 @@ There is one namespace, and the pipe is required:
870
873
  | `[[WikiLink\|Text]]` | an address | `Text` |
871
874
  | `[[Name]]` | nothing | a finding |
872
875
 
873
- **A link written without a label addresses nothing** (#180), and the correction
876
+ **A link written without a label addresses nothing**, and the correction
874
877
  is always the same: write `[[type-shortcode|Text]]`.
875
878
 
876
- The bare form used to name an **alias** — a note's own display name, or one of
879
+ The bare form does not name an **alias** — a note's own display name, or one of
877
880
  the names it listed in `aliases:` — looked up within the citing note's type. It
878
881
  was measured before it was retired, and the namespace was empty in practice:
879
882
  across 8,305 wikilinks in three content trees, **not one** bare link resolved to
880
883
  a note. What the index behind it did do was fold every note's `name.full` into
881
884
  itself, so two notes of one type could not share a display name — a rules page
882
885
  and a user guide page both called "Gear" were a build failure whose every
883
- available fix moved a published URL (#179).
886
+ available fix moved a published URL.
884
887
 
885
888
  The top-level `aliases:` that fed it is **retired** and refused. The nested
886
889
  `name.aliases:` is **not**: it is reserved for a use that does not exist yet, so
@@ -901,7 +904,7 @@ page it is written on. It is the label that is required, not a target.
901
904
 
902
905
  #### Every address resolves, and every build says so the same way
903
906
 
904
- An address that names no note **fails the build** (#184) — in the link checker,
907
+ An address that names no note **fails the build** — in the link checker,
905
908
  in the pack compilers and in the site build alike.
906
909
 
907
910
  It was a warning in the checker and, in the site build, nothing at all while any
@@ -909,21 +912,21 @@ linkable package had no vendored manifest. The reasoning was that `[[Sunless
909
912
  Vault]]` might be a placeholder for a note somebody meant to write. That was a
910
913
  property of the **bare** form, which is retired, and the intent behind it has a
911
914
  real spelling now: a note tagged `draft` exists, resolves, compiles and
912
- publishes, and a link to it renders visibly marked (#183). So an address landing
915
+ publishes, and a link to it renders visibly marked. So an address landing
913
916
  nowhere is a typo or an omission, and both want fixing.
914
917
 
915
918
  There are six ways a link can fail, and each is one **error** with one message
916
919
  wherever it is met:
917
920
 
918
- | finding | what it means | the fix |
919
- | ---------------- | ----------------------------------------------- | ------------------------------------------------------ |
920
- | `unlabelled` | no `\|`, so the link addresses nothing | write `[[type-shortcode\|Text]]` |
921
- | `not-an-address` | labelled, but the target is not an address | write the address, not the name |
922
- | `not-lowercase` | any segment of the address is capitalised | lowercase it — every segment is lowercase |
923
- | `unknown-type` | qualified, but names no type this build knows | correct the type segment |
924
- | `unresolved` | parses as an address; nothing publishes it | fix the shortcode, or qualify to reach another package |
925
- | `ambiguous` | _unreachable since #336; kept for the manifest_ | — |
926
- | `unknown-anchor` | the address resolves; the `#section` does not | correct the anchor |
921
+ | finding | what it means | the fix |
922
+ | ---------------- | --------------------------------------------- | ------------------------------------------------------ |
923
+ | `unlabelled` | no `\|`, so the link addresses nothing | write `[[type-shortcode\|Text]]` |
924
+ | `not-an-address` | labelled, but the target is not an address | write the address, not the name |
925
+ | `not-lowercase` | any segment of the address is capitalised | lowercase it — every segment is lowercase |
926
+ | `unknown-type` | qualified, but names no type this build knows | correct the type segment |
927
+ | `unresolved` | parses as an address; nothing publishes it | fix the shortcode, or qualify to reach another package |
928
+ | `ambiguous` | _unreachable; kept for the manifest_ | — |
929
+ | `unknown-anchor` | the address resolves; the `#section` does not | correct the anchor |
927
930
 
928
931
  `ambiguous` no longer fires. An omitted segment defaults rather than wildcarding,
929
932
  so a written target expands to one canonical address and a lookup returns one
@@ -1021,10 +1024,10 @@ having nothing worth summarising.
1021
1024
  Every note in **both** groups still produces its JournalEntry and its web page.
1022
1025
  The difference is only whether a system Actor or Item is created as well.
1023
1026
 
1024
- That has been true of actors only since #337. A being used to produce its Actor
1025
- and nothing else, which left it the one system-bearing note with no address at
1026
- `none` — so a prose link naming it had nowhere to land. It now carries a
1027
- documentation journal like every other such note, addressed
1027
+ That includes actors. A being producing its Actor and nothing else would be
1028
+ the one system-bearing note with no address at `none`, leaving a prose link
1029
+ naming it nowhere to land. It carries a documentation journal like every other
1030
+ such note, addressed
1028
1031
  `<package>-none-docbeing-<shortcode>` beside the Actor's
1029
1032
  `<package>-<system>-being-<shortcode>`.
1030
1033
 
@@ -1116,7 +1119,7 @@ still rendered — the finding is the point, not withholding the output.
1116
1119
  ##### In SQL, over the content index
1117
1120
 
1118
1121
  `dataview` is being replaced by **SQL**, queried over the content index, and both
1119
- fences work while the corpus is converted (#246). The query is real SQL, run by
1122
+ fences work while the corpus is converted. The query is real SQL, run by
1120
1123
  DuckDB — not a dialect maintained by this package.
1121
1124
 
1122
1125
  ````markdown
@@ -1148,7 +1151,7 @@ relational operations:
1148
1151
  | `_section` | Emits a headed table per distinct value, in the order the rows arrive. |
1149
1152
 
1150
1153
  `_section` is why one query replaces the forty near-identical blocks a grouped
1151
- table used to need: the authored `ORDER BY` decides the section order too.
1154
+ table would otherwise need: the authored `ORDER BY` decides the section order too.
1152
1155
 
1153
1156
  **Beware `packFolder`.** It is a note's _pack_ folder, not its directory — the
1154
1157
  directory is `file.folder`. (The `folder` field it replaced is retired; a query
@@ -1351,7 +1354,7 @@ sohl:
1351
1354
  durability: 0
1352
1355
  ```
1353
1356
 
1354
- **A top-level `shortcode:` is retired** (#334). It selected a template, while the
1357
+ **A top-level `shortcode:` is retired**. It selected a template, while the
1355
1358
  `system.shortcode` beside it was the compiled item's identity — one word for two
1356
1359
  things — and it could not say which package a template came from, so an address
1357
1360
  resolved into a dependency only because no local pack claimed it and would have
@@ -1391,7 +1394,7 @@ shortcode)` — compendium/world reconciliation, template shadowing, cohort
1391
1394
  membership, effect and expression references. A `name` cannot stand in: it is
1392
1395
  presentation, free to be localized or to diverge.
1393
1396
 
1394
- **Reordering the list moves no id.** The key used to carry the entry's position,
1397
+ **Reordering the list moves no id.** A key carrying the entry's position
1395
1398
  so inserting an item renumbered every id after it and a re-import created new
1396
1399
  documents beside the old ones — while nothing about those documents had changed,
1397
1400
  only their neighbours. The same is now true of a note's journal pages: an
@@ -1612,7 +1615,7 @@ the heading its page is published under; an affiliation's `system.title` is _the
1612
1615
  style of address the office carries_, Ajaw or Warden, which a being holds by
1613
1616
  virtue of its rank. So the top-level key is **not** a shared source for this
1614
1617
  field, and a note that writes one is stating its own heading and nothing else
1615
- (#218). Author the style of address on the membership — the `system.title` of the
1618
+ . Author the style of address on the membership — the `system.title` of the
1616
1619
  entry in a being's `sohl.items` — or, on a catalogue note that genuinely carries
1617
1620
  one, at `sohl.system.title`.
1618
1621
 
@@ -2111,11 +2114,11 @@ depicts what it depicts. A place's maps are therefore derived — every map whos
2111
2114
  The three differ only in the canvas defaults derived for them, which is why they
2112
2115
  are subTypes of one type rather than three types.
2113
2116
 
2114
- > The three were **types** until package-build#174, which is the shape the notes
2115
- > in the wild still carry. Both are read: a note still writing `type: battlemap`
2116
- > is reported and told what to write instead, exactly as a note writing
2117
- > `type: character` is (SoHL#1580). A consumer's `sections` config keys off the
2118
- > type, so it takes one `map` entry where it carried three.
2117
+ > The three are also readable as **types**, which is the shape notes in the
2118
+ > wild still carry: a note writing `type: battlemap` is reported and told what
2119
+ > to write instead, exactly as a note writing `type: character` is. A
2120
+ > consumer's `sections` config keys off the type, so it takes one `map` entry
2121
+ > rather than three.
2119
2122
 
2120
2123
  **NoteLocation** is `[GridLocation, anchor]` where the `anchor` is an anchor identified in the body of the note, and `GridLocation` represents a particular grid location on the document.
2121
2124
 
@@ -2153,24 +2156,13 @@ compilation, and the server-side migration shim is version-gated on
2153
2156
  single Level is synthesised from `img`, `overlay`, `levelName` and
2154
2157
  `backgroundColor`.
2155
2158
 
2156
- > **`img`, at the note's top level, as every other type's artwork is.** A map
2157
- > alone named it `image` and read it out of the `sohl:` block, so one idea had
2158
- > two spellings and this table had to hedge rather than state a rule
2159
- > ([package-build#142](https://github.com/HeroicLands/package-build/issues/142)).
2160
- > Art is not system-specific — a Scene is a core Foundry document, and a second
2161
- > system would want the identical art — so the field sits beside every other
2162
- > note's `img` rather than inside a system block.
2159
+ > **`img`, at the note's top level, as every other type's artwork is.** Art is
2160
+ > not system-specific a Scene is a core Foundry document, and a second system
2161
+ > would want the identical art so the field sits beside every other note's
2162
+ > `img` rather than inside a system block.
2163
2163
  >
2164
- > `image` was **retired in favour of it**, in the three steps `package:` took
2165
- > (#56), and all three have now run
2166
- > ([package-build#149](https://github.com/HeroicLands/package-build/issues/149)).
2167
- > Through the window both spellings were read, `img` won where a note carried
2168
- > both, and a note still writing `image` got a located **warning** rather than a
2169
- > refusal — it compiled to the byte-identical document, so failing a build over
2170
- > it would have redded a tree that had done nothing wrong. The trees were then
2171
- > swept, and the alias dropped. `image` is now simply not a key a map has: in a
2172
- > `sohl:` block it is reported as unknown, and either way the note is refused
2173
- > for the `img` it never declared.
2164
+ > `image` is **not a key a map has**: in a `sohl:` block it is reported as
2165
+ > unknown, and either way the note is refused for the `img` it never declared.
2174
2166
 
2175
2167
  **Two unit conventions, deliberately.** Geometry — walls, doors, lights, tiles,
2176
2168
  sounds, region shapes — is authored in **pixels**, Foundry's native storage,
@@ -2277,9 +2269,15 @@ Content prepared to be played — a situation with its cast, places, and possibl
2277
2269
  - rules: The rules of the game, independent of medium — valid at a table with paper and dice.
2278
2270
  - userguide: How to operate the Foundry implementation to play by the rules.
2279
2271
  - reference: Out-of-world lookup material about the setting or system — correspondences, conversions, glossaries.
2272
+ - howto: A task with an outcome, written as the steps that reach it.
2273
+ - concept: An explanation of how something works and why it is shaped that way, read to understand rather than to follow.
2280
2274
 
2281
2275
  A `doc` declares no properties of its own.
2282
2276
 
2277
+ The field is a genre and only a genre: it says what kind of page this is, never
2278
+ who reads it. A page written for a developer is a `howto` or a `concept` like
2279
+ any other, and the audience is the section it sits in.
2280
+
2283
2281
  **A page that introduces a type is an ordinary note, named by convention.**
2284
2282
  Write `type: doc`, `subType: reference`, `shortcode: <type>` — so the
2285
2283
  affiliations introduction is `doc-affiliation`, addressed and linked like
@@ -2289,8 +2287,8 @@ way (`homepage-root`).
2289
2287
 
2290
2288
  There is no landing page and no section. A `README.md` used to _be_ its
2291
2289
  section's landing, and a `subType: collection` note with a top-level `section:`
2292
- key was a second way to say the same thing. All of it is retired the second
2293
- rule in #202, the first in #204 — because a section appears in **no address**: a
2290
+ key was a second way to say the same thing. All of it is retired, because a
2291
+ section appears in **no address**: a
2294
2292
  page publishes at `/<package>/<type>-<shortcode>/`, which names no directory. A
2295
2293
  section is what Hugo calls a content directory, and the note format does not
2296
2294
  carry one.
@@ -2440,7 +2438,7 @@ an Adventure pack declared first still compiles last.
2440
2438
 
2441
2439
  Foundry's `Folder` — the grouping documents are filed in, and the last document
2442
2440
  this package compiled from bespoke configuration (`*-folders.yaml`, five files
2443
- per tree) rather than from a note. Those files are retired (#260); a pack that
2441
+ per tree) rather than from a note. Those files are retired; a pack that
2444
2442
  still names one is refused.
2445
2443
 
2446
2444
  ```yaml
@@ -2463,8 +2461,9 @@ data:
2463
2461
  A folder is addressed `<package>-none-folder-<shortcode>` — **`none`**, because a
2464
2462
  `Folder` is a core Foundry document like a `JournalEntry` or a `Scene`, not a
2465
2463
  system's. Its shortcode is [an address segment](#the-canonical-address) like
2466
- every other, so it is strictly alphanumeric: `possessionscooking`, never
2467
- `possessions-cooking`, which would read as two segments and resolve to nothing.
2464
+ every other, so it is strictly lowercase alphanumeric: `possessionscooking`,
2465
+ never `possessions-cooking`, which would read as two segments and resolve to
2466
+ nothing.
2468
2467
 
2469
2468
  **`color` must be quoted**, and YAML gives no third option: `color: #7a4b2a`
2470
2469
  parses as `null` (a `#` after a space opens a comment) and `color: 000000` parses
@@ -2519,4 +2518,4 @@ the namespace is **`folder`**, not the `document` one [every other note hashes
2519
2518
  under](#the-document-id): a folder and an item sharing a shortcode would
2520
2519
  otherwise derive the same id, and Foundry keys the two in separate collections
2521
2520
  so neither would complain. The content index publishes this value, so a consumer
2522
- reads a folder's id rather than recomputing one (#310).
2521
+ reads a folder's id rather than recomputing one.