linked-rolls 0.44.0 → 0.45.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 (78) hide show
  1. package/README.md +17 -2
  2. package/lib/Agent.d.ts +1 -1
  3. package/lib/Assumption.d.ts +2 -2
  4. package/lib/Collation.d.ts +15 -8
  5. package/lib/Collation.js +4 -4
  6. package/lib/ConditionState.d.ts +1 -1
  7. package/lib/Edit.d.ts +3 -3
  8. package/lib/Edition.d.ts +6 -6
  9. package/lib/EditionView.d.ts +8 -8
  10. package/lib/EditionView.js +6 -6
  11. package/lib/Emulation.d.ts +4 -4
  12. package/lib/Emulation.js +3 -3
  13. package/lib/Feature.d.ts +5 -5
  14. package/lib/FeatureSource.d.ts +4 -4
  15. package/lib/ReproducingSystem.d.ts +4 -4
  16. package/lib/RollCopy.d.ts +10 -10
  17. package/lib/RollCopy.js +4 -4
  18. package/lib/Symbol.d.ts +2 -2
  19. package/lib/Symbol.js +1 -1
  20. package/lib/TrackCalibration.d.ts +1 -1
  21. package/lib/TrackCalibration.js +1 -1
  22. package/lib/TrackerBar.d.ts +3 -3
  23. package/lib/TrackerBar.js +1 -1
  24. package/lib/Version.d.ts +6 -6
  25. package/lib/Version.js +2 -2
  26. package/lib/alignment.d.ts +4 -4
  27. package/lib/alignment.js +3 -3
  28. package/lib/asJsonLd.d.ts +1 -1
  29. package/lib/asJsonLd.js +3 -3
  30. package/lib/constraints.d.ts +1 -1
  31. package/lib/constraints.js +5 -5
  32. package/lib/context.js +4 -4
  33. package/lib/editionOps.d.ts +9 -9
  34. package/lib/editionOps.js +12 -12
  35. package/lib/importJsonLd.d.ts +1 -1
  36. package/lib/importJsonLd.js +3 -3
  37. package/lib/index.d.ts +42 -42
  38. package/lib/index.js +42 -42
  39. package/lib/migrate.js +6 -6
  40. package/lib/procedures.d.ts +1 -1
  41. package/lib/readers/phillipsEroll.d.ts +3 -3
  42. package/lib/readers/phillipsEroll.js +5 -5
  43. package/lib/readers/spencerBar.d.ts +2 -2
  44. package/lib/readers/spencerBar.js +3 -3
  45. package/lib/readers/stanfordAton.d.ts +3 -3
  46. package/lib/readers/stanfordAton.js +4 -4
  47. package/lib/reservations.d.ts +3 -3
  48. package/lib/reservations.js +4 -4
  49. package/lib/scatter.d.ts +74 -13
  50. package/lib/scatter.js +72 -12
  51. package/lib/schema.json +4 -4
  52. package/lib/sigla.d.ts +1 -1
  53. package/lib/sigla.js +4 -4
  54. package/lib/statistics.d.ts +1 -1
  55. package/lib/statistics.js +1 -1
  56. package/lib/substitution.d.ts +5 -5
  57. package/lib/substitution.js +2 -2
  58. package/lib/systems/index.d.ts +2 -2
  59. package/lib/systems/index.js +4 -4
  60. package/lib/systems/welteLicensee/bar.d.ts +1 -1
  61. package/lib/systems/welteLicensee/bar.js +2 -2
  62. package/lib/systems/welteLicensee/system.d.ts +2 -2
  63. package/lib/systems/welteLicensee/system.js +3 -3
  64. package/lib/systems/welteT100/bar.d.ts +1 -1
  65. package/lib/systems/welteT100/bar.js +2 -2
  66. package/lib/systems/welteT100/system.d.ts +4 -4
  67. package/lib/systems/welteT100/system.js +4 -4
  68. package/lib/systems/welteT98/bar.d.ts +1 -1
  69. package/lib/systems/welteT98/bar.js +2 -2
  70. package/lib/systems/welteT98/system.d.ts +4 -4
  71. package/lib/systems/welteT98/system.js +4 -4
  72. package/lib/validate.d.ts +1 -1
  73. package/lib/validate.js +1 -1
  74. package/lib/vocabulary.d.ts +1 -1
  75. package/lib/vocabulary.js +3 -3
  76. package/lib/witnesses.d.ts +2 -2
  77. package/lib/witnesses.js +2 -2
  78. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -1,42 +1,42 @@
