linked-rolls 0.73.0 → 0.75.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.
@@ -0,0 +1,79 @@
1
+ import { ActorAssignment, Assumption, Certainty, PropositionSet, TimeSpan } from "../model/Assumption.js";
2
+ import { Edition } from "../model/Edition.js";
3
+ /**
4
+ * The published rules the proposal of a stemma follows, by IRI, each
5
+ * under the cost or the step that carries it out. They are the
6
+ * editorial principles of the edition of WM 225, which are suggested
7
+ * for the filiation of piano rolls at large.
8
+ * @category Filiation
9
+ */
10
+ export declare const stemmaRules: {
11
+ /** An addition at the same place is not made twice independently, so a reading arising costs ten times one lost. */
12
+ readonly sharedAddition: 'https://welte225.org/rules#shared-addition';
13
+ /** Redundancies are cleaned up in two branches independently, so losing one counts for less. */
14
+ readonly independentCleanup: 'https://welte225.org/rules#independent-cleanup';
15
+ /** A re-cut for another system was an editorial pass of its own, so what it lacks counts for less. */
16
+ readonly recutLoss: 'https://welte225.org/rules#recut-loss';
17
+ /** A copy may fail to show a reading of the version it carries. */
18
+ readonly copyDeviation: 'https://welte225.org/rules#copy-deviation';
19
+ /** A lost state is posited only where shared additions require it. */
20
+ readonly lostStates: 'https://welte225.org/rules#lost-states';
21
+ /** Copies of one system that differ in a few readings carry one text. */
22
+ readonly oneText: 'https://welte225.org/rules#one-text';
23
+ /** Later versions are the more refined, which orients the root. */
24
+ readonly refinement: 'https://welte225.org/rules#refinement';
25
+ /** A version derives from one exemplar, so a stemma is a tree. */
26
+ readonly noContamination: 'https://welte225.org/rules#no-contamination';
27
+ };
28
+ /**
29
+ * The published rules the proposal of edits follows, by IRI.
30
+ * @category Filiation
31
+ */
32
+ export declare const editRules: {
33
+ /** An edit stays at one place: it runs across no command both texts keep. */
34
+ readonly onePlace: 'https://welte225.org/rules#one-place';
35
+ };
36
+ /**
37
+ * What is known of a run of a program beside what it computed: who ran
38
+ * it, when, how firmly what it concluded is held, and by which
39
+ * published rules. An adoption records the run with it; whatever is left
40
+ * out is not stated.
41
+ * @category Filiation
42
+ */
43
+ export interface Run {
44
+ /** Who ran the program and so holds what it concluded: the editor. */
45
+ actor?: ActorAssignment;
46
+ /** When it ran. */
47
+ date?: TimeSpan;
48
+ /** How firmly what it concluded is held: likely, where nothing else is said. */
49
+ certainty?: Certainty;
50
+ /** The rules it followed, by IRI, in place of those the library names (`stemmaRules`, `editRules`). */
51
+ applies?: string[];
52
+ }
53
+ /** What a recorded run concluded besides its statements: what the inference says of itself. */
54
+ export interface Concluded {
55
+ /** What the run is, and what it was computed with, in words. */
56
+ note: string;
57
+ premises: string[];
58
+ used: string[];
59
+ applies: string[];
60
+ }
61
+ /**
62
+ * The proposition set of a run, with its belief and the inference it
63
+ * rests on. Its id follows from what it is given, so that recording the
64
+ * same run again gives the same set.
65
+ */
66
+ export declare const recorded: (kind: string, identity: unknown, concluded: Concluded, run: Run) => PropositionSet;
67
+ /** The statement as one of the set: its annotation names the set, and it carries no belief of its own. */
68
+ export declare const memberOf: <T extends Assumption>(set: string, statement: T) => T;
69
+ /**
70
+ * The sets the edition keeps, with those given added where it holds none
71
+ * with their id: a set already recorded stays as it was recorded, by
72
+ * whom and when it was first concluded. Kept are the sets a statement
73
+ * belongs to, and those whose belief the reasons of another kept
74
+ * statement or set name as a premise. A set nothing names any longer is
75
+ * the record of a run whose conclusions have all been replaced.
76
+ */
77
+ export declare const keptSets: (edition: Edition, adding: readonly PropositionSet[]) => PropositionSet[] | undefined;
78
+ /** A distance in millimetres as a note gives it. */
79
+ export declare const inMillimetres: (value: number) => string;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * What adopting a proposal records of the run that made it: the
3
+ * proposition set the statements it concluded belong to, held under one
4
+ * belief, and the reasoning that belief rests on.
5
+ */
6
+ import { v5 } from "uuid";
7
+ import { linkedRolls } from "../software.js";
8
+ /** The namespace the ids of recorded sets and beliefs are minted in, so that recording the same run again gives them again. */
9
+ const RECORDED = 'b7e2a4d1-5c3f-4e86-9a0b-1d2f3e4c5a67';
10
+ /**
11
+ * The published rules the proposal of a stemma follows, by IRI, each
12
+ * under the cost or the step that carries it out. They are the
13
+ * editorial principles of the edition of WM 225, which are suggested
14
+ * for the filiation of piano rolls at large.
15
+ * @category Filiation
16
+ */
17
+ export const stemmaRules = {
18
+ /** An addition at the same place is not made twice independently, so a reading arising costs ten times one lost. */
19
+ sharedAddition: 'https://welte225.org/rules#shared-addition',
20
+ /** Redundancies are cleaned up in two branches independently, so losing one counts for less. */
21
+ independentCleanup: 'https://welte225.org/rules#independent-cleanup',
22
+ /** A re-cut for another system was an editorial pass of its own, so what it lacks counts for less. */
23
+ recutLoss: 'https://welte225.org/rules#recut-loss',
24
+ /** A copy may fail to show a reading of the version it carries. */
25
+ copyDeviation: 'https://welte225.org/rules#copy-deviation',
26
+ /** A lost state is posited only where shared additions require it. */
27
+ lostStates: 'https://welte225.org/rules#lost-states',
28
+ /** Copies of one system that differ in a few readings carry one text. */
29
+ oneText: 'https://welte225.org/rules#one-text',
30
+ /** Later versions are the more refined, which orients the root. */
31
+ refinement: 'https://welte225.org/rules#refinement',
32
+ /** A version derives from one exemplar, so a stemma is a tree. */
33
+ noContamination: 'https://welte225.org/rules#no-contamination'
34
+ };
35
+ /**
36
+ * The published rules the proposal of edits follows, by IRI.
37
+ * @category Filiation
38
+ */
39
+ export const editRules = {
40
+ /** An edit stays at one place: it runs across no command both texts keep. */
41
+ onePlace: 'https://welte225.org/rules#one-place'
42
+ };
43
+ /**
44
+ * The proposition set of a run, with its belief and the inference it
45
+ * rests on. Its id follows from what it is given, so that recording the
46
+ * same run again gives the same set.
47
+ */
48
+ export const recorded = (kind, identity, concluded, run) => {
49
+ const id = `propositions_${v5(JSON.stringify([kind, linkedRolls, identity]), RECORDED)}`;
50
+ const inference = {
51
+ type: 'inference',
52
+ ...(run.actor && { actor: run.actor }),
53
+ note: concluded.note,
54
+ premises: concluded.premises,
55
+ ...(concluded.used.length > 0 && { used: concluded.used }),
56
+ applies: run.applies ?? concluded.applies,
57
+ software: [linkedRolls],
58
+ ...(run.date && { date: run.date })
59
+ };
60
+ return {
61
+ type: 'propositionSet',
62
+ id,
63
+ belief: {
64
+ type: 'belief',
65
+ id: `belief_${v5(id, RECORDED)}`,
66
+ certainty: run.certainty ?? 'likely',
67
+ reasons: [inference]
68
+ }
69
+ };
70
+ };
71
+ /** The statement as one of the set: its annotation names the set, and it carries no belief of its own. */
72
+ export const memberOf = (set, statement) => statement['@annotation']?.id === set && statement['@annotation'].belief === undefined
73
+ ? statement
74
+ : { ...statement, '@annotation': { id: set } };
75
+ /** The ids every annotation of the value names a set by, and every premise names a belief by. */
76
+ const namedIn = (value, names) => {
77
+ if (Array.isArray(value)) {
78
+ value.forEach(item => namedIn(item, names));
79
+ return;
80
+ }
81
+ if (value === null || typeof value !== 'object' || value instanceof Date)
82
+ return;
83
+ const record = value;
84
+ const annotation = record['@annotation'];
85
+ if (annotation?.id !== undefined && annotation.belief === undefined)
86
+ names.add(annotation.id);
87
+ if (Array.isArray(record.premises))
88
+ record.premises.forEach(premise => typeof premise === 'string' && names.add(premise));
89
+ Object.values(record).forEach(child => namedIn(child, names));
90
+ };
91
+ /**
92
+ * The sets the edition keeps, with those given added where it holds none
93
+ * with their id: a set already recorded stays as it was recorded, by
94
+ * whom and when it was first concluded. Kept are the sets a statement
95
+ * belongs to, and those whose belief the reasons of another kept
96
+ * statement or set name as a premise. A set nothing names any longer is
97
+ * the record of a run whose conclusions have all been replaced.
98
+ */
99
+ export const keptSets = (edition, adding) => {
100
+ const held = edition.propositionSets ?? [];
101
+ const known = new Set(held.map(set => set.id));
102
+ const sets = [...held, ...adding.filter(set => !known.has(set.id))];
103
+ const named = new Set();
104
+ namedIn({ ...edition, propositionSets: [] }, named);
105
+ const kept = new Set();
106
+ for (let grown = true; grown;) {
107
+ grown = false;
108
+ for (const set of sets) {
109
+ if (kept.has(set) || !(named.has(set.id) || named.has(set.belief.id)))
110
+ continue;
111
+ kept.add(set);
112
+ namedIn(set.belief, named);
113
+ grown = true;
114
+ }
115
+ }
116
+ const keeping = sets.filter(set => kept.has(set));
117
+ return keeping.length > 0 ? keeping : undefined;
118
+ };
119
+ /** A distance in millimetres as a note gives it. */
120
+ export const inMillimetres = (value) => `${Math.round(value * 100) / 100} mm`;
package/lib/index.d.ts CHANGED
@@ -61,6 +61,7 @@ export * from './analysis/witnesses.js';
61
61
  export { alignFeatures, ALIGNMENT_METHOD, fromAxis, ownFeaturesOf, toAxis, tooShortToShorten, type AlignmentResult } from './collation/alignment.js';
