@heroiclands/package-build 20.3.1 → 20.4.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 (178) hide show
  1. package/CHANGELOG.md +75 -0
  2. package/CONTENT.md +111 -92
  3. package/README.md +2 -9
  4. package/bin/content-build.mjs +70 -61
  5. package/bin/package-build.mjs +2 -2
  6. package/config.mjs +6 -8
  7. package/content-config.mjs +187 -64
  8. package/docs/content-format.md +57 -68
  9. package/e2e.mjs +4 -4
  10. package/engine/actor-compiler.mjs +36 -36
  11. package/engine/address-charset.mjs +6 -6
  12. package/engine/address-diff.mjs +12 -11
  13. package/engine/anchored-sections.mjs +1 -1
  14. package/engine/anchors.mjs +1 -1
  15. package/engine/base-compiler.mjs +36 -38
  16. package/engine/bundle-notes.mjs +4 -4
  17. package/engine/bundles.mjs +8 -8
  18. package/engine/code-fences.mjs +3 -3
  19. package/engine/compendiums.mjs +8 -8
  20. package/engine/compile-corpus.mjs +4 -5
  21. package/engine/content-address.mjs +15 -15
  22. package/engine/content-charset.mjs +1 -1
  23. package/engine/content-format-check.mjs +24 -25
  24. package/engine/content-format.mjs +8 -8
  25. package/engine/content-html.mjs +202 -0
  26. package/engine/content-icons.mjs +196 -165
  27. package/engine/content-index.mjs +17 -17
  28. package/engine/content-links.mjs +30 -30
  29. package/engine/content-lint.mjs +20 -24
  30. package/engine/content-package.mjs +7 -9
  31. package/engine/content-slug.mjs +2 -2
  32. package/engine/content-tables.mjs +7 -8
  33. package/engine/content-tree.mjs +1 -1
  34. package/engine/derived-fields.mjs +174 -0
  35. package/engine/diagnostics.mjs +3 -4
  36. package/engine/document-subtypes.mjs +6 -7
  37. package/engine/field-reference.mjs +8 -8
  38. package/engine/field-spec.mjs +29 -30
  39. package/engine/folder-notes.mjs +14 -14
  40. package/engine/foreign-catalog.mjs +8 -9
  41. package/engine/foundry-entries.mjs +19 -20
  42. package/engine/frontmatter-lint.mjs +64 -69
  43. package/engine/frontmatter.mjs +11 -11
  44. package/engine/generate.mjs +39 -39
  45. package/engine/helpers.mjs +63 -54
  46. package/engine/homepage.mjs +20 -22
  47. package/engine/ids.mjs +15 -15
  48. package/engine/index-records.mjs +4 -4
  49. package/engine/index.mjs +14 -8
  50. package/engine/item-compiler.mjs +54 -29
  51. package/engine/item-docs.mjs +11 -13
  52. package/engine/item-registry.mjs +13 -13
  53. package/engine/journals.mjs +15 -15
  54. package/engine/macros.mjs +3 -3
  55. package/engine/map-notes.mjs +6 -6
  56. package/engine/metadata-index.mjs +5 -5
  57. package/engine/note-claims.mjs +36 -34
  58. package/engine/note-ids.mjs +5 -5
  59. package/engine/note-package.mjs +4 -4
  60. package/engine/note-renames.mjs +3 -3
  61. package/engine/note-schemas.mjs +3 -3
  62. package/engine/note-vocabulary.mjs +27 -26
  63. package/engine/pack-config.mjs +13 -13
  64. package/engine/pack-router.mjs +0 -0
  65. package/engine/prose-config.mjs +9 -9
  66. package/engine/prose-lint.mjs +12 -13
  67. package/engine/region-events.mjs +2 -2
  68. package/engine/retired-fields.mjs +24 -22
  69. package/engine/runtime-only-fields.mjs +1 -1
  70. package/engine/scene-levels.mjs +1 -1
  71. package/engine/scenes.mjs +19 -20
  72. package/engine/schema-check.mjs +20 -20
  73. package/engine/schema-extract.mjs +1 -1
  74. package/engine/site-build.mjs +45 -47
  75. package/engine/site-index.mjs +17 -18
  76. package/engine/sql-tables.mjs +21 -13
  77. package/engine/subtype-registry.mjs +5 -4
  78. package/engine/system-block.mjs +18 -19
  79. package/engine/systems.mjs +2 -2
  80. package/engine/web-wikilinks.mjs +35 -35
  81. package/engine/wikilink-syntax.mjs +16 -16
  82. package/engine/wikilinks.mjs +39 -39
  83. package/hm3/actors.mjs +22 -22
  84. package/hm3/document-subtypes.mjs +5 -5
  85. package/hm3/index.mjs +2 -2
  86. package/hm3/item-builders.mjs +1 -1
  87. package/hm3/item-fields.mjs +3 -3
  88. package/hm3/items.mjs +20 -8
  89. package/hm3/template-priority.mjs +2 -2
  90. package/lang.mjs +3 -3
  91. package/manifest.mjs +17 -20
  92. package/package.json +1 -2
  93. package/release.mjs +3 -3
  94. package/sohl/actors.mjs +28 -28
  95. package/sohl/affiliation-standings.mjs +2 -2
  96. package/sohl/being-info.mjs +5 -5
  97. package/sohl/default-item-art.mjs +5 -5
  98. package/sohl/document-subtypes.mjs +5 -5
  99. package/sohl/index.mjs +3 -3
  100. package/sohl/item-builders.mjs +7 -7
  101. package/sohl/item-fields.mjs +8 -9
  102. package/sohl/items.mjs +20 -6
  103. package/sohl/kb-passes.mjs +5 -5
  104. package/sohl/note-schemas.mjs +7 -7
  105. package/sohl/skill-base.mjs +1 -1
  106. package/types/content-config.d.mts +25 -24
  107. package/types/e2e.d.mts +3 -3
  108. package/types/engine/actor-compiler.d.mts +14 -13
  109. package/types/engine/address-charset.d.mts +6 -6
  110. package/types/engine/address-diff.d.mts +3 -3
  111. package/types/engine/base-compiler.d.mts +17 -19
  112. package/types/engine/bundle-notes.d.mts +3 -3
  113. package/types/engine/bundles.d.mts +1 -1
  114. package/types/engine/code-fences.d.mts +3 -3
  115. package/types/engine/compendiums.d.mts +3 -3
  116. package/types/engine/compile-corpus.d.mts +1 -1
  117. package/types/engine/content-address.d.mts +11 -11
  118. package/types/engine/content-format-check.d.mts +6 -6
  119. package/types/engine/content-format.d.mts +2 -2
  120. package/types/engine/content-html.d.mts +78 -0
  121. package/types/engine/content-icons.d.mts +139 -92
  122. package/types/engine/content-index.d.mts +2 -2
  123. package/types/engine/content-links.d.mts +8 -8
  124. package/types/engine/content-lint.d.mts +2 -2
  125. package/types/engine/content-package.d.mts +6 -8
  126. package/types/engine/derived-fields.d.mts +101 -0
  127. package/types/engine/diagnostics.d.mts +2 -2
  128. package/types/engine/document-subtypes.d.mts +3 -3
  129. package/types/engine/field-spec.d.mts +37 -39
  130. package/types/engine/folder-notes.d.mts +4 -5
  131. package/types/engine/foreign-catalog.d.mts +3 -3
  132. package/types/engine/foundry-entries.d.mts +6 -7
  133. package/types/engine/frontmatter-lint.d.mts +7 -7
  134. package/types/engine/frontmatter.d.mts +7 -7
  135. package/types/engine/generate.d.mts +7 -7
  136. package/types/engine/helpers.d.mts +25 -27
  137. package/types/engine/homepage.d.mts +16 -18
  138. package/types/engine/ids.d.mts +13 -13
  139. package/types/engine/index-records.d.mts +3 -3
  140. package/types/engine/index.d.mts +2 -0
  141. package/types/engine/item-compiler.d.mts +21 -5
  142. package/types/engine/item-docs.d.mts +2 -2
  143. package/types/engine/item-registry.d.mts +6 -6
  144. package/types/engine/journals.d.mts +3 -3
  145. package/types/engine/map-notes.d.mts +2 -2
  146. package/types/engine/metadata-index.d.mts +4 -4
  147. package/types/engine/note-claims.d.mts +16 -15
  148. package/types/engine/note-ids.d.mts +4 -4
  149. package/types/engine/note-package.d.mts +1 -1
  150. package/types/engine/note-renames.d.mts +3 -3
  151. package/types/engine/note-vocabulary.d.mts +9 -8
  152. package/types/engine/pack-config.d.mts +3 -3
  153. package/types/engine/pack-router.d.mts +1 -1
  154. package/types/engine/prose-config.d.mts +9 -9
  155. package/types/engine/prose-lint.d.mts +3 -4
  156. package/types/engine/region-events.d.mts +2 -2
  157. package/types/engine/retired-fields.d.mts +10 -9
  158. package/types/engine/schema-check.d.mts +11 -11
  159. package/types/engine/site-build.d.mts +18 -19
  160. package/types/engine/site-index.d.mts +3 -4
  161. package/types/engine/sql-tables.d.mts +11 -5
  162. package/types/engine/subtype-registry.d.mts +3 -3
  163. package/types/engine/system-block.d.mts +3 -3
  164. package/types/engine/web-wikilinks.d.mts +7 -7
  165. package/types/engine/wikilink-syntax.d.mts +17 -17
  166. package/types/engine/wikilinks.d.mts +13 -12
  167. package/types/hm3/actors.d.mts +1 -1
  168. package/types/hm3/document-subtypes.d.mts +1 -1
  169. package/types/hm3/items.d.mts +1 -2
  170. package/types/hm3/template-priority.d.mts +1 -1
  171. package/types/manifest.d.mts +8 -8
  172. package/types/sohl/actors.d.mts +2 -2
  173. package/types/sohl/affiliation-standings.d.mts +2 -2
  174. package/types/sohl/being-info.d.mts +2 -2
  175. package/types/sohl/document-subtypes.d.mts +1 -1
  176. package/types/sohl/items.d.mts +1 -2
  177. package/types/sohl/note-schemas.d.mts +1 -1
  178. package/MIGRATING.md +0 -608