1
- export * from './utils';
2
- export * from './Quantity';
3
- export * from './Agent';
4
- export * from './Assumption';
5
- export * from './ConditionState';
6
- export * from './Symbol';
7
- export * from './Feature';
8
- export * from './Edit';
9
- export * from './Version';
10
- export * from './Collation';
11
- export * from './TrackCalibration';
12
- export * from './TrackerBar';
13
- export * from './systems/welteT100/bar';
14
- export * from './systems/welteLicensee/bar';
15
- export * from './systems/welteT98/bar';
16
- export * from './systems';
17
- export * from './ReproducingSystem';
18
- export * from './FeatureSource';
19
- export * from './RollCopy';
20
- export * from './procedures';
21
- export * from './vocabulary';
22
- export * from './reservations';
23
- export * from './witnesses';
24
- export * from './alignment';
25
- export * from './statistics';
26
- export * from './Edition';
27
- export * from './EditionView';
28
- export * from './scatter';
29
- export * from './editionOps';
30
- export * from './Emulation';
31
- export * from './validate';
32
- export * from './constraints';
33
- export * from './substitution';
34
- export * from './context';
35
- export * from './sigla';
36
- export * from './notes';
37
- export * from './asJsonLd';
38
- export * from './importJsonLd';
39
- export * from './migrate';
40
- export { readFromStanfordAton } from './readers/stanfordAton';
41
- export { readFromPhillipsEroll, CONTROL_OFFSET, phillipsSystems } from './readers/phillipsEroll';
42
- export { readFromSpencerBar, readSpencerAnn, paperSpeedOfSpencerAnn, SPENCER_ROWS_PER_INCH } from './readers/spencerBar';
1
+ export * from './utils.js';
2
+ export * from './Quantity.js';
3
+ export * from './Agent.js';
4
+ export * from './Assumption.js';
5
+ export * from './ConditionState.js';
6
+ export * from './Symbol.js';
7
+ export * from './Feature.js';
8
+ export * from './Edit.js';
9
+ export * from './Version.js';
10
+ export * from './Collation.js';
11
+ export * from './TrackCalibration.js';
12
+ export * from './TrackerBar.js';
13
+ export * from './systems/welteT100/bar.js';
14
+ export * from './systems/welteLicensee/bar.js';
15
+ export * from './systems/welteT98/bar.js';
16
+ export * from './systems/index.js';
17
+ export * from './ReproducingSystem.js';
18
+ export * from './FeatureSource.js';
19
+ export * from './RollCopy.js';
20
+ export * from './procedures.js';
21
+ export * from './vocabulary.js';
22
+ export * from './reservations.js';
23
+ export * from './witnesses.js';
24
+ export * from './alignment.js';
25
+ export * from './statistics.js';
26
+ export * from './Edition.js';
27
+ export * from './EditionView.js';
28
+ export * from './scatter.js';
29
+ export * from './editionOps.js';
30
+ export * from './Emulation.js';
31
+ export * from './validate.js';
32
+ export * from './constraints.js';
33
+ export * from './substitution.js';
34
+ export * from './context.js';
35
+ export * from './sigla.js';
36
+ export * from './notes.js';
37
+ export * from './asJsonLd.js';
38
+ export * from './importJsonLd.js';
39
+ export * from './migrate.js';
40
+ export { readFromStanfordAton } from './readers/stanfordAton.js';
41
+ export { readFromPhillipsEroll, CONTROL_OFFSET, phillipsSystems } from './readers/phillipsEroll.js';
42
+ export { readFromSpencerBar, readSpencerAnn, paperSpeedOfSpencerAnn, SPENCER_ROWS_PER_INCH } from './readers/spencerBar.js';
package/lib/migrate.js CHANGED
@@ -1,9 +1,9 @@
1
- import { conditions, isFeatureType, media, techniques } from "./Feature";
2
- import { rollConditions } from "./RollCopy";
3
- import { systemIdIn, systemOf, translationBetween } from "./TrackerBar";
4
- import { trackerBars } from "./systems";
5
- import { welteT100 } from "./systems/welteT100/bar";
6
- import { isDateString } from "./utils";
1
+ import { conditions, isFeatureType, media, techniques } from "./Feature.js";
2
+ import { rollConditions } from "./RollCopy.js";
3
+ import { systemIdIn, systemOf, translationBetween } from "./TrackerBar.js";
4
+ import { trackerBars } from "./systems/index.js";
5
+ import { welteT100 } from "./systems/welteT100/bar.js";
6
+ import { isDateString } from "./utils.js";
7
7
  const retiredVersionTypes = new Set(['edition', 'unicum']);
8
8
  const conditionTypeValues = new Set([...rollConditions, ...Object.values(conditions).flat()]);
