@shapeshift-labs/frontier-lang-compiler 0.2.98 → 0.2.100
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.
- package/dist/declarations/semantic-edit-bundle.d.ts +90 -0
- package/dist/declarations/semantic-edit-script.d.ts +34 -37
- package/dist/declarations/semantic-lineage.d.ts +63 -34
- package/dist/declarations/semantic-patch-bundle-index.d.ts +3 -0
- package/dist/declarations/semantic-patch-bundle.d.ts +23 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/internal/index-impl/declarationRecord.js +2 -2
- package/dist/internal/index-impl/inferSemanticLineageEvents.js +8 -0
- package/dist/internal/index-impl/projectSemanticEditScriptToSource.js +56 -64
- package/dist/internal/index-impl/replaySemanticEditProjection.js +54 -22
- package/dist/internal/index-impl/semanticEditBundleAdmission.js +220 -0
- package/dist/internal/index-impl/semanticEditBundleIndex.js +16 -10
- package/dist/internal/index-impl/semanticEditSourceRanges.js +204 -0
- package/dist/internal/index-impl/semanticHistoryLineageResolution.js +35 -1
- package/dist/internal/index-impl/semanticIndexFromNativeDeclarations.js +2 -2
- package/dist/internal/index-impl/semanticLineageInferenceMatching.js +150 -13
- package/dist/internal/index-impl/semanticLineageResolutionRecords.js +28 -1
- package/dist/internal/index-impl/semanticPatchBundleAdmission.js +130 -11
- package/dist/internal/index-impl/semanticPatchBundleLineageLinks.js +199 -0
- package/dist/internal/index-impl/semanticPatchBundleOverlaps.js +6 -2
- package/dist/internal/index-impl/semanticPatchBundleRecords.js +65 -126
- package/dist/internal/index-impl/semanticPatchBundleSourceRecords.js +127 -0
- package/dist/internal/index-impl/sourceTextForSpan.js +4 -9
- package/dist/lightweight-dependency-relations.js +113 -7
- package/dist/native-import-utils.js +15 -1
- package/dist/native-region-scanner-js-helpers.js +61 -17
- package/dist/native-region-scanner-js.js +12 -4
- package/dist/semantic-import-regions.js +3 -3
- package/package.json +1 -1
|
@@ -2,27 +2,43 @@ import { normalizeSemanticMergeReadiness, uniqueStrings } from '../../native-imp
|
|
|
2
2
|
|
|
3
3
|
export function createSemanticPatchBundleAdmission(input = {}, context = {}) {
|
|
4
4
|
const transformAdmission = semanticTransformAdmission(context);
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
5
|
+
const semanticEditAdmission = context.semanticEditAdmission ?? { status: 'none', action: 'none', readiness: 'needs-review', reasonCodes: [] };
|
|
6
|
+
const evidenceAdmission = autoMergeEvidenceAdmission(context, { transformAdmission, semanticEditAdmission });
|
|
7
|
+
const fallbackReadiness = fallbackAdmissionReadiness(transformAdmission, semanticEditAdmission, evidenceAdmission, context.readiness);
|
|
8
|
+
const inputReadiness = normalizeSemanticMergeReadiness(input.readiness ?? fallbackReadiness) ?? input.readiness ?? fallbackReadiness;
|
|
9
|
+
const readiness = hasPositiveApplyAction(transformAdmission, semanticEditAdmission) && evidenceAdmission.action !== 'admit'
|
|
10
|
+
? evidenceAdmission.readiness
|
|
11
|
+
: inputReadiness;
|
|
12
|
+
const computedStatus = admissionStatusForReadiness(readiness, transformAdmission, semanticEditAdmission, evidenceAdmission);
|
|
13
|
+
const status = input.status === 'admitted' && computedStatus !== 'admitted' ? computedStatus : input.status ?? computedStatus;
|
|
14
|
+
const computedAutoApplyCandidate = status === 'admitted' &&
|
|
15
|
+
hasPositiveApplyAction(transformAdmission, semanticEditAdmission) &&
|
|
16
|
+
evidenceAdmission.action === 'admit';
|
|
17
|
+
const autoApplyCandidate = input.autoApplyCandidate === true ? computedAutoApplyCandidate : input.autoApplyCandidate ?? computedAutoApplyCandidate;
|
|
18
|
+
const admittedWithoutPositiveProof = status === 'admitted' &&
|
|
19
|
+
hasPositiveApplyAction(transformAdmission, semanticEditAdmission) &&
|
|
20
|
+
evidenceAdmission.action !== 'admit';
|
|
9
21
|
return compactRecord({
|
|
10
22
|
status,
|
|
11
23
|
readiness,
|
|
12
|
-
reviewRequired: input.reviewRequired ?? status !== 'admitted',
|
|
24
|
+
reviewRequired: input.reviewRequired ?? (status !== 'admitted' || admittedWithoutPositiveProof),
|
|
13
25
|
autoMergeClaim: false,
|
|
14
26
|
autoApplyCandidate,
|
|
15
27
|
transformAdmission,
|
|
28
|
+
semanticEditAdmission,
|
|
29
|
+
evidenceAdmission,
|
|
16
30
|
reasonCodes: uniqueStrings([
|
|
17
31
|
...strings(input.reasonCodes),
|
|
18
32
|
...strings(context.source?.reasons),
|
|
19
33
|
...strings(context.mergeCandidate?.reasons),
|
|
20
|
-
...transformAdmission.reasonCodes
|
|
21
|
-
|
|
34
|
+
...transformAdmission.reasonCodes,
|
|
35
|
+
...strings(semanticEditAdmission.reasonCodes),
|
|
36
|
+
...strings(evidenceAdmission.reasonCodes)
|
|
37
|
+
].filter(Boolean)),
|
|
22
38
|
conflictKeys: uniqueStrings([...strings(input.conflictKeys), ...context.conflictKeys]),
|
|
23
39
|
admittedAt: input.admittedAt,
|
|
24
40
|
reviewerId: input.reviewerId,
|
|
25
|
-
evidenceIds: uniqueStrings([...strings(input.evidenceIds), ...strings(transformAdmission.evidenceIds)]),
|
|
41
|
+
evidenceIds: uniqueStrings([...strings(input.evidenceIds), ...strings(transformAdmission.evidenceIds), ...strings(evidenceAdmission.evidenceIds)]),
|
|
26
42
|
metadata: input.metadata
|
|
27
43
|
});
|
|
28
44
|
}
|
|
@@ -68,7 +84,7 @@ function transformReasonCodes(input) {
|
|
|
68
84
|
!input.complete ? 'transform-evidence-incomplete' : undefined,
|
|
69
85
|
input.ready ? 'transform-auto-apply-candidate' : undefined,
|
|
70
86
|
...input.readinesses.map((readiness) => `transform-readiness:${readiness}`)
|
|
71
|
-
]);
|
|
87
|
+
].filter(Boolean));
|
|
72
88
|
}
|
|
73
89
|
|
|
74
90
|
function transformReadiness(value) {
|
|
@@ -81,17 +97,120 @@ function transformReadiness(value) {
|
|
|
81
97
|
return undefined;
|
|
82
98
|
}
|
|
83
99
|
|
|
84
|
-
function
|
|
100
|
+
function autoMergeEvidenceAdmission(context, admissions) {
|
|
101
|
+
const evidence = uniqueEvidenceRecords([
|
|
102
|
+
...array(context.evidenceRecords),
|
|
103
|
+
...array(context.evidence),
|
|
104
|
+
...array(context.source?.evidence),
|
|
105
|
+
...array(context.source?.patch?.evidence),
|
|
106
|
+
...array(context.source?.semanticPatch?.evidence),
|
|
107
|
+
...array(context.mergeCandidate?.evidence)
|
|
108
|
+
]);
|
|
109
|
+
const positiveApply = hasPositiveApplyAttempt(admissions.transformAdmission, admissions.semanticEditAdmission);
|
|
110
|
+
if (!positiveApply) return { status: 'none', action: 'none', readiness: 'needs-review', reasonCodes: [], evidenceIds: evidenceIds(evidence) };
|
|
111
|
+
const summary = summarizeAutoMergeEvidence(evidence);
|
|
112
|
+
const blocked = summary.failed > 0 || summary.conflict > 0;
|
|
113
|
+
const ready = !blocked && summary.stale === 0 && summary.passed > 0;
|
|
114
|
+
const status = blocked ? 'blocked' : summary.stale > 0 ? 'stale' : ready ? 'ready' : 'needs-review';
|
|
115
|
+
return compactRecord({
|
|
116
|
+
status,
|
|
117
|
+
action: blocked ? 'block' : status === 'stale' ? 'rerun-semantic-import' : ready ? 'admit' : 'review',
|
|
118
|
+
readiness: blocked ? 'blocked' : ready ? 'ready' : 'needs-review',
|
|
119
|
+
reasonCodes: autoMergeEvidenceReasonCodes(summary, status),
|
|
120
|
+
evidenceIds: summary.evidenceIds,
|
|
121
|
+
passed: summary.passed,
|
|
122
|
+
failed: summary.failed,
|
|
123
|
+
conflict: summary.conflict,
|
|
124
|
+
stale: summary.stale
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function summarizeAutoMergeEvidence(evidence) {
|
|
129
|
+
const testLike = evidence.filter(isAutoMergeTestEvidence);
|
|
130
|
+
const failed = testLike.filter((record) => evidenceStatus(record, ['failed', 'failure', 'error', 'blocked', 'rejected']));
|
|
131
|
+
const passed = testLike.filter((record) => evidenceStatus(record, ['passed', 'ok', 'success', 'succeeded', 'accepted', 'verified']));
|
|
132
|
+
const conflict = evidence.filter((record) => evidenceStatus(record, ['conflict', 'conflicted']) || record?.metadata?.conflict === true || strings(record?.reasonCodes ?? record?.reasons).some((reason) => reason.toLowerCase().includes('conflict')));
|
|
133
|
+
const stale = evidence.filter((record) => evidenceStatus(record, ['stale']) || record?.metadata?.stale === true || strings(record?.reasonCodes ?? record?.reasons).some((reason) => reason.toLowerCase().includes('stale')));
|
|
134
|
+
return {
|
|
135
|
+
evidenceIds: evidenceIds(evidence),
|
|
136
|
+
passed: passed.length,
|
|
137
|
+
failed: failed.length,
|
|
138
|
+
conflict: conflict.length,
|
|
139
|
+
stale: stale.length
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function autoMergeEvidenceReasonCodes(summary, status) {
|
|
144
|
+
return uniqueStrings([
|
|
145
|
+
summary.passed ? 'auto-merge-tests-passed' : undefined,
|
|
146
|
+
summary.passed === 0 ? 'auto-merge-tests-passed-evidence-missing' : undefined,
|
|
147
|
+
summary.failed ? 'auto-merge-tests-failed' : undefined,
|
|
148
|
+
summary.conflict ? 'auto-merge-conflict-evidence' : undefined,
|
|
149
|
+
summary.stale ? 'auto-merge-stale-evidence' : undefined,
|
|
150
|
+
status === 'ready' ? 'auto-merge-positive-proof' : undefined
|
|
151
|
+
].filter(Boolean));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function fallbackAdmissionReadiness(transformAdmission, semanticEditAdmission, evidenceAdmission, fallback) {
|
|
155
|
+
if ([transformAdmission.readiness, semanticEditAdmission.readiness, evidenceAdmission.readiness].includes('blocked')) return 'blocked';
|
|
156
|
+
if (hasSkipReadyAction(semanticEditAdmission)) return 'ready';
|
|
157
|
+
if (hasPositiveApplyAction(transformAdmission, semanticEditAdmission)) return evidenceAdmission.action === 'admit' ? 'ready' : evidenceAdmission.readiness;
|
|
158
|
+
return fallback;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function admissionStatusForReadiness(readiness, transformAdmission, semanticEditAdmission, evidenceAdmission) {
|
|
85
162
|
if (readiness === 'blocked') return 'blocked';
|
|
86
|
-
if (transformAdmission
|
|
163
|
+
if (hasAdmissibleReadyAction(transformAdmission, semanticEditAdmission, evidenceAdmission) && readiness === 'ready') return 'admitted';
|
|
87
164
|
return readiness === 'needs-review' ? 'needs-review' : 'proposed';
|
|
88
165
|
}
|
|
89
166
|
|
|
167
|
+
function hasAdmissibleReadyAction(transformAdmission, semanticEditAdmission, evidenceAdmission) {
|
|
168
|
+
return hasSkipReadyAction(semanticEditAdmission) ||
|
|
169
|
+
(hasPositiveApplyAction(transformAdmission, semanticEditAdmission) && evidenceAdmission.action === 'admit');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function hasPositiveApplyAction(transformAdmission, semanticEditAdmission) {
|
|
173
|
+
return [transformAdmission.action, semanticEditAdmission.action].includes('admit');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function hasPositiveApplyAttempt(transformAdmission, semanticEditAdmission) {
|
|
177
|
+
return hasPositiveApplyAction(transformAdmission, semanticEditAdmission) ||
|
|
178
|
+
Number(semanticEditAdmission.summary?.acceptedClean ?? 0) > 0 ||
|
|
179
|
+
strings(transformAdmission.reasonCodes).includes('transform-readiness:auto-merge-candidate');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function hasSkipReadyAction(semanticEditAdmission) {
|
|
183
|
+
return semanticEditAdmission.action === 'skip' && semanticEditAdmission.readiness === 'ready' && semanticEditAdmission.reviewRequired === false;
|
|
184
|
+
}
|
|
185
|
+
|
|
90
186
|
function hasCrossLanguageTransform(index) {
|
|
91
187
|
const source = new Set(strings(index.transformSourceLanguages));
|
|
92
188
|
return strings(index.transformTargetLanguages).some((target) => !source.has(target));
|
|
93
189
|
}
|
|
94
190
|
|
|
191
|
+
function isAutoMergeTestEvidence(record) {
|
|
192
|
+
const kind = String(record?.kind ?? record?.type ?? '').toLowerCase();
|
|
193
|
+
return ['test', 'tests', 'proof', 'gate', 'verification', 'check'].includes(kind);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function evidenceStatus(record, statuses) {
|
|
197
|
+
const status = String(record?.status ?? record?.outcome ?? '').toLowerCase();
|
|
198
|
+
return statuses.includes(status);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function uniqueEvidenceRecords(records) {
|
|
202
|
+
const seen = new Set();
|
|
203
|
+
const result = [];
|
|
204
|
+
for (const record of records.filter(Boolean)) {
|
|
205
|
+
const key = record.id ?? JSON.stringify(record);
|
|
206
|
+
if (seen.has(key)) continue;
|
|
207
|
+
seen.add(key);
|
|
208
|
+
result.push(record);
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function evidenceIds(evidence) { return uniqueStrings(evidence.map((record) => record.id)); }
|
|
95
214
|
function array(value) { if (value === undefined || value === null) return []; return Array.isArray(value) ? value : [value]; }
|
|
96
215
|
function strings(value) { return array(value).map((entry) => String(entry ?? '')).filter(Boolean); }
|
|
97
216
|
function compactRecord(value) { return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0))); }
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { uniqueStrings } from '../../native-import-utils.js';
|
|
2
|
+
|
|
3
|
+
export function lineageLinkInputs(source, options, changedRegions, targetPortability) {
|
|
4
|
+
return [
|
|
5
|
+
...array(options.lineageResolutionLinks ?? options.semanticLineageResolutionLinks),
|
|
6
|
+
...array(options.lineageResolutions ?? options.semanticLineageResolutions),
|
|
7
|
+
...array(source.lineageResolutionLinks ?? source.semanticLineageResolutionLinks),
|
|
8
|
+
...array(source.lineageResolutions ?? source.semanticLineageResolutions),
|
|
9
|
+
...array(source.metadata?.semanticLineageResolutionLinks),
|
|
10
|
+
...array(source.metadata?.semanticHistoryLineageResolution),
|
|
11
|
+
...array(source.metadata?.semanticLineageResolution),
|
|
12
|
+
...array(source.metadata?.targetPortability?.lineageResolutionLinks),
|
|
13
|
+
...array(targetPortability?.lineageResolutionLinks),
|
|
14
|
+
...array(targetPortability?.lineageResolutions),
|
|
15
|
+
...changedRegions.flatMap((region) => lineageLinksFromRegion(region))
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function normalizeLineageResolutionLinks(entries) {
|
|
20
|
+
const seen = new Set();
|
|
21
|
+
const result = [];
|
|
22
|
+
for (const entry of lineageResolutionEntries(entries)) {
|
|
23
|
+
const currentAnchors = array(entry.currentAnchors);
|
|
24
|
+
const summary = entry.summary ?? {};
|
|
25
|
+
const anchorSummary = entry.anchorSummary ?? {};
|
|
26
|
+
const ids = uniqueStrings([
|
|
27
|
+
entry.id,
|
|
28
|
+
entry.resolutionId,
|
|
29
|
+
entry.lineageResolutionId,
|
|
30
|
+
...strings(entry.lineageResolutionIds),
|
|
31
|
+
...strings(entry.semanticLineageResolutionIds),
|
|
32
|
+
...strings(summary.lineageResolutionIds)
|
|
33
|
+
]);
|
|
34
|
+
const link = compactRecord({
|
|
35
|
+
id: firstString(entry.id, entry.resolutionId, entry.lineageResolutionId, ids[0]),
|
|
36
|
+
lineageResolutionIds: ids,
|
|
37
|
+
status: entry.status,
|
|
38
|
+
readiness: entry.readiness ?? entry.admission?.readiness,
|
|
39
|
+
action: entry.action ?? entry.admission?.action,
|
|
40
|
+
anchorKeys: uniqueStrings([
|
|
41
|
+
entry.anchorKey,
|
|
42
|
+
entry.query?.anchorKey,
|
|
43
|
+
entry.startAnchor?.key,
|
|
44
|
+
...strings(entry.anchorKeys),
|
|
45
|
+
...strings(anchorSummary.activeAnchorKeys),
|
|
46
|
+
...strings(anchorSummary.candidateAnchorKeys),
|
|
47
|
+
...strings(anchorSummary.blockedAnchorKeys),
|
|
48
|
+
...strings(summary.activeAnchorKeys),
|
|
49
|
+
...strings(summary.candidateAnchorKeys),
|
|
50
|
+
...strings(summary.blockedAnchorKeys),
|
|
51
|
+
...currentAnchors.map((anchor) => anchor.key)
|
|
52
|
+
]),
|
|
53
|
+
sourcePaths: uniqueStrings([
|
|
54
|
+
entry.sourcePath,
|
|
55
|
+
entry.query?.sourcePath,
|
|
56
|
+
entry.startAnchor?.sourcePath,
|
|
57
|
+
...strings(entry.sourcePaths),
|
|
58
|
+
...strings(entry.lineageSourcePaths),
|
|
59
|
+
...strings(summary.sourcePaths),
|
|
60
|
+
...currentAnchors.flatMap((anchor) => [anchor.sourcePath, ...strings(anchor.lineageSourcePaths)])
|
|
61
|
+
]),
|
|
62
|
+
evidenceIds: uniqueStrings([
|
|
63
|
+
...strings(entry.evidenceIds),
|
|
64
|
+
...strings(entry.lineageEvidenceIds),
|
|
65
|
+
...strings(summary.evidenceIds),
|
|
66
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.evidenceIds))
|
|
67
|
+
]),
|
|
68
|
+
proofIds: uniqueStrings([
|
|
69
|
+
...strings(entry.proofIds),
|
|
70
|
+
...strings(entry.lineageProofIds),
|
|
71
|
+
...strings(summary.proofIds),
|
|
72
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.proofIds))
|
|
73
|
+
]),
|
|
74
|
+
lineageEventIds: uniqueStrings([
|
|
75
|
+
...strings(entry.lineageEventIds),
|
|
76
|
+
...strings(entry.traversedEventIds),
|
|
77
|
+
...strings(summary.lineageEventIds),
|
|
78
|
+
...strings(summary.traversedEventIds),
|
|
79
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.lineageEventIds))
|
|
80
|
+
]),
|
|
81
|
+
terminalEventIds: uniqueStrings([
|
|
82
|
+
...strings(entry.terminalEventIds),
|
|
83
|
+
...strings(summary.terminalEventIds),
|
|
84
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.terminalLineageEventIds))
|
|
85
|
+
]),
|
|
86
|
+
crdtOperationIds: uniqueStrings([
|
|
87
|
+
...strings(entry.crdtOperationIds),
|
|
88
|
+
...strings(summary.crdtOperationIds),
|
|
89
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.crdtOperationIds))
|
|
90
|
+
]),
|
|
91
|
+
crdtHeads: uniqueStrings([
|
|
92
|
+
...strings(entry.crdtHeads),
|
|
93
|
+
...strings(summary.crdtHeads),
|
|
94
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.crdtHeads))
|
|
95
|
+
]),
|
|
96
|
+
reasonCodes: uniqueStrings([
|
|
97
|
+
...strings(entry.reasonCodes),
|
|
98
|
+
...strings(entry.lineageReasonCodes),
|
|
99
|
+
...strings(summary.reasonCodes),
|
|
100
|
+
...currentAnchors.flatMap((anchor) => strings(anchor.lineageReasonCodes))
|
|
101
|
+
])
|
|
102
|
+
});
|
|
103
|
+
const key = firstString(link.id, ...strings(link.lineageResolutionIds), ...strings(link.lineageEventIds), ...strings(link.evidenceIds), ...strings(link.sourcePaths));
|
|
104
|
+
if (!key || seen.has(key)) continue;
|
|
105
|
+
seen.add(key);
|
|
106
|
+
result.push(link);
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function semanticLineageLinkIndex(links = [], changedRegions = [], targetPortability, admission) {
|
|
112
|
+
const records = normalizeLineageResolutionLinks([
|
|
113
|
+
...array(links),
|
|
114
|
+
...array(targetPortability?.lineageResolutionLinks),
|
|
115
|
+
...array(targetPortability?.lineageResolutions),
|
|
116
|
+
...array(admission?.metadata?.semanticLineageResolutionLinks),
|
|
117
|
+
...array(changedRegions).flatMap((region) => lineageLinksFromRegion(region))
|
|
118
|
+
]);
|
|
119
|
+
return {
|
|
120
|
+
lineageResolutionIds: uniqueStrings(records.flatMap((record) => [record.id, ...strings(record.lineageResolutionIds)])),
|
|
121
|
+
lineageEventIds: uniqueStrings(records.flatMap((record) => record.lineageEventIds)),
|
|
122
|
+
sourcePaths: uniqueStrings(records.flatMap((record) => record.sourcePaths)),
|
|
123
|
+
evidenceIds: uniqueStrings(records.flatMap((record) => record.evidenceIds)),
|
|
124
|
+
proofIds: uniqueStrings(records.flatMap((record) => record.proofIds)),
|
|
125
|
+
reasonCodes: uniqueStrings(records.flatMap((record) => record.reasonCodes)),
|
|
126
|
+
terminalEventIds: uniqueStrings(records.flatMap((record) => record.terminalEventIds)),
|
|
127
|
+
crdtOperationIds: uniqueStrings(records.flatMap((record) => record.crdtOperationIds)),
|
|
128
|
+
crdtHeads: uniqueStrings(records.flatMap((record) => record.crdtHeads))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function linkAdmissionLineage(admission, lineageLinks) {
|
|
133
|
+
if (lineageLinks.length === 0) return admission;
|
|
134
|
+
const lineageIndex = semanticLineageLinkIndex(lineageLinks);
|
|
135
|
+
return {
|
|
136
|
+
...admission,
|
|
137
|
+
evidenceIds: uniqueStrings([...strings(admission.evidenceIds), ...lineageIndex.evidenceIds]),
|
|
138
|
+
reasonCodes: uniqueStrings([...strings(admission.reasonCodes), 'semantic-lineage-resolution-linked', ...lineageIndex.reasonCodes]),
|
|
139
|
+
metadata: compactRecord({
|
|
140
|
+
...(admission.metadata ?? {}),
|
|
141
|
+
semanticLineageResolutionLinks: lineageLinks
|
|
142
|
+
})
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function lineageLinksFromRegion(region = {}) {
|
|
147
|
+
const metadata = region.metadata ?? {};
|
|
148
|
+
const bidirectional = metadata.bidirectionalTargetChange ?? {};
|
|
149
|
+
const history = metadata.semanticHistoryLineageResolution ?? {};
|
|
150
|
+
const lineage = metadata.semanticLineageResolution ?? {};
|
|
151
|
+
return [
|
|
152
|
+
...array(region.lineageResolutionLinks),
|
|
153
|
+
...array(region.lineageResolutions),
|
|
154
|
+
compactRecord({
|
|
155
|
+
lineageResolutionIds: region.lineageResolutionIds,
|
|
156
|
+
lineageEventIds: region.lineageEventIds,
|
|
157
|
+
sourcePaths: region.lineageSourcePaths,
|
|
158
|
+
evidenceIds: region.lineageEvidenceIds,
|
|
159
|
+
proofIds: region.lineageProofIds,
|
|
160
|
+
reasonCodes: region.lineageReasonCodes
|
|
161
|
+
}),
|
|
162
|
+
bidirectional,
|
|
163
|
+
history,
|
|
164
|
+
lineage,
|
|
165
|
+
...array(bidirectional.lineageResolutionLinks),
|
|
166
|
+
...array(history.lineageResolutionLinks),
|
|
167
|
+
...array(lineage.lineageResolutionLinks)
|
|
168
|
+
].filter((entry) => Object.keys(entry ?? {}).length > 0);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function lineageResolutionEntries(entries) {
|
|
172
|
+
const result = [];
|
|
173
|
+
for (const entry of array(entries).filter(Boolean)) {
|
|
174
|
+
result.push(entry);
|
|
175
|
+
result.push(...array(entry.resolutions));
|
|
176
|
+
result.push(...array(entry.lineageResolutions));
|
|
177
|
+
result.push(...array(entry.semanticLineageResolutions));
|
|
178
|
+
result.push(...array(entry.lineageResolutionLinks));
|
|
179
|
+
result.push(...array(entry.semanticLineageResolutionLinks));
|
|
180
|
+
}
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function array(value) {
|
|
185
|
+
if (value === undefined || value === null) return [];
|
|
186
|
+
return Array.isArray(value) ? value : [value];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function strings(value) {
|
|
190
|
+
return array(value).map((entry) => String(entry ?? '')).filter(Boolean);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function firstString(...values) {
|
|
194
|
+
return values.map((value) => value === undefined || value === null ? '' : String(value)).find(Boolean);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function compactRecord(value) {
|
|
198
|
+
return Object.fromEntries(Object.entries(value ?? {}).filter(([, entry]) => entry !== undefined && (!Array.isArray(entry) || entry.length > 0)));
|
|
199
|
+
}
|
|
@@ -113,8 +113,12 @@ function sharedIndex(left,right,options){
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function overlapAdmission(shared,{leftIndex,rightIndex,options}){
|
|
116
|
-
const
|
|
117
|
-
const
|
|
116
|
+
const hashMismatch=disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)||disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes);
|
|
117
|
+
const sourceRelated=shared.sourcePaths.length||shared.regionKeys.length||shared.conflictKeys.length||shared.sourceIdentityHashes.length;
|
|
118
|
+
const editContent=shared.operationContentHashes.length||shared.editContentHashes.length||shared.semanticEditReplayOutputHashes.length;
|
|
119
|
+
const transformContent=shared.semanticTransformContentHashes.length&&shared.projectionIdentityHashes.length;
|
|
120
|
+
const duplicate=(transformContent||shared.semanticEditReplayIds.length||(editContent&&sourceRelated))&&!hashMismatch;
|
|
121
|
+
const semantic=editContent||shared.semanticEditKeys.length||shared.semanticIdentityHashes.length||shared.sourceIdentityHashes.length||shared.semanticTransformIdentityHashes.length||shared.projectionIdentityHashes.length;
|
|
118
122
|
const source=shared.regionKeys.length||shared.conflictKeys.length||shared.sourcePaths.length||shared.semanticEditReplayCurrentHashes.length;
|
|
119
123
|
const status=duplicate?'duplicate':semantic?'semantic-overlap':source?'source-overlap':'independent';
|
|
120
124
|
const reasonCodes=uniqueStrings([
|