62
62
  export * from './collation/statistics.js';
63
63
  export * from './model/Edition.js';
64
+ export { linkedRolls } from './software.js';
64
65
  export * from './lookup/lookup.js';
65
66
  export * from './lookup/paths.js';
66
67
  export * from './analysis/stemma.js';
package/lib/index.js CHANGED
@@ -24,6 +24,7 @@ export * from './analysis/witnesses.js';
24
24
  export { alignFeatures, ALIGNMENT_METHOD, fromAxis, ownFeaturesOf, toAxis, tooShortToShorten } from './collation/alignment.js';
25
25
  export * from './collation/statistics.js';
26
26
  export * from './model/Edition.js';
27
+ export { linkedRolls } from './software.js';
27
28
  export * from './lookup/lookup.js';
28
29
  export * from './lookup/paths.js';
29
30
  export * from './analysis/stemma.js';
@@ -12,7 +12,11 @@ export declare const exportDate: (date: Date) => string;
12
12
  * and every version carries the context of its own reproducing system.
13
13
  * A reference the edition holds possible, unlikely or false is quoted
14
14
  * rather than stated, so that a reader of the RDF does not take it for
15
- * a fact. The edition given is not changed.
15
+ * a fact, and so is one that belongs to a proposition set held so. A
16
+ * statement that belongs to a set names the set in its annotation,
17
+ * which in RDF makes the set its reifier, and the set, stated once
18
+ * beside the document, carries the belief. The edition given is not
19
+ * changed.
16
20
  * @category Reading and writing
17
21
  */
18
22
  export declare const asJsonLd: (edition: Edition) => any;
@@ -97,38 +97,57 @@ const withChanges = (edition) => Array.isArray(edition.copies) ? { ...edition, c
97
97
  const silentTerms = new Set(Object.entries(context['@context'])
98
98
  .filter(([, definition]) => definition === null)
99
99
  .map(([term]) => term));
100
+ const doubtedSetsOf = (edition) => new Map((edition.propositionSets ?? [])
101
+ .filter(set => !isAsserted(set.belief.certainty))
102
+ .map(set => [set.id, set.belief.id]));
103
+ /** The set a value's annotation names instead of carrying a belief, where the edition doubts it. */
104
+ const doubtedSetOf = (value, doubted) => {
105
+ const annotation = value['@annotation'];
106
+ return isRecord(annotation) && annotation.belief === undefined && typeof annotation['@id'] === 'string'
107
+ ? doubted.get(annotation['@id']) && annotation['@id']
108
+ : undefined;
109
+ };
100
110
  /**
101
111
  * A reference its belief does not hold to be so: it names a node, states
102
- * nothing RDF would read besides, and its belief is below likely.
112
+ * nothing RDF would read besides, and its belief is below likely, or the
113
+ * belief of the proposition set it belongs to is.
103
114
  */
104
- const isDoubtedReference = (value) => isRecord(value)
115
+ const isDoubtedReference = (value, doubted) => isRecord(value)
105
116
  && typeof value['@id'] === 'string'
106
117
  && isRecord(value['@annotation'])
107
- && !isAsserted(certaintyOf(value))
118
+ && (!isAsserted(certaintyOf(value)) || doubtedSetOf(value, doubted) !== undefined)
108
119
  && Object.keys(value).every(key => key === '@id' || key === '@annotation' || silentTerms.has(key));
109
120
  /**
110
121
  * The statement a doubted reference makes, as a JSON-LD-star embedded
111
122
  * node: the triple is named without being stated, and the belief is
112
123
  * about it. The annotation's own id goes along under a key RDF does not
113
- * read, so that an import can put it back.
124
+ * read, so that an import can put it back. A statement that belongs to
125
+ * a proposition set names the set's belief by its id, which is stated
126
+ * with the set.
114
127
  */
115
- const quote = (subject, key, reference, listed) => {
128
+ const quote = (subject, key, reference, listed, doubted) => {
116
129
  const { '@annotation': { '@id': annotation, ...about }, ...object } = reference;
117
- return { '@id': { '@id': subject, [key]: listed ? [object] : object }, annotation, ...about };
130
+ const set = doubtedSetOf(reference, doubted);
131
+ return {
132
+ '@id': { '@id': subject, [key]: listed ? [object] : object },
133
+ annotation,
134
+ ...about,
135
+ ...(set !== undefined && { belief: { '@id': doubted.get(set) } })
136
+ };
118
137
  };
119
138
  /** The value a node states under a key, less the doubted references, which go to the quoted. */
120
- const unquoted = (subject, key, value, quoted) => {
139
+ const unquoted = (subject, key, value, quoted, doubted) => {
121
140
  if (Array.isArray(value)) {
122
141
  return value.filter(item => {
123
- if (!isDoubtedReference(item))
142
+ if (!isDoubtedReference(item, doubted))
124
143
  return true;
125
- quoted.push(quote(subject, key, item, true));
144
+ quoted.push(quote(subject, key, item, true, doubted));
126
145
  return false;
127
146
  });
128
147
  }
129
- if (!isDoubtedReference(value))
148
+ if (!isDoubtedReference(value, doubted))
130
149
  return value;
131
- quoted.push(quote(subject, key, value, false));
150
+ quoted.push(quote(subject, key, value, false, doubted));
132
151
  return undefined;
133
152
  };
134
153
  /**
@@ -141,16 +160,16 @@ const unquoted = (subject, key, value, quoted) => {
141
160
  * between nodes are quoted, since only they can be put back where they
142
161
  * stood; a doubted date or attribution stays annotated in place.
143
162
  */
144
- const withDoubtedReferencesQuoted = (value, quoted) => {
163
+ const withDoubtedReferencesQuoted = (value, quoted, doubted) => {
145
164
  if (Array.isArray(value))
146
- return value.map(item => withDoubtedReferencesQuoted(item, quoted));
165
+ return value.map(item => withDoubtedReferencesQuoted(item, quoted, doubted));
147
166
  if (!isRecord(value))
148
167
  return value;
149
168
  const subject = value['@id'];
150
169
  const node = {};
151
170
  Object.entries(value).forEach(([key, child]) => {
152
- const stated = typeof subject === 'string' && !key.startsWith('@') ? unquoted(subject, key, child, quoted) : child;
153
- const below = withDoubtedReferencesQuoted(stated, quoted);
171
+ const stated = typeof subject === 'string' && !key.startsWith('@') ? unquoted(subject, key, child, quoted, doubted) : child;
172
+ const below = withDoubtedReferencesQuoted(stated, quoted, doubted);
154
173
  if (below !== undefined)
155
174
  node[key] = below;
156
175
  });
@@ -167,12 +186,16 @@ const atOwnPlacesAll = (edition) => edition.copies.some(copy => copy.measurement
167
186
  * and every version carries the context of its own reproducing system.
168
187
  * A reference the edition holds possible, unlikely or false is quoted
169
188
  * rather than stated, so that a reader of the RDF does not take it for
170
- * a fact. The edition given is not changed.
189
+ * a fact, and so is one that belongs to a proposition set held so. A
190
+ * statement that belongs to a set names the set in its annotation,
191
+ * which in RDF makes the set its reifier, and the set, stated once
192
+ * beside the document, carries the belief. The edition given is not
193
+ * changed.
171
194
  * @category Reading and writing
172
195
  */
173
196
  export const asJsonLd = (edition) => {
174
197
  const quoted = [];
175
- const node = withDoubtedReferencesQuoted(withSystemContexts(withCreations(withChanges(asJsonLdEntity(atOwnPlacesAll(edition))))), quoted);
198
+ const node = withDoubtedReferencesQuoted(withSystemContexts(withCreations(withChanges(asJsonLdEntity(atOwnPlacesAll(edition))))), quoted, doubtedSetsOf(edition));
176
199
  // The context is the export's own; one carried in from an import must not override it.
177
200
  const { base, '@context': carried, ...rest } = node;
178
201
  return {
@@ -83,9 +83,20 @@ const withoutEmptyCreations = (json) => Array.isArray(json.versions)
83
83
  : json;
84
84
  /** A statement an export quoted rather than stated: an included node whose id is a triple. */
85
85
  const isQuotedStatement = (node) => node !== null && typeof node === 'object' && node['@id'] !== null && typeof node['@id'] === 'object';
86
- /** The reference a quoted statement made, annotated again with the belief the export set beside it. */
86
+ /**
87
+ * A belief named by its id alone, as a quoted statement names the belief
88
+ * of the proposition set it belongs to, which is stated with the set.
89
+ */
90
+ const isNamedBelief = (belief) => belief !== null && typeof belief === 'object' && Object.keys(belief).every(key => key === '@id');
91
+ /**
92
+ * The reference a quoted statement made, annotated again with the belief
93
+ * the export set beside it, or where it belongs to a proposition set,
94
+ * naming the set again.
95
+ */
87
96
  const referenceOf = (statement) => {
88
- const { '@id': { '@id': subject, ...made }, annotation, ...about } = statement;
97
+ const { '@id': { '@id': subject, ...made }, annotation, ...stated } = statement;
98
+ const { belief, ...rest } = stated;
99
+ const about = isNamedBelief(belief) ? rest : stated;
89
100
  const [key, value] = Object.entries(made)[0];
90
101
  const listed = Array.isArray(value);
91
102
  return {
package/lib/io/migrate.js CHANGED
@@ -63,6 +63,35 @@ const renamedEditTypes = {
63
63
  const withRenamedEditType = (node) => typeof node.editType === 'string' && Object.hasOwn(renamedEditTypes, node.editType)
64
64
  ? { ...node, editType: renamedEditTypes[node.editType] }
65
65
  : node;
66
+ /** The motivation a corrected error is stated with, as `correctedErrorMotivation` was when the kind of edit was retired. */
67
+ const correctedErrorMotivation = {
68
+ '@type': 'motivation',
69
+ '@id': 'corrected-error',
70
+ note: 'Puts right an error of the version it derives from.'
71
+ };
72
+ const isTypedCorrectError = (edit) => edit !== null && typeof edit === 'object' && (edit.editType === 'correct-error' || edit.classification === 'correct-error');
73
+ /**
74
+ * Whether a change corrects an error was once one of the kinds of edit,
75
+ * though it is not read off the shape of a change but is a reason for
76
+ * it. An edit typed so states it as its motivation instead, where it
77
+ * gives none of its own, and the version states what the motivation
78
+ * means; one that gives a motivation of its own keeps that one. Either
79
+ * way it states no kind, its shape being left to be read again.
80
+ */
81
+ const withCorrectedErrorsMotivated = (node) => {
82
+ if (!Array.isArray(node.edits) || !node.edits.some(isTypedCorrectError))
83
+ return node;
84
+ const edits = node.edits.map((edit) => {
85
+ if (!isTypedCorrectError(edit))
86
+ return edit;
87
+ const { editType: _kind, classification: _named, ...rest } = edit;
88
+ return rest.motivation === undefined || rest.motivation === 'unchecked' ? { ...rest, motivation: correctedErrorMotivation['@id'] } : rest;
89
+ });
90
+ const motivations = Array.isArray(node.motivations) ? node.motivations : [];
91
+ const declare = edits.some((edit) => edit?.motivation === correctedErrorMotivation['@id'])
92
+ && !motivations.some(motivation => motivation?.['@id'] === correctedErrorMotivation['@id']);
93
+ return { ...node, edits, ...(declare && { motivations: [...motivations, correctedErrorMotivation] }) };
94
+ };
66
95
  const withRenamedType = (node) => Object.hasOwn(renamedTypes, node['@type']) ? { ...node, '@type': renamedTypes[node['@type']] } : node;
67
96
  /** Whether the feature is of the class under either name, since a node is migrated before its children are. */
68
97
  const isOfType = (type) => (feature) => feature?.['@type'] === type || renamedTypes[feature?.['@type']] === type;
@@ -503,7 +532,7 @@ const withMeasuredByInReasons = (node) => {
503
532
  }
504
533
  };
505
534
  };
506
- const nodeSteps = [withRenamedKeys, withRenamedEditType, withTypology, withRenamedType, withoutVersionType, withoutVersionSiglum, withLowerCaseTerms, withSplitMethod, withReferences, withKeeper, withoutEmptyKeeper,
535
+ const nodeSteps = [withRenamedKeys, withRenamedEditType, withCorrectedErrorsMotivated, withTypology, withRenamedType, withoutVersionType, withoutVersionSiglum, withLowerCaseTerms, withSplitMethod, withReferences, withKeeper, withoutEmptyKeeper,
507
536
  withPerforator, withProductionNodes, withTypedPerforator, withScale, withoutOps, withDerivationList, withReadingKind, withTimeSpanDates,
508
537
  withoutFeatureKind, withBorneFeaturesNamed, withFeaturesInActs, withOwnPlaces, withDriveOfStaggering, withoutPattern, withoutBearings, withoutEntailedType,
509
538
  withMeasuredByInReasons];
@@ -21,7 +21,10 @@ export type Certainty = typeof certainties[number];
21
21
  */
22
22
  export declare const isAsserted: (certainty: Certainty) => boolean;
23
23
  /**
24
- * The certainty a statement is held with. One that carries no belief is stated plainly, and so held true.
24
+ * The certainty a statement is held with for itself. One that carries
25
+ * no belief is stated plainly, and so held true; one that belongs to a
26
+ * proposition set is held with the set's belief, which `certaintyIn`
27
+ * reads.
25
28
  * @category Assumptions and beliefs
26
29
  */
27
30
  export declare const certaintyOf: (assumption: Readonly<Assumption>) => Certainty;
@@ -90,6 +93,24 @@ export interface Inference extends Argumentation<'inference'> {
90
93
  * @see crminf:J3 applied
91
94
  */
92
95
  applies?: string[];
96
+ /**
97
+ * The programs that drew the conclusion, each with its version,
98
+ * where a program drew it: a stemma `proposeStemma` found, which the
99
+ * editor ran and holds. The actor is the one who ran it, since a
100
+ * program holds no belief. Naming software makes the inference a
101
+ * digital machine event in the sense of CRMdig, which can be run
102
+ * again on what it used, and the note states what it was run with.
103
+ * @see crmdig:L23 used software or firmware
104
+ */
105
+ software?: Software[];
106
+ /**
107
+ * When the conclusion was drawn. It is part of the reason and
108
+ * carries no belief of its own, and it tells a run of a program
109
+ * from the next, since a program may conclude otherwise once it, or
110
+ * what it used, has changed.
111
+ * @see crm:P4 has time-span
112
+ */
113
+ date?: TimeSpan;
93
114
  }
94
115
  /**
95
116
  * A belief adoption takes over someone else's belief without checking it:
@@ -202,15 +223,77 @@ export interface Assumption {
202
223
  * An optional annotation expressing a belief about this assumption.
203
224
  * Uses the JSON-LD-star `@annotation` mechanism to attach
204
225
  * epistemic metadata (certainty and reasons) to any triple.
226
+ *
227
+ * An annotation that carries no belief names, by its `id`, the
228
+ * proposition set the statement belongs to (`PropositionSet`): the
229
+ * statement is held with the belief the set states, together with
230
+ * the other statements that name it.
205
231
  */
206
232
  '@annotation'?: WithId & {
207
233
  /**
208
- * The belief held about the annotated statement.
234
+ * The belief held about the annotated statement, where it is
235
+ * held for itself rather than as one of a proposition set.
209
236
  * @see crminf:J4i is subject of
210
237
  */
211
- belief: Belief;
238
+ belief?: Belief;
212
239
  };
213
240
  }
241
+ /**
242
+ * Statements held together under one belief, because one reasoning
243
+ * concluded them together: the derivations and edits of a stemma, which
244
+ * a search such as `proposeStemma` scores as a whole rather than one
245
+ * derivation at a time, or the edits a proposal grouped the changes of
246
+ * versions into. Each statement belongs to the set by naming it in its
247
+ * annotation, which carries the set's id and no belief of its own, and
248
+ * the belief is stated here, once, with the reasoning that concluded
249
+ * it. Read as RDF, the set is the reifier of each statement that names
250
+ * it, which RDF 1.2 lets reify several.
251
+ *
252
+ * A statement the editor takes out of the set by giving it a belief of
253
+ * its own is the editor's, and its reasons can name the set's belief as
254
+ * a premise, so that what the editor decided apart from the program
255
+ * stays apart from it.
256
+ * @see crminf:I4 Proposition Set
257
+ * @category Format types
258
+ */
259
+ export interface PropositionSet extends WithId {
260
+ type: 'propositionSet';
261
+ /**
262
+ * The belief the statements of the set are held with, and the
263
+ * reasons for it.
264
+ * @see crminf:J4i is subject of
265
+ */
266
+ belief: Belief;
267
+ }
268
+ /**
269
+ * Whether the statement carries a belief of its own, rather than none
270
+ * or the belief of the proposition set it belongs to.
271
+ * @category Assumptions and beliefs
272
+ */
273
+ export declare const isHeldForItself: (assumption: Readonly<Assumption>) => boolean;
274
+ /**
275
+ * The id of the proposition set the statement belongs to, where its
276
+ * annotation names one instead of carrying a belief.
277
+ * @category Assumptions and beliefs
278
+ */
279
+ export declare const propositionSetOf: (assumption: Readonly<Assumption>) => string | undefined;
280
+ /**
281
+ * The belief the statement is held with in the edition: its own, or
282
+ * that of the proposition set it belongs to.
283
+ * @category Assumptions and beliefs
284
+ */
285
+ export declare const beliefIn: (edition: {
286
+ propositionSets?: readonly PropositionSet[];
287
+ }, assumption: Readonly<Assumption>) => Belief | undefined;
288
+ /**
289
+ * The certainty the statement is held with in the edition: that of its
290
+ * own belief, or of the proposition set it belongs to. One that carries
291
+ * neither is stated plainly, and so held true.
292
+ * @category Assumptions and beliefs
293
+ */
294
+ export declare const certaintyIn: (edition: {
295
+ propositionSets?: readonly PropositionSet[];
296
+ }, assumption: Readonly<Assumption>) => Certainty;
214
297
  /**
215
298
  * A value assumption wraps a literal value, e.g. a string, a number, a date, with an optional annotation.
216
299
  * Used for properties where the value itself may be uncertain,
@@ -19,10 +19,47 @@ export const certainties = [
19
19
  */
20
20
  export const isAsserted = (certainty) => certainty === 'true' || certainty === 'likely';
21
21
  /**
22
- * The certainty a statement is held with. One that carries no belief is stated plainly, and so held true.
22
+ * The certainty a statement is held with for itself. One that carries
23
+ * no belief is stated plainly, and so held true; one that belongs to a
24
+ * proposition set is held with the set's belief, which `certaintyIn`
25
+ * reads.
23
26
  * @category Assumptions and beliefs
24
27
  */
25
- export const certaintyOf = (assumption) => assumption['@annotation']?.belief.certainty ?? 'true';
28
+ export const certaintyOf = (assumption) => assumption['@annotation']?.belief?.certainty ?? 'true';
29
+ /**
30
+ * Whether the statement carries a belief of its own, rather than none
31
+ * or the belief of the proposition set it belongs to.
32
+ * @category Assumptions and beliefs
33
+ */
34
+ export const isHeldForItself = (assumption) => assumption['@annotation']?.belief !== undefined;
35
+ /**
36
+ * The id of the proposition set the statement belongs to, where its
37
+ * annotation names one instead of carrying a belief.
38
+ * @category Assumptions and beliefs
39
+ */
40
+ export const propositionSetOf = (assumption) => {
41
+ const annotation = assumption['@annotation'];
42
+ return annotation && annotation.belief === undefined ? annotation.id : undefined;
43
+ };
44
+ /**
45
+ * The belief the statement is held with in the edition: its own, or
46
+ * that of the proposition set it belongs to.
47
+ * @category Assumptions and beliefs
48
+ */
49
+ export const beliefIn = (edition, assumption) => {
50
+ const own = assumption['@annotation']?.belief;
51
+ if (own)
52
+ return own;
53
+ const set = propositionSetOf(assumption);
54
+ return set === undefined ? undefined : edition.propositionSets?.find(candidate => candidate.id === set)?.belief;
55
+ };
56
+ /**
57
+ * The certainty the statement is held with in the edition: that of its
58
+ * own belief, or of the proposition set it belongs to. One that carries
59
+ * neither is stated plainly, and so held true.
60
+ * @category Assumptions and beliefs
61
+ */
62
+ export const certaintyIn = (edition, assumption) => beliefIn(edition, assumption)?.certainty ?? 'true';
26
63
  /**
27
64
  * The value the assumption holds, without the belief about it.
28
65
  * @category Assumptions and beliefs
@@ -2,7 +2,10 @@ import { Assumption } from "./Assumption.js";
2
2
  import { AnySymbol } from "./Symbol.js";
3
3
  import { WithId } from "../shared/utils.js";
4
4
  /**
5
- * The types of editorial change an edit may state.
5
+ * The types of editorial change an edit may state. Each is read off the
6
+ * shape of the change, as `proposeEdits` reads it. Whether a change
7
+ * corrects an error is not: it is a reason for the change, and stated as
8
+ * its motivation (`correctedError`).
6
9
  * @category Vocabulary
7
10
  */
8
11
  export declare const editTypes: readonly ['additional-accent', 'add-redundancy', 'remove-redundancy',
@@ -12,11 +15,12 @@ export declare const editTypes: readonly ['additional-accent', 'add-redundancy',
12
15
  * a command the other system cannot read struck, or one of its own
13
16
  * put in where the first had no word for it.
14
17
  */
15
- 'recoding', 'shift', 'correct-error', 'shorten', 'prolong'];
18
+ 'recoding', 'shift', 'shorten', 'prolong'];
16
19
  /**
17
20
  * The type of editorial change applied to a symbol or set of symbols.
18
- * Classifies the nature of the edit, e.g. whether it corrects an error,
19
- * adds an accent, shifts a note, or shortens/prolongs a perforation.
21
+ * Classifies the shape of the edit, e.g. whether it adds an accent,
22
+ * shifts a note, or shortens/prolongs a perforation. Why it was made is
23
+ * its motivation.
20
24
  * @category Format types
21
25
  */
22
26
  export type EditType = typeof editTypes[number];
@@ -24,7 +28,7 @@ export type EditType = typeof editTypes[number];
24
28
  * A set of edits transforms a version of a roll into another version.
25
29
  * Edits insert or delete symbols, or both (= replace).
26
30
  * Edits may be motivated by a given set of reasons, e.g.
27
- * to add an additional accent or to correct an error.
31
+ * to strengthen an accent or to correct an error.
28
32
  * If an edit is the interpretation of a metamark,
29
33
  * such as a pencil mark, this should be made explicit
30
34
  * using a meaning comprehension on the `@annotation` field.
@@ -38,7 +42,7 @@ export type EditType = typeof editTypes[number];
38
42
  export interface Edit extends WithId, Assumption {
39
43
  type: 'edit';
40
44
  /**
41
- * The type of editorial change (e.g. 'correct-error', 'additional-accent').
45
+ * The type of editorial change, as its shape shows it (e.g. 'shift', 'additional-accent').
42
46
  * @see crm:P2 has type
43
47
  */
44
48
  editType?: EditType;
package/lib/model/Edit.js CHANGED
@@ -1,5 +1,8 @@
1
1
  /**
2
- * The types of editorial change an edit may state.
2
+ * The types of editorial change an edit may state. Each is read off the
3
+ * shape of the change, as `proposeEdits` reads it. Whether a change
4
+ * corrects an error is not: it is a reason for the change, and stated as
5
+ * its motivation (`correctedError`).
3
6
  * @category Vocabulary
4
7
  */
5
8
  export const editTypes = [
@@ -14,7 +17,6 @@ export const editTypes = [
14
17
  */
15
18
  'recoding',
16
19
  'shift',
17
- 'correct-error',
18
20
  'shorten',
19
21
  'prolong',
20
22
  ];