9
9
  const renamedKeys = {
@@ -1,4 +1,4 @@
1
- import { Concept } from "./Agent";
1
+ import { Concept } from "./Agent.js";
2
2
  /**
3
3
  * The procedures the type vocabulary declares, for a consumer that has
4
4
  * to offer them. The names are the German labels of the concepts, which
@@ -1,6 +1,6 @@
1
- import { RollCopy } from "../RollCopy";
2
- import { TrackerBar } from "../TrackerBar";
3
- import { Millimeters, Seconds } from "../Quantity";
1
+ import { RollCopy } from "../RollCopy.js";
2
+ import { TrackerBar } from "../TrackerBar.js";
3
+ import { Millimeters, Seconds } from "../Quantity.js";
4
4
  /**
5
5
  * Peter Phillips's "e-roll" file, the unprocessed output of his
6
6
  * pneumatic roll reader (thesis pp. 182–196): the roll runs over a
@@ -1,10 +1,10 @@
1
1
  import { read } from "midifile-ts";
2
2
  import { v4 } from "uuid";
3
- import { assignObject } from "../Assumption";
4
- import { systemOf } from "../TrackerBar";
5
- import { welteT100 } from "../systems/welteT100/bar";
6
- import { welteLicensee } from "../systems/welteLicensee/bar";
7
- import { inMetersPerMinute, mm, seconds, track } from "../Quantity";
3
+ import { assignObject } from "../Assumption.js";
4
+ import { systemOf } from "../TrackerBar.js";
5
+ import { welteT100 } from "../systems/welteT100/bar.js";
6
+ import { welteLicensee } from "../systems/welteLicensee/bar.js";
7
+ import { inMetersPerMinute, mm, seconds, track } from "../Quantity.js";
8
8
  /**
9
9
  * Peter Phillips's "e-roll" file, the unprocessed output of his
10
10
  * pneumatic roll reader (thesis pp. 182–196): the roll runs over a
@@ -1,5 +1,5 @@
1
- import { PaperSpeed, RollCopy } from "../RollCopy";
2
- import { TrackerBar } from "../TrackerBar";
1
+ import { PaperSpeed, RollCopy } from "../RollCopy.js";
2
+ import { TrackerBar } from "../TrackerBar.js";
3
3
  /**
4
4
  * Rows of the image on an inch of paper. The player reads eight rows a
5
5
  * second per unit of roll tempo (tempo 80 comes with a sample rate of
@@ -1,7 +1,7 @@
1
1
  import { v4 } from "uuid";
2
- import { systemOf } from "../TrackerBar";
3
- import { welteLicensee } from "../systems/welteLicensee/bar";
4
- import { feetPerMinute, inMillimeters, px, track } from "../Quantity";
2
+ import { systemOf } from "../TrackerBar.js";
3
+ import { welteLicensee } from "../systems/welteLicensee/bar.js";
4
+ import { feetPerMinute, inMillimeters, px, track } from "../Quantity.js";
5
5
  /**
6
6
  * Spencer Chase's e-roll file (`.bar`, "eRoll Tracker Bar Image") holds
7
7
  * a roll as a list of events: a distance in rows of the scanned image,
@@ -1,6 +1,6 @@
1
- import { RollCopy } from "../RollCopy";
2
- import { TrackerBar } from "../TrackerBar";
3
- import { Track } from "../Quantity";
1
+ import { RollCopy } from "../RollCopy.js";
2
+ import { TrackerBar } from "../TrackerBar.js";
3
+ import { Track } from "../Quantity.js";
4
4
  export interface StanfordAtonOptions {
5
5
  /**
6
6
  * Added to the scanning software's hole numbering to reach the
@@ -1,8 +1,8 @@
1
1
  import { v4 } from "uuid";
2
- import { AtonParser } from "./AtonParser";
3
- import { systemOf } from "../TrackerBar";
4
- import { welteT100 } from "../systems/welteT100/bar";
5
- import { inMillimeters, mean, mm, pixelsPerInch, px, subtract, track } from "../Quantity";
2
+ import { AtonParser } from "./AtonParser.js";
3
+ import { systemOf } from "../TrackerBar.js";
4
+ import { welteT100 } from "../systems/welteT100/bar.js";
5
+ import { inMillimeters, mean, mm, pixelsPerInch, px, subtract, track } from "../Quantity.js";
6
6
  /** Values in these files carry their unit as a suffix, e.g. "37.7646px". */
7
7
  const readPx = (value) => px(parseFloat(value));
8
8
  /** The parser writes one record as an object and several as an array. */
@@ -1,6 +1,6 @@
1
- import { RollCopy } from "./RollCopy";
2
- import { Version } from "./Version";
3
- import { EditionView } from "./EditionView";
1
+ import { RollCopy } from "./RollCopy.js";
2
+ import { Version } from "./Version.js";
3
+ import { EditionView } from "./EditionView.js";
4
4
  export declare const reservationTypes: readonly ['source-not-stated', 'source-undocumented', 'software-not-named', 'instrument-not-named', 'features-interpreted', 'no-physical-evidence', 'measurement-undocumented', 'not-calibrated', 'system-unknown', 'keeper-unknown'];
5
5
  export type ReservationType = typeof reservationTypes[number];
6
6
  /**
@@ -1,7 +1,7 @@
1
- import { bearsPhysicalEvidence, isMeasured, sourceLabels } from "./FeatureSource";
2
- import { calibrationOf, featuresOf } from "./RollCopy";
3
- import { trackerBarOf } from "./systems";
4
- import { witnessesOf } from "./witnesses";
1
+ import { bearsPhysicalEvidence, isMeasured, sourceLabels } from "./FeatureSource.js";
2
+ import { calibrationOf, featuresOf } from "./RollCopy.js";
3
+ import { trackerBarOf } from "./systems/index.js";
4
+ import { witnessesOf } from "./witnesses.js";
5
5
  export const reservationTypes = [
6
6
  'source-not-stated',
7
7
  'source-undocumented',
package/lib/scatter.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { Belief } from "./Assumption";
2
- import { BothEnds, CollationTolerance, Displacement } from "./Collation";
3
- import { EditionView } from "./EditionView";
4
- import { Millimeters } from "./Quantity";
5
- import { Histogram, Spread, Tail } from "./statistics";
6
- import { AnySymbol } from "./Symbol";
1
+ import { Belief } from "./Assumption.js";
2
+ import { BothEnds, CollationTolerance, Displacement } from "./Collation.js";
3
+ import { EditionView } from "./EditionView.js";
4
+ import { Millimeters } from "./Quantity.js";
5
+ import { Histogram, Spread, Tail } from "./statistics.js";
6
+ import { AnySymbol } from "./Symbol.js";
7
7
  /**
8
8
  * How far the copies of a roll disagree about where a symbol lies, and
9
9
  * the collation tolerance that follows from it.
@@ -31,7 +31,15 @@ export interface Reading {
31
31
  * that reads it: no second symbol is left to match it against. Which
32
32
  * copies a version was established from is therefore not something the
33
33
  * edition still states once the collation has run, and the caller
34
- * names them.
34
+ * names them. `sidesOf` says which copies attest each side of a
35
+ * derivation, which is the way to name them rather than by hand.
36
+ *
37
+ * The copies named are one **side** of a comparison and the rest are
38
+ * the other, so the displacement is signed and its sign is the caller's
39
+ * choice. Naming a set that is not a side yields a well formed
40
+ * measurement of something else: one copy's own noise against a mixture
41
+ * of both sides, which is no window any collation used and is wider
42
+ * than the truth.
35
43
  *
36
44
  * A symbol only one side carries measures nothing and is passed over,
37
45
  * which leaves out exactly the insertions and the deletions.
@@ -117,7 +125,14 @@ export interface Scatter {
117
125
  * one of the sample's own readings is expected to pass it.
118
126
  */
119
127
  k: number;
120
- /** The window that follows: `k` times the scatter, centred on the median. */
128
+ /**
129
+ * The window that follows: `k` times the scatter, centred on the
130
+ * median. Its offsets run in the direction of the sample, the
131
+ * copies named less the rest, so a window measured over the
132
+ * parent's copies carries them negated. `toleranceAcross` is what
133
+ * turns these into the window a derivation stores, and it asks
134
+ * which side was named; storing one of these directly does not.
135
+ */
121
136
  tolerance: CollationTolerance;
122
137
  /** How far the sample departs from the normal shape, at either end. */
123
138
  normality: BothEnds<Normality>;
@@ -142,13 +157,59 @@ export declare const scatterOf: (readings: readonly Reading[], options?: Scatter
142
157
  /** How one copy's readings of a version's text scatter against the readings of the copies it is collated with. */
143
158
  export declare const scatterOfCopy: (view: EditionView, versionId: string, copyId: string, options?: ScatterOptions) => Scatter[];
144
159
  /**
145
- * One window admitting what every sample's own window admits. A
146
- * derivation states a single tolerance while the samples differ, and
160
+ * Which side of a derivation a measurement was taken over: the version
161
+ * derived, or the version it is read against.
162
+ */
163
+ export type Side = 'child' | 'parent';
164
+ /**
165
+ * One window admitting what every sample's own window admits, in the
166
+ * direction a collation applies it.
167
+ *
168
+ * A derivation states a single tolerance while the samples differ, and
147
169
  * covering them keeps each sample within the budget of chance
148
- * departures its own threshold was chosen for. Nothing where there is
149
- * no sample.
170
+ * departures its own threshold was chosen for.
171
+ *
172
+ * `named` says whose copies the scatters were measured over, and it is
173
+ * asked for rather than assumed because nothing else can tell. A window
174
+ * measured over the parent's copies runs the other way, and stored
175
+ * unturned its offsets sit on the wrong side of the readings: the width
176
+ * is unaffected, so nothing in the magnitude looks wrong, and the
177
+ * departures are unaffected too, since they are taken about the
178
+ * sample's own median. Only the collation is wrong, and it is wrong in
179
+ * both directions at once, separating readings that belong together and
180
+ * merging readings that do not. Nothing where there is no sample.
181
+ */
182
+ export declare const toleranceAcross: (scatters: readonly Scatter[], named: Side) => CollationTolerance | undefined;
183
+ /** How many of a side's symbols a copy bears. */
184
+ export interface Attestation {
185
+ copy: string;
186
+ symbols: number;
187
+ }
188
+ /** The copies attesting each side of a derivation, each side in order of how much it bears. */
189
+ export interface Sides {
190
+ /** The copies bearing what the child inserts: the reading the derivation moves to. */
191
+ child: Attestation[];
192
+ /** The copies bearing what the child strikes from the parent: the reading it moves from. */
193
+ parent: Attestation[];
194
+ }
195
+ /**
196
+ * Which copies attest each side of a version's derivation, read off the
197
+ * edits themselves: the copies bearing what it inserts stand for the
198
+ * reading it moves to, and those bearing what it strikes for the
199
+ * reading it moves from.
200
+ *
201
+ * This is the way to name a side. Counting only the copies that bear a
202
+ * version's own text will not do it, because a collation hands a
203
+ * child's carriers up to the parent's symbols, so a descendant's copies
204
+ * come to bear an ancestor's readings and look like its own. The
205
+ * deletions are not exposed to that: what a version strikes is attested
206
+ * by the copies that read it before the version departed from it.
207
+ *
208
+ * A fully collated edge inserts and deletes nothing and so attests
209
+ * neither side, which is the case where the edition has genuinely
210
+ * stopped saying and an editor has to.
150
211
  */
151
- export declare const toleranceAcross: (scatters: readonly Scatter[]) => CollationTolerance | undefined;
212
+ export declare const sidesOf: (view: EditionView, versionId: string) => Sides | undefined;
152
213
  /**
153
214
  * The belief a calculated tolerance rests on, to annotate the
154
215
  * derivation's `collationTolerance` with: an inference from the scatter
package/lib/scatter.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { v4 } from "uuid";
2
- import { admits, offsetEndOf, offsetStartOf } from "./Collation";
3
- import { mean, mm } from "./Quantity";
4
- import { excessKurtosisOf, histogramOf, normalQuantile, spreadOf, standardise, tailOf } from "./statistics";
5
- import { groupBy } from "./utils";
2
+ import { admits, offsetEndOf, offsetStartOf } from "./Collation.js";
3
+ import { mean, mm } from "./Quantity.js";
4
+ import { excessKurtosisOf, histogramOf, normalQuantile, spreadOf, standardise, tailOf } from "./statistics.js";
5
+ import { groupBy } from "./utils.js";
6
+ import { deletedBy, insertedBy } from "./Version.js";
6
7
  const placeOf = (carriers) => ({
7
8
  from: mean(carriers.map(carrier => carrier.horizontal.from)),
8
9
  to: mean(carriers.map(carrier => carrier.horizontal.to))
@@ -20,7 +21,15 @@ const sitsOn = (view, copies) => (feature) => {
20
21
  * that reads it: no second symbol is left to match it against. Which
21
22
  * copies a version was established from is therefore not something the
22
23
  * edition still states once the collation has run, and the caller
23
- * names them.
24
+ * names them. `sidesOf` says which copies attest each side of a
25
+ * derivation, which is the way to name them rather than by hand.
26
+ *
27
+ * The copies named are one **side** of a comparison and the rest are
28
+ * the other, so the displacement is signed and its sign is the caller's
29
+ * choice. Naming a set that is not a side yields a well formed
30
+ * measurement of something else: one copy's own noise against a mixture
31
+ * of both sides, which is no window any collation used and is wider
32
+ * than the truth.
24
33
  *
25
34
  * A symbol only one side carries measures nothing and is passed over,
26
35
  * which leaves out exactly the insertions and the deletions.
@@ -118,24 +127,75 @@ const covering = (windows) => {
118
127
  return { offset: mm((lowest + highest) / 2), tolerance: mm((highest - lowest) / 2) };
119
128
  };
120
129
  /**
121
- * One window admitting what every sample's own window admits. A
122
- * derivation states a single tolerance while the samples differ, and
130
+ * One window admitting what every sample's own window admits, in the
131
+ * direction a collation applies it.
132
+ *
133
+ * A derivation states a single tolerance while the samples differ, and
123
134
  * covering them keeps each sample within the budget of chance
124
- * departures its own threshold was chosen for. Nothing where there is
125
- * no sample.
135
+ * departures its own threshold was chosen for.
136
+ *
137
+ * `named` says whose copies the scatters were measured over, and it is
138
+ * asked for rather than assumed because nothing else can tell. A window
139
+ * measured over the parent's copies runs the other way, and stored
140
+ * unturned its offsets sit on the wrong side of the readings: the width
141
+ * is unaffected, so nothing in the magnitude looks wrong, and the
142
+ * departures are unaffected too, since they are taken about the
143
+ * sample's own median. Only the collation is wrong, and it is wrong in
144
+ * both directions at once, separating readings that belong together and
145
+ * merging readings that do not. Nothing where there is no sample.
126
146
  */
127
- export const toleranceAcross = (scatters) => {
147
+ export const toleranceAcross = (scatters, named) => {
128
148
  if (scatters.length === 0)
129
149
  return undefined;
150
+ const towardsChild = named === 'child' ? 1 : -1;
130
151
  const start = covering(scatters.map(({ tolerance }) => ({ offset: offsetStartOf(tolerance), tolerance: tolerance.toleranceStart })));
131
152
  const end = covering(scatters.map(({ tolerance }) => ({ offset: offsetEndOf(tolerance), tolerance: tolerance.toleranceEnd })));
132
153
  return {
133
- offsetStart: start.offset,
154
+ offsetStart: mm(towardsChild * start.offset),
134
155
  toleranceStart: start.tolerance,
135
- offsetEnd: end.offset,
156
+ offsetEnd: mm(towardsChild * end.offset),
136
157
  toleranceEnd: end.tolerance
137
158
  };
138
159
  };
160
+ const copiesBearing = (view, symbols) => {
161
+ const tally = symbols.reduce((counts, symbol) => {
162
+ const bearers = new Set(view.carriersOf(symbol).flatMap(carrier => {
163
+ const copy = view.copyOf(carrier.id);
164
+ return copy ? [copy.id] : [];
165
+ }));
166
+ bearers.forEach(copy => counts.set(copy, (counts.get(copy) ?? 0) + 1));
167
+ return counts;
168
+ }, new Map());
169
+ return [...tally]
170
+ .map(([copy, symbols]) => ({ copy, symbols }))
171
+ .sort((a, b) => b.symbols - a.symbols);
172
+ };
173
+ /**
174
+ * Which copies attest each side of a version's derivation, read off the
175
+ * edits themselves: the copies bearing what it inserts stand for the
176
+ * reading it moves to, and those bearing what it strikes for the
177
+ * reading it moves from.
178
+ *
179
+ * This is the way to name a side. Counting only the copies that bear a
180
+ * version's own text will not do it, because a collation hands a
181
+ * child's carriers up to the parent's symbols, so a descendant's copies
182
+ * come to bear an ancestor's readings and look like its own. The
183
+ * deletions are not exposed to that: what a version strikes is attested
184
+ * by the copies that read it before the version departed from it.
185
+ *
186
+ * A fully collated edge inserts and deletes nothing and so attests
187
+ * neither side, which is the case where the edition has genuinely
188
+ * stopped saying and an editor has to.
189
+ */
190
+ export const sidesOf = (view, versionId) => {
191
+ const version = view.get(versionId);
192
+ if (!version)
193
+ return undefined;
194
+ return {
195
+ child: copiesBearing(view, insertedBy(version)),
196
+ parent: copiesBearing(view, view.getAll(deletedBy(version)))
197
+ };
198
+ };
139
199
  const inMillimetres = (value) => `${value.toFixed(2)} mm`;
140
200
  const sampleDescribed = (scatter) => `${scatter.group}: ${scatter.spread.from.n} readings, scattering by `
141
201
  + `${inMillimetres(scatter.spread.from.sigma)} at the start and ${inMillimetres(scatter.spread.to.sigma)} at the end `
package/lib/schema.json CHANGED
@@ -208,11 +208,11 @@
208
208
  "properties": {
209
209
  "offsetEnd": {
210
210
  "$ref": "#/definitions/Millimeters",
211
- "description": "The same at the end of a feature."
211
+ "description": "The same at the end of a feature, in the same direction."
212
212
  },
213
213
  "offsetStart": {
214
214
  "$ref": "#/definitions/Millimeters",
215
- "description": "How much later the collated copy puts the start of a feature than the copy it is read against, where the two differ systematically. Nothing where they do not."
215
+ "description": "How much later the derived version puts the start of a feature than the version it is read against, where the two differ systematically. Nothing where they do not.\n\nThe direction is the one a collation measures in, the child less the parent, and it is not symmetric: stored the other way round the window sits on the wrong side of the readings and merges what it should separate. A measurement taken over the parent's copies gives the negative of this, which is what `toleranceAcross` asks the side for."
216
216
  },
217
217
  "toleranceEnd": {
218
218
  "$ref": "#/definitions/Millimeters",
@@ -1932,11 +1932,11 @@
1932
1932
  },
1933
1933
  "offsetEnd": {
1934
1934
  "$ref": "#/definitions/Millimeters",
1935
- "description": "The same at the end of a feature."
1935
+ "description": "The same at the end of a feature, in the same direction."
1936
1936
  },
1937
1937
  "offsetStart": {
1938
1938
  "$ref": "#/definitions/Millimeters",
1939
- "description": "How much later the collated copy puts the start of a feature than the copy it is read against, where the two differ systematically. Nothing where they do not."
1939
+ "description": "How much later the derived version puts the start of a feature than the version it is read against, where the two differ systematically. Nothing where they do not.\n\nThe direction is the one a collation measures in, the child less the parent, and it is not symmetric: stored the other way round the window sits on the wrong side of the readings and merges what it should separate. A measurement taken over the parent's copies gives the negative of this, which is what `toleranceAcross` asks the side for."
1940
1940
  },
1941
1941
  "toleranceEnd": {
1942
1942
  "$ref": "#/definitions/Millimeters",
package/lib/sigla.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Edition } from './Edition';
1
+ import { Edition } from './Edition.js';
2
2
  /**
3
3
  * The siglum of every version, as the stemma stands. The letter names the
4
4
  * reproducing system a version is coded for, the number counts the
package/lib/sigla.js CHANGED
@@ -1,7 +1,7 @@
1
- import { idOf } from './Assumption';
2
- import { systemIdOf } from './TrackerBar';
3
- import { trackerBarOf } from './systems';
4
- import { principalDerivationOf } from './Version';
1
+ import { idOf } from './Assumption.js';
2
+ import { systemIdOf } from './TrackerBar.js';
3
+ import { trackerBarOf } from './systems/index.js';
4
+ import { principalDerivationOf } from './Version.js';
5
5
  /** The letter the versions of a system are labelled with. */
6
6
  const letters = new Map([
7
7
  ['welte-t100', 'R'],
@@ -1,4 +1,4 @@
1
- import { Quantity } from "./Quantity";
1
+ import { Quantity } from "./Quantity.js";
2
2
  /**
3
3
  * The statistics a sample of measurements is described with.
4
4
  *
package/lib/statistics.js CHANGED
@@ -1,4 +1,4 @@
1
- import { quantity } from "./Quantity";
1
+ import { quantity } from "./Quantity.js";
2
2
  /**
3
3
  * The statistics a sample of measurements is described with.
4
4
  *
@@ -1,7 +1,7 @@
1
- import { CollationTolerance, Locate } from "./Collation";
2
- import { AnySymbol, Expression } from "./Symbol";
3
- import { Millimeters, Track } from "./Quantity";
4
- import { TrackerBar } from "./TrackerBar";
1
+ import { CollationTolerance, Locate } from "./Collation.js";
2
+ import { AnySymbol, Expression } from "./Symbol.js";
3
+ import { Millimeters, Track } from "./Quantity.js";
4
+ import { TrackerBar } from "./TrackerBar.js";
5
5
  /**
6
6
  * How a scale words a function: as a command that turns it on, one that
7
7
  * cancels it, or one that holds it for as long as it lasts.
@@ -46,7 +46,7 @@ export interface Substitution {
46
46
  * 2.66 mm grid with bridges of about a millimetre, so a scan read hole
47
47
  * by hole shows a run where the paper shows one command.
48
48
  */
49
- export declare const defaultChainGap: import("./Quantity").Quantity<"mm">;
49
+ export declare const defaultChainGap: import("./Quantity.js").Quantity<"mm">;
50
50
  /**
51
51
  * The position a bar reads its own command for the same function on,
52
52
  * where it has no word for this one.
@@ -1,5 +1,5 @@
1
- import { defaultCollationTolerance } from "./Collation";
2
- import { distance, mm, track } from "./Quantity";
1
+ import { defaultCollationTolerance } from "./Collation.js";
2
+ import { distance, mm, track } from "./Quantity.js";
3
3
  /**
4
4
  * What each Welte expression type operates.
5
5
  *
@@ -1,5 +1,5 @@
1
- import { Concept } from "../Agent";
2
- import { TrackerBar } from "../TrackerBar";
1
+ import { Concept } from "../Agent.js";
2
+ import { TrackerBar } from "../TrackerBar.js";
3
3
  /** The tracker bars the library knows, the T-100 first as the usual one. */
4
4
  export declare const trackerBars: readonly TrackerBar[];
5
5
  /** The bar of a system the type vocabulary knows, from its concept. */
@@ -1,7 +1,7 @@
1
- import { systemIdOf } from "../TrackerBar";
2
- import { welteT100 } from "./welteT100/bar";
3
- import { welteLicensee } from "./welteLicensee/bar";
4
- import { welteT98 } from "./welteT98/bar";
1
+ import { systemIdOf } from "../TrackerBar.js";
2
+ import { welteT100 } from "./welteT100/bar.js";
3
+ import { welteLicensee } from "./welteLicensee/bar.js";
4
+ import { welteT98 } from "./welteT98/bar.js";
5
5
  /** The tracker bars the library knows, the T-100 first as the usual one. */
6
6
  export const trackerBars = [welteT100, welteLicensee, welteT98];
7
7
  /** The bar of a system the type vocabulary knows, from its concept. */
@@ -1,4 +1,4 @@
1
- import { TrackerBar } from "../../TrackerBar";
1
+ import { TrackerBar } from "../../TrackerBar.js";
2
2
  /**
3
3
  * Welte-Mignon (Licensee), the American re-cut of the T-100 rolls on
4
4
  * a roll 11¼ inches wide with 98 positions at nine to the inch, cf.
@@ -1,5 +1,5 @@
1
- import { describeTrackerBar } from "../../TrackerBar";
2
- import { mm } from "../../Quantity";
1
+ import { describeTrackerBar } from "../../TrackerBar.js";
2
+ import { mm } from "../../Quantity.js";
3
3
  /**
4
4
  * Welte-Mignon (Licensee), the American re-cut of the T-100 rolls on
5
5
  * a roll 11¼ inches wide with 98 positions at nine to the inch, cf.
@@ -1,5 +1,5 @@
1
- import { ReproducingSystem } from "../../ReproducingSystem";
2
- import { type WelteT100Options } from "../welteT100/system";
1
+ import { ReproducingSystem } from "../../ReproducingSystem.js";
2
+ import { type WelteT100Options } from "../welteT100/system.js";
3
3
  export type WelteLicenseeOptions = WelteT100Options;
4
4
  /**
5
5
  * The one instrument on offer, and it is not a Licensee instrument.
@@ -1,7 +1,7 @@
1
1
  import { CONSENSUS } from "welte-mignon-emulator/t100";
2
- import { track } from "../../Quantity";
3
- import { welteLicensee } from "./bar";
4
- import { defaultWelteT100Options, instrumentNameOf, nuanceOf, performAs } from "../welteT100/system";
2
+ import { track } from "../../Quantity.js";
3
+ import { welteLicensee } from "./bar.js";
4
+ import { defaultWelteT100Options, instrumentNameOf, nuanceOf, performAs } from "../welteT100/system.js";
5
5
  /**
6
6
  * The one instrument on offer, and it is not a Licensee instrument.
7
7
  *
@@ -1,4 +1,4 @@
1
- import { TrackerBar } from "../../TrackerBar";
1
+ import { TrackerBar } from "../../TrackerBar.js";
2
2
  /**
3
3
  * The commands of the Welte-Mignon T-100, as its tracker bar reads them.
4
4
  */
@@ -1,5 +1,5 @@
1
- import { describeTrackerBar } from "../../TrackerBar";
2
- import { metersPerMinute, mm } from "../../Quantity";
1
+ import { describeTrackerBar } from "../../TrackerBar.js";
2
+ import { metersPerMinute, mm } from "../../Quantity.js";
3
3
  /**
4
4
  * The commands of the Welte-Mignon T-100, as its tracker bar reads them.
5
5
  */
@@ -1,9 +1,9 @@
1
1
  import { Half, Parameters, PedalMode, Spool } from "welte-mignon-emulator";
2
2
  import { Instrument, RollNumber } from "welte-mignon-emulator/t100";
3
- import { NegotiatedEvent, Performance, ReproducingSystem, RollProperties } from "../../ReproducingSystem";
4
- import { Millimeters, Seconds, Track } from "../../Quantity";
5
- import { type VelocityMap } from "../velocity";
6
- export type { VelocityMap } from "../velocity";
3
+ import { NegotiatedEvent, Performance, ReproducingSystem, RollProperties } from "../../ReproducingSystem.js";
4
+ import { Millimeters, Seconds, Track } from "../../Quantity.js";
5
+ import { type VelocityMap } from "../velocity.js";
6
+ export type { VelocityMap } from "../velocity.js";
7
7
  export type { Instrument } from "welte-mignon-emulator/t100";
8
8
  export type InstrumentName = 'consensus' | RollNumber;
9
9
  /**