@@ -26,7 +26,7 @@
26
26
  * `aliases:`, `section:` and `traits:` have no such home — there is no
27
27
  * surviving concept any of them was part of — so they are refused here.
28
28
  *
29
- * **What `draft:` did (#69).** It excluded a note from the compiled packs, from
29
+ * **What `draft:` did.** It excluded a note from the compiled packs, from
30
30
  * the link manifest and from a consuming site build. Nothing reported the
31
31
  * consequence: `content-links.mjs`, `site-index.mjs` and `content-lint.mjs`
32
32
  * never read the field, so a link into a drafted note was indistinguishable
@@ -35,13 +35,13 @@
35
35
  * *unresolvable*, silently — and it also suppressed real build failures, since
36
36
  * a note the compilers never reached could not fail on the defects it carried.
37
37
  *
38
- * **What `aliases:` did (#180).** It fed the alias index, which is what a bare
38
+ * **What `aliases:` did.** It fed the alias index, which is what a bare
39
39
  * `[[Alias]]` was looked up in. That form resolved to nothing anywhere in the
40
40
  * corpus, while the collision rule guarding it folded in every note's
41
- * `name.full` and so decided what a note could be named (#179). The form and
41
+ * `name.full` and so decided what a note could be named. The form and
42
42
  * the index are retired together, leaving the field with no reader at all.
43
43
  *
44
- * **What `section:` did (#202).** It named the section a `collection` note
44
+ * **What `section:` did.** It named the section a `collection` note
45
45
  * headed, under the `collection` landing rule — its only reader anywhere. That
46
46
  * rule is retired, a section being landed by the `README.md` in its directory,
47
47
  * so the field has none. No schema or vocabulary ever declared it either, and
@@ -56,11 +56,11 @@
56
56
  * reserved.test.ts` pins that equivalence so a future reader cannot be added
57
57
  * by accident.
58
58
  *
59
- * **What `traits:` did (#291).** It held a being's own description — gender,
59
+ * **What `traits:` did.** It held a being's own description — gender,
60
60
  * species, age, birthday, height, weight, frame and `appearance.*` — at the
61
61
  * note's top level. The content format gives those a home: `data:`, the closed
62
62
  * container for a subject's type-specific facts, which `being` declares every
63
- * one of them in. #128 moved all 2,533 notes that carried one, across four
63
+ * one of them in. Every note that carried one has been moved, across four
64
64
  * repositories, and this is the third step of that retirement.
65
65
  *
66
66
  * Refusing it matters more than refusing an ordinary dead key, because top
@@ -73,19 +73,19 @@
73
73
  * declares one, and the theme's gear sidebar reads it — so the refusal is
74
74
  * anchored at column 1 and never reaches inside a system block.
75
75
  *
76
- * **A field retired in favour of another is a third case (#142).** `draft:` and
76
+ * **A field retired in favour of another is a third case.** `draft:` and
77
77
  * `package:` were retired outright: nothing replaced them, so no value made
78
78
  * writing one right and refusal was the only honest answer. A *renamed* field
79
79
  * has a replacement, and the two spellings mean the same thing — so the note
80
80
  * still compiles, correctly, and refusing it would fail a build over a document
81
- * that is not wrong. Those retire in the three steps `package:` took (#56), and
81
+ * that is not wrong. Those retire in the three steps `package:` took, and
82
82
  * this module carries the **first**: both spellings are read, the current one
83
83
  * wins, and the retired one is *reported* rather than refused. See
84
84
  * {@link RETIRED_FIELD_ALIASES}.
85
85
  *
86
- * **The third step is deletion, and it needs no code (#149).** `image`, a map's
86
+ * **The third step is deletion, and it needs no code.** `image`, a map's
87
87
  * background art, is the first rename to have run all three: reported (#142),
88
- * swept (SoHL#1801 and the position move that followed), then dropped from the
88
+ * swept, then dropped from the
89
89
  * table. Removing the entry is the whole of it — with no alias, the spelling is
90
90
  * an ordinary unknown key in the `sohl:` block, which the frontmatter lint
91
91
  * already refuses as an error alongside the required field it failed to supply.
@@ -93,7 +93,7 @@
93
93
  * the record, and a retirement that needed a standing refusal would mean the
94
94
  * replacement never arrived. Do not keep a tombstone for one.
95
95
  *
96
- * **A retired *position* is the same case, and reads the same (#305).** A field
96
+ * **A retired *position* is the same case, and reads the same.** A field
97
97
  * whose shared source moved under `data:` is not renamed — `data.species` and
98
98
  * `hm3.species` are one field written in two places — but the retirement has
99
99
  * the identical shape: both are read, the one the note carries wins, and the
@@ -102,8 +102,9 @@
102
102
  * {@link module:engine/system-block.resolveFieldValue}'s answer; this module
103
103
  * only says what an author is told about it.
104
104
  *
105
- * **A field has two retiring positions, not one (#332).** The in-block key is
106
- * the obvious one; the other is the note's **top level**, because #128 did not
105
+ * **A field has two retiring positions, not one.** The in-block key is
106
+ * the obvious one; the other is the note's **top level**, because the sweep
107
+ * did not
107
108
  * invent the facts `data:` holds — it gathered them from exactly there. So
108
109
  * `portrait:` beside `img:` is the pre-`data:` spelling of `data.portrait`,
109
110
  * read for the same reason and reported by {@link retiredTopLevelMessage}. Both
@@ -184,11 +185,11 @@ export function assertNoDraftField(fm, { file, absPath } = {}) {
184
185
  * It says what the field fed and what to write instead, rather than which value
185
186
  * to correct: no value makes declaring it right.
186
187
  *
187
- * **What it did (#180).** It was the authored half of the alias index — the
188
+ * **What it did.** It was the authored half of the alias index — the
188
189
  * namespace a bare `[[Alias]]` was looked up in. Across the three content trees
189
190
  * not one bare link resolved through it, while the collision rule that kept it
190
191
  * unambiguous folded in every note's `name.full` and so dictated what a note
191
- * could be named (#179). The form is retired, so the list has no reader.
192
+ * could be named. The form is retired, so the list has no reader.
192
193
  *
193
194
  * **`name.aliases` is a different field and is not retired.** It fed the same
194
195
  * index, but unlike the top-level list it is being kept — reserved, unread,
@@ -275,10 +276,10 @@ export function declaresRetiredAliasesField(fm) {
275
276
  * It names what lands a section now rather than a value to correct: no value
276
277
  * makes declaring the field right.
277
278
  *
278
- * **What it did (#202).** It named the section a `collection` note headed,
279
+ * **What it did.** It named the section a `collection` note headed,
279
280
  * under the `collection` landing rule — the only reader it ever had, in the
280
281
  * second branch of `landingOf` (`engine/content-address.mjs`). That rule went
281
- * first, and the whole mechanism went with it (#204): a section is a Hugo
282
+ * first, and the whole mechanism went with it: a section is a Hugo
282
283
  * directory the note format does not carry, so no note lands one and a page
283
284
  * that introduces a type is an ordinary note addressed `doc-<type>`. Nothing
284
285
  * else read the field, and no schema or vocabulary declared it, so left in
@@ -438,14 +439,14 @@ export function locateFrontmatterKey(absPath, key, value = undefined, { topLevel
438
439
  * `relation` is retired on an affiliation — which declares `relations` — and
439
440
  * remains an unknown key anywhere else.
440
441
  *
441
- * **`templatePriority` (#266).** The number that decides which of several
442
+ * **`templatePriority`.** The number that decides which of several
442
443
  * competing templates the Create dialog offers was called `archetype`, and
443
444
  * `archetypes` — one letter apart — is a list of what *sort* a character is.
444
445
  * A priority and a taxonomy cannot be told apart by a plural `s`, so the
445
446
  * priority takes the name that says what it is. The specification already
446
447
  * called it `templatePriority` on two of its three sides.
447
448
  *
448
- * **`relations` (SoHL#1781).** The field holds a *map* of standings, one per
449
+ * **`relations`.** The field holds a *map* of standings, one per
449
450
  * affiliation — its own description says so, and `resolveRelation` has always
450
451
  * read it that way. `relation` named the many as one, which every author had to
451
452
  * read past. Only `affiliation` declares the field, so the alias is reported
@@ -488,7 +489,7 @@ export function retiredAliasMessage(retired, current, file) {
488
489
  * What a note writing a field at its **legacy in-block position** is told.
489
490
  *
490
491
  * The same three-step retirement `retiredAliasMessage` announces, applied to a
491
- * *position* rather than a spelling (#305). A field whose shared source moved
492
+ * *position* rather than a spelling. A field whose shared source moved
492
493
  * under `data:` keeps reading the key its block still carries, that read wins,
493
494
  * and it is reported here so a sweep has something to count down — without it,
494
495
  * moving a field into `data:` would be a flag day across every repository that
@@ -518,9 +519,10 @@ export function legacyKeyMessage(block, field, file) {
518
519
 
519
520
  /**
520
521
  * What a note writing a field at the **top-level key `data:` gathered it off**
521
- * is told (#332).
522
+ * is told.
522
523
  *
523
- * {@link legacyKeyMessage}'s counterpart for the other retiring position. #128
524
+ * {@link legacyKeyMessage}'s counterpart for the other retiring position. The
525
+ * sweep
524
526
  * did not invent the facts `data:` holds — it collected them out of the note's
525
527
  * open top level — so `portrait:` beside `img:` is the *pre-`data:`* spelling
526
528
  * of `data.portrait`, and both are read for the same reason both in-block
@@ -13,7 +13,7 @@
13
13
 
14
14
  /**
15
15
  * Schema fields a note may **never** author, because the document writes them
16
- * in play (#330).
16
+ * in play.
17
17
  *
18
18
  * `retired-fields.mjs` refuses a field a note may no longer declare; this
19
19
  * refuses one it never could. The two read alike deliberately — a note says one
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  /**
15
- * **Scene ↔ Level integrity** for a compiled compendium pack (issue #1538).
15
+ * **Scene ↔ Level integrity** for a compiled compendium pack.
16
16
  *
17
17
  * A v14 Scene keeps its map image on an embedded `Level`, and a compiled pack
18
18
  * stores the two in *separate* LevelDB keys: the Scene at `!scenes!<id>`
package/engine/scenes.mjs CHANGED
@@ -13,8 +13,7 @@
13
13
 
14
14
  /**
15
15
  * Scenes pack compiler — map notes in `assets/content/` → Foundry `Scene`
16
- * documents, and the `Adventure` bundles that make their references resolve
17
- * (issue #1525).
16
+ * documents, and the `Adventure` bundles that make their references resolve.
18
17
  *
19
18
  * The translation itself lives in the framework-free `map-notes.mjs`; this
20
19
  * module is the pass that walks the tree, resolves what one note says about
@@ -44,7 +43,7 @@
44
43
  *
45
44
  * The walk itself — filtering by type, expanding tables, converting
46
45
  * wikilinks, writing the JSON and counting errors — belongs to {@link sohl.utils.packs.BasePackCompiler}; this module
47
- * states only what makes this pass its own (#1509).
46
+ * states only what makes this pass its own.
48
47
  */
49
48
 
50
49
  import fs from "fs";
@@ -62,12 +61,12 @@ import {
62
61
  import { BasePackCompiler } from "./base-compiler.mjs";
63
62
  // What an Adventure member may carry is one rule, and the module that owns the
64
63
  // Adventure states it: the scenes pass bundles its pinned places, and the
65
- // bundles pass compiles a note into one (#259).
64
+ // bundles pass compiles a note into one.
66
65
  import { stripAdventureKeys } from "./bundle-notes.mjs";
67
66
  import { buildJournalEntry, splitPages, journalPageId } from "./journals.mjs";
68
67
  import { compendiumUuid, makeId, packForType } from "./ids.mjs";
69
68
  // The record accessors only — see `engine/index-records.mjs` for why they live
70
- // apart from the index that builds them (#243).
69
+ // apart from the index that builds them.
71
70
  import { authoredFrontmatter, isNoteRecord, noteFile } from "./index-records.mjs";
72
71
  import { packRouter } from "./pack-router.mjs";
73
72
  import { foundryPackageId } from "./content-package.mjs";
@@ -124,8 +123,8 @@ export class Scenes extends BasePackCompiler {
124
123
  * A map note's `img` is its background art, and it is **required**: the map
125
124
  * compiler refuses a note without one. It lands on the scene's level rather
126
125
  * than on a property spelled `img`, which makes no difference to the
127
- * question this declaration answers — the authored path reaches the output
128
- * (#349). The place Adventure this pass bundles carries it too.
126
+ * question this declaration answers — the authored path reaches the output.
127
+ * The place Adventure this pass bundles carries it too.
129
128
  *
130
129
  * @type {readonly string[]}
131
130
  */
@@ -182,7 +181,7 @@ export class Scenes extends BasePackCompiler {
182
181
  * `generatePack` hands every pass the one router the compile resolved, and
183
182
  * that is the answer whenever a real compile is running — a second router
184
183
  * is a second answer to where a document landed, built from whichever
185
- * configuration the working directory offers (#243). A compiler
184
+ * configuration the working directory offers. A compiler
186
185
  * constructed directly, as a consumer's or a test's is, has none, and falls
187
186
  * back exactly as `prepare` falls back to deriving its own corpus.
188
187
  *
@@ -196,19 +195,19 @@ export class Scenes extends BasePackCompiler {
196
195
  const maps = [];
197
196
  const effectsByAddress = new Map();
198
197
  // The corpus this compile derived once, not a walk of this pass's own
199
- // (#243) — and a note is opened only when this pass needs its *prose*,
198
+ // — and a note is opened only when this pass needs its *prose*,
200
199
  // which for a map note means three files in `sohl` rather than 1,685.
201
200
  for (const record of this.corpus.records) {
202
201
  if (!isNoteRecord(record)) continue;
203
202
  // No retired-field test: this pass's own walk — the shared compile
204
- // loop — is where a note still declaring `package:` (#56) or
205
- // `draft:` (#69) is reported, once. Repeating either check here
203
+ // loop — is where a note still declaring `package:` or
204
+ // `draft:` is reported, once. Repeating either check here
206
205
  // would double the diagnostic or throw past it. A refused note is
207
206
  // indexed and then never compiled, so it reaches no document.
208
207
  const fm = authoredFrontmatter(record);
209
208
  const absPath = noteFile(this.contentBase, record);
210
209
  // The id is the index's, derived against the configuration this
211
- // build resolved (#270, #243) — it was derived here through
210
+ // build resolved — it was derived here through
212
211
  // `resolveNoteId(fm)` with no package, which falls back to the
213
212
  // ambient one. What remains unset is a file with no address.
214
213
  if (!fm || !fm.id) continue;
@@ -218,10 +217,10 @@ export class Scenes extends BasePackCompiler {
218
217
  type: fm.type,
219
218
  // Where the owning item landed, so a region behaviour's
220
219
  // effect reference addresses the right pack when a
221
- // repository ships several of one type (#1566).
220
+ // repository ships several of one type.
222
221
  // This compile's router, not a freshly built one: a
223
222
  // second router is a second answer to where the document
224
- // landed, resolved from the working directory (#243).
223
+ // landed, resolved from the working directory.
225
224
  pack: this.#packRouter.resolveOrNull(fm, packForType(fm.type).docType),
226
225
  effects: fm.effects,
227
226
  });
@@ -409,7 +408,7 @@ export class Scenes extends BasePackCompiler {
409
408
  const name = resolveName(fm);
410
409
  const hasBody = Boolean(String(markdown).trim());
411
410
  // The same doc-entry id the journals pass derives, from the
412
- // shared `docEntryTypes` arrangement (#1514) — so neither
411
+ // shared `docEntryTypes` arrangement — so neither
413
412
  // pass has to read the other's output.
414
413
  const entryId = hasBody ? itemDocEntryId(fm.id) : undefined;
415
414
  const { value: authoredFolder } = folderField(fm);
@@ -423,8 +422,8 @@ export class Scenes extends BasePackCompiler {
423
422
  journalEntryId: entryId,
424
423
  // A map note's prose is a derived JournalEntry: it lands in the
425
424
  // default JournalEntry pack, not in whichever Scene pack the map
426
- // itself was routed to (#1566).
427
- // This compile's router, as everywhere else in this pass (#243).
425
+ // itself was routed to.
426
+ // This compile's router, as everywhere else in this pass.
428
427
  journalPack: this.#packRouter.defaultOf("JournalEntry"),
429
428
  pageIds: hasBody ? this.#pageIds(markdown, entryId, name) : new Map(),
430
429
  knownActions: this.knownActions,
@@ -432,7 +431,7 @@ export class Scenes extends BasePackCompiler {
432
431
  ...this.#resolvers(this.index, this.effectsByAddress, fm.shortcode),
433
432
  });
434
433
  for (const message of warnings) {
435
- // Named by file, like every other note diagnostic (#17). A map
434
+ // Named by file, like every other note diagnostic. A map
436
435
  // warning is about the note's frontmatter, which carries no
437
436
  // offset, so it names the file and stops there rather than
438
437
  // pointing at a line it cannot establish.
@@ -452,8 +451,8 @@ export class Scenes extends BasePackCompiler {
452
451
  leadName: name,
453
452
  // As in the journals pass: an address resolves in the
454
453
  // pack that emits it, which is what makes the folder
455
- // materialise there too (#257). The id spelling that used
456
- // to cross packs verbatim is retired (#260).
454
+ // materialise there too. The id spelling that used
455
+ // to cross packs verbatim is retired.
457
456
  folder: this.folderResolver(authoredFolder, { isAddress: true }),
458
457
  flags: fm.flags,
459
458
  })
@@ -13,7 +13,7 @@
13
13
 
14
14
  /**
15
15
  * What a builder **emits** into `system`, against what the receiving DataModel
16
- * **declares** (#60).
16
+ * **declares**.
17
17
  *
18
18
  * Foundry discards an unknown `system` key when a document is constructed, and
19
19
  * says nothing: the value is simply absent at load, while the build that wrote
@@ -22,7 +22,7 @@
22
22
  *
23
23
  * - **Emitted, not declared.** `mysticalability` emitted `assocMysteryCode`,
24
24
  * which no DataModel defined — 0.8.x had replaced it with
25
- * `assocAffiliationCode` (#35). And `affiliation.subType`, authored on all 21
25
+ * `assocAffiliationCode`. And `affiliation.subType`, authored on all 21
26
26
  * of `sohl-kethira-basic`'s deities, is not defined at the version that module
27
27
  * targets, so the divine/arcane split evaporates on load.
28
28
  * - **Declared, not emitted.** The mirror image, fixed by hand in
@@ -39,8 +39,8 @@
39
39
  *
40
40
  * **The rest of the emission is only observable.** A compiler writes keys of
41
41
  * its own alongside the declared fields — `shortcode`, `actionDefs`, `notes`,
42
- * `docHtml`, and since #126 `templatePriority` — and those appear in neither set
43
- * {@link compareFields} compares, so nothing compared them at all (#155). They
42
+ * `docHtml` and `templatePriority` — and those appear in neither set
43
+ * {@link compareFields} compares, so nothing compared them at all. They
44
44
  * cannot be listed here without the list going stale the next time a compiler
45
45
  * grows a key, so they are read off the `system` object the compiler produced:
46
46
  * {@link compareEmittedSystem} takes the assembled block and asks what the
@@ -69,7 +69,7 @@ import { cachedSchemaPath, SCHEMA_ARTIFACT_FILE } from "./foreign-catalog.mjs";
69
69
  import { loadPackConfig } from "./pack-config.mjs";
70
70
  import { systemData, systemDataPaths, undeclaredPaths } from "./system-block.mjs";
71
71
  // A field the document writes for itself in play: declared by the schema,
72
- // emitted by no builder, and authored by no note (#330).
72
+ // emitted by no builder, and authored by no note.
73
73
  import { runtimeOnlyFields } from "./field-spec.mjs";
74
74
 
75
75
  /**
@@ -77,7 +77,7 @@ import { runtimeOnlyFields } from "./field-spec.mjs";
77
77
  *
78
78
  * A mismatch stops the check rather than resolving anyway: a schema read under
79
79
  * the wrong shape would report confident nonsense in both directions, and a
80
- * silently skipped check is the state #60 exists to leave.
80
+ * silently skipped check is the state this exists to leave.
81
81
  *
82
82
  * @type {number}
83
83
  */
@@ -136,7 +136,7 @@ export function declaredFields(artifact, documentType, subtype) {
136
136
  * the path beneath it separately, so a comparison that knew only the leaf would
137
137
  * report the container as unemitted and the leaf as undeclared.
138
138
  *
139
- * **A runtime-only field is not in it** (#330). It declares a `to` in order to
139
+ * **A runtime-only field is not in it**. It declares a `to` in order to
140
140
  * *claim* the path — so the verbatim passthrough leaves it alone and the
141
141
  * refusal has something to name — and `buildFromFields` deliberately skips it,
142
142
  * because the document writes that field in play. Counting it here would make
@@ -196,7 +196,7 @@ function coveredByAncestor(path, emitted) {
196
196
  * compile into.
197
197
  * @param {(type: string) => string} [opts.subtypeOf] - Maps a builder's type to
198
198
  * the document subtype it emits. Defaults to identity, which is what the
199
- * coincidence of names amounts to today (#79) — stated as a seam so that the
199
+ * coincidence of names amounts to today — stated as a seam so that the
200
200
  * explicit map replaces a default rather than a hard-coded assumption.
201
201
  * @returns {{undeclared: object[], unemitted: object[], skipped: string[]}}
202
202
  * `undeclared` fails a build; `unemitted` is reported; `skipped` names the
@@ -226,14 +226,14 @@ export function compareFields({
226
226
  const declared = declaredFields(artifact, documentType, subtype);
227
227
  if (!declared) {
228
228
  // Not a finding: a builder may compile into a type this system does
229
- // not define at all, which is a routing question (#79) rather than a
229
+ // not define at all, which is a routing question rather than a
230
230
  // field one. Named so the count is never mistaken for coverage.
231
231
  skipped.push(type);
232
232
  continue;
233
233
  }
234
234
 
235
235
  const emitted = emittedFields(fields);
236
- // Paths the declaration says the *document* writes in play (#330). They
236
+ // Paths the declaration says the *document* writes in play. They
237
237
  // are neither emitted nor a defect, so they answer the unemitted
238
238
  // question below rather than appearing in it: "every compiled document
239
239
  // will carry the field's initial value" is exactly what a runtime-only
@@ -373,7 +373,7 @@ function undeclaredEmittedPaths(data, declared, enumerated, prefix = "") {
373
373
 
374
374
  /**
375
375
  * What a **compiled document** carries in `system`, against what the receiving
376
- * subtype declares (#155).
376
+ * subtype declares.
377
377
  *
378
378
  * The third of the three checks, and the only one whose emitted set is
379
379
  * *observed*. {@link compareFields} reads the `itemBuilders` declarations and
@@ -430,7 +430,7 @@ export function compareEmittedSystem({
430
430
 
431
431
  const declared = declaredFields(artifact, documentType, subtype);
432
432
  // Not a finding, for the same reason `compareFields` skips one: a subtype
433
- // the artifact says nothing about is a routing question (#79), not a field
433
+ // the artifact says nothing about is a routing question, not a field
434
434
  // one, and guessing at it would report every key on the document.
435
435
  if (!declared) return [];
436
436
 
@@ -457,7 +457,7 @@ export function compareEmittedSystem({
457
457
  * The published schema this build should check itself against, or `null`.
458
458
  *
459
459
  * **Which system, and which version, are already settled.** `stats.systemId`
460
- * and `stats.systemVersion` are derived rather than authored (#48) — a system
460
+ * and `stats.systemVersion` are derived rather than authored — a system
461
461
  * package is its own system, and a module takes the one it requires — and the
462
462
  * version is the `compatibility.verified` it pins. So the question "whose
463
463
  * schema, at what version" has one answer here rather than a second set of
@@ -477,12 +477,12 @@ export function compareEmittedSystem({
477
477
  * stamps no system at all, and a system that has not adopted the artifact yet
478
478
  * is simply unchecked. Neither is an error, and the caller says which it was.
479
479
  *
480
- * **A build may have more than one system, and then the caller names it (#139).**
480
+ * **A build may have more than one system, and then the caller names it.**
481
481
  * `stats.systemId` is the package-wide answer, and a repository shipping content
482
482
  * for two systems has no package-wide answer — it is deliberately `null` there,
483
483
  * because a module feeding both `sohl` and `hm3` targets neither. Left at that,
484
484
  * every schema check in such a build would be skipped in silence, which is the
485
- * state #60 exists to remove: the five type names the two systems *share* are
485
+ * state this exists to remove: the five type names the two systems *share* are
486
486
  * exactly the ones a wrong-system emission hides in. So a pass supplies the
487
487
  * system its pack declares, and the version comes from that system's own
488
488
  * `systems:` entry rather than from a package-wide stamp.
@@ -606,7 +606,7 @@ const artifacts = new WeakMap();
606
606
  * The per-note check below runs thousands of times in a build and an artifact
607
607
  * never changes inside one, so reading and parsing it per note would be a
608
608
  * megabyte of JSON per hundred documents for an answer that is already known.
609
- * Keyed by system as well as by configuration since #139: a build with two
609
+ * Keyed by system as well as by configuration: a build with two
610
610
  * systems has two artifacts, and caching one of them under the configuration
611
611
  * alone would hand every pass whichever system asked first.
612
612
  *
@@ -624,7 +624,7 @@ function schemaFor(config, system = undefined) {
624
624
 
625
625
  /**
626
626
  * What a note authors under `<system>.system`, against what the receiving
627
- * subtype declares (#58).
627
+ * subtype declares.
628
628
  *
629
629
  * The **note-side** half of the check `compareFields` performs on the
630
630
  * declarations. A field list is checked once for the whole build because it is
@@ -649,7 +649,7 @@ function schemaFor(config, system = undefined) {
649
649
  * @param {string} opts.documentType - `Item`, `Actor`, …
650
650
  * @param {string} opts.subType - The document subtype the note compiles into.
651
651
  * @param {string} [opts.system] - The system whose published schema to read,
652
- * where a build has more than one (#139). Defaults to the package-wide
652
+ * where a build has more than one. Defaults to the package-wide
653
653
  * `stats.systemId`.
654
654
  * @param {object} [opts.config] - The resolved build configuration.
655
655
  * @returns {{path: string, message: string}[]} One finding per undeclared path,
@@ -680,7 +680,7 @@ export function checkAuthoredSystemData(
680
680
 
681
681
  /**
682
682
  * The `system` block a compiler just assembled, against what the receiving
683
- * subtype declares (#155).
683
+ * subtype declares.
684
684
  *
685
685
  * The build-time face of {@link compareEmittedSystem}: it resolves the schema
686
686
  * the way every other check here does — the system's own committed artifact, or
@@ -703,7 +703,7 @@ export function checkAuthoredSystemData(
703
703
  * @param {readonly {to?: string}[]} [opts.fields] - The type's field
704
704
  * declaration, which decides each finding's origin.
705
705
  * @param {string} [opts.system] - The system whose published schema to read,
706
- * where a build has more than one (#139). Defaults to the package-wide
706
+ * where a build has more than one. Defaults to the package-wide
707
707
  * `stats.systemId`.
708
708
  * @param {object} [opts.config] - The resolved build configuration.
709
709
  * @returns {(EmissionFinding & {message: string})[]} One per undeclared path.
@@ -17,7 +17,7 @@
17
17
  * The consuming half of this contract already lives in `schema-check.mjs`: a
18
18
  * content build subtracts what its builders emit from what a document will
19
19
  * actually receive, because Foundry discards an unknown `system` key at
20
- * construction and says nothing about it (#60). What was missing is the
20
+ * construction and says nothing about it. What was missing is the
21
21
  * producing half — until now each system carried its own extractor, and the
22
22
  * first one to exist hardcoded {@link SCHEMA_ARTIFACT_VERSION}, a constant this
23
23
  * package owns. Two producers stamping a third repository's constant by hand is