@shapeshift-labs/frontier-lang-compiler 0.2.69 → 0.2.70
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-impact.d.ts +12 -0
- package/dist/internal/index-impl/compileNativeSource.js +13 -1
- package/dist/internal/index-impl/nativeProjectionReview.js +73 -0
- package/dist/internal/index-impl/projectNativeImportToSource.js +10 -1
- package/dist/semantic-import-impact-types.d.ts +21 -0
- package/dist/semantic-import-impact.js +5 -2
- package/dist/semantic-import-merge-signal.js +86 -0
- package/package.json +1 -1
|
@@ -3,12 +3,21 @@ import type { NativeImportRegionTaxonomyKind } from './native-import-losses.js';
|
|
|
3
3
|
|
|
4
4
|
export type SemanticImportImpactRisk = 'low' | 'medium' | 'high' | string;
|
|
5
5
|
export type SemanticImportImpactConfidence = 'source-exact' | 'source-addressed' | 'estimated-source-region' | 'review-required' | string;
|
|
6
|
+
export type SemanticImportMergeSignalStatus = 'strong' | 'partial' | 'weak' | 'blocked' | string;
|
|
6
7
|
|
|
7
8
|
export interface SemanticImportImpactVerificationStep {
|
|
8
9
|
readonly kind: 'dependency-review' | 'source-map-review' | 'reject-or-reprove' | 'proof-review' | 'patch-admission' | 'evidence-review' | string;
|
|
9
10
|
readonly reason: string;
|
|
10
11
|
readonly required: boolean;
|
|
11
12
|
}
|
|
13
|
+
export interface SemanticImportMergeSignal {
|
|
14
|
+
readonly status: SemanticImportMergeSignalStatus;
|
|
15
|
+
readonly score: number;
|
|
16
|
+
readonly missing: readonly string[];
|
|
17
|
+
readonly reviewRequired: boolean;
|
|
18
|
+
readonly queryKeys: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
export interface SemanticImportMergeSignalScoreSummary { readonly min: number; readonly max: number; readonly average: number; }
|
|
12
21
|
|
|
13
22
|
export interface SemanticImportImpactRecord {
|
|
14
23
|
readonly id: string;
|
|
@@ -39,6 +48,7 @@ export interface SemanticImportImpactRecord {
|
|
|
39
48
|
readonly readiness: SemanticMergeReadiness;
|
|
40
49
|
readonly risk: SemanticImportImpactRisk;
|
|
41
50
|
readonly confidence: SemanticImportImpactConfidence;
|
|
51
|
+
readonly mergeSignal: SemanticImportMergeSignal;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
export interface SemanticImportImpactSummary {
|
|
@@ -51,5 +61,7 @@ export interface SemanticImportImpactSummary {
|
|
|
51
61
|
readonly sourceMapMappings: number; readonly sourcePreservationRecords: number; readonly patchHints: number;
|
|
52
62
|
readonly proofObligations: number; readonly openProofObligations: number; readonly failedProofObligations: number; readonly paradigmSemantics: number; readonly loweringRecords: number;
|
|
53
63
|
readonly evidenceIds: number; readonly verificationPlans: readonly string[]; readonly requiredVerificationSteps: number;
|
|
64
|
+
readonly byMergeSignal: Readonly<Record<string, number>>; readonly weakMergeSignals: number; readonly reviewRequiredMergeSignals: number;
|
|
65
|
+
readonly mergeSignalQueryKeys: readonly string[]; readonly mergeSignalScores: SemanticImportMergeSignalScoreSummary;
|
|
54
66
|
};
|
|
55
67
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{nativeLanguageCompileTarget}from'../../coverage-matrix-profiles.js';import{idFragment,uniqueByEvidenceId,uniqueByLossId}from'../../native-import-utils.js';
|
|
2
|
-
import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{createProjectionTargetLossMatrix}from'./createProjectionTargetLossMatrix.js';import{importNativeSource}from'./importNativeSource.js';import{isNativeSourceImportResult}from'./isNativeSourceImportResult.js';import{nativeCompileSourceLanguage}from'./nativeCompileSourceLanguage.js';import{nativeCompileTarget}from'./nativeCompileTarget.js';import{nativeSourceCompileEvidence}from'./nativeSourceCompileEvidence.js';import{nativeSourceCompileSourceMaps}from'./nativeSourceCompileSourceMaps.js';import{nativeSourceCompileTargetCoverage}from'./nativeSourceCompileTargetCoverage.js';import{nativeSourceCompileTargetLosses}from'./nativeSourceCompileTargetLosses.js';import{projectNativeImportToSource}from'./projectNativeImportToSource.js';import{resolveNativeTargetProjectionAdapter}from'./resolveNativeTargetProjectionAdapter.js';import{runNativeTargetProjectionAdapter}from'./runNativeTargetProjectionAdapter.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
|
|
2
|
+
import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{createProjectionTargetLossMatrix}from'./createProjectionTargetLossMatrix.js';import{importNativeSource}from'./importNativeSource.js';import{isNativeSourceImportResult}from'./isNativeSourceImportResult.js';import{nativeCompileSourceLanguage}from'./nativeCompileSourceLanguage.js';import{nativeCompileTarget}from'./nativeCompileTarget.js';import{nativeProjectionReview}from'./nativeProjectionReview.js';import{nativeSourceCompileEvidence}from'./nativeSourceCompileEvidence.js';import{nativeSourceCompileSourceMaps}from'./nativeSourceCompileSourceMaps.js';import{nativeSourceCompileTargetCoverage}from'./nativeSourceCompileTargetCoverage.js';import{nativeSourceCompileTargetLosses}from'./nativeSourceCompileTargetLosses.js';import{projectNativeImportToSource}from'./projectNativeImportToSource.js';import{resolveNativeTargetProjectionAdapter}from'./resolveNativeTargetProjectionAdapter.js';import{runNativeTargetProjectionAdapter}from'./runNativeTargetProjectionAdapter.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
|
|
3
3
|
export function compileNativeSource(input, options = {}) {
|
|
4
4
|
const importResult = isNativeSourceImportResult(input) ? input : importNativeSource(input);
|
|
5
5
|
const sourceLanguage = nativeCompileSourceLanguage(importResult, input);
|
|
@@ -124,6 +124,17 @@ export function compileNativeSource(input, options = {}) {
|
|
|
124
124
|
compileResultId: id
|
|
125
125
|
});
|
|
126
126
|
const sourceMap = sourceMaps[0];
|
|
127
|
+
const projectionReview = nativeProjectionReview({
|
|
128
|
+
mode: projection.mode, outputMode, language: projection.language, sourceLanguage, target,
|
|
129
|
+
sourcePath: importResult.sourcePath ?? importResult.nativeSource?.sourcePath,
|
|
130
|
+
exactSourceAvailable: projection.metadata?.exactSourceAvailable === true,
|
|
131
|
+
sourceTextAvailable: projection.metadata?.sourceTextAvailable === true,
|
|
132
|
+
sourceHashVerified: projection.metadata?.sourceHashVerified === true,
|
|
133
|
+
declarationCount: projection.declarations.length, sourceMapCount: sourceMaps.length,
|
|
134
|
+
losses, targetLosses, readiness: readiness.readiness, targetCoverage, targetProjection
|
|
135
|
+
});
|
|
136
|
+
compileEvidence.metadata.projectionReview = projectionReview;
|
|
137
|
+
for (const record of sourceMaps) record.metadata = { ...(record.metadata ?? {}), projectionReview };
|
|
127
138
|
const roundtripEvidence = createNativeRoundtripEvidence(importResult, {
|
|
128
139
|
id: `evidence_${idPart}_${idFragment(target)}_native_roundtrip`,
|
|
129
140
|
projection,
|
|
@@ -179,6 +190,7 @@ export function compileNativeSource(input, options = {}) {
|
|
|
179
190
|
targetLossClass: targetCoverage.lossClass,
|
|
180
191
|
targetReadiness: targetCoverage.readiness,
|
|
181
192
|
targetSupported: targetCoverage.supported,
|
|
193
|
+
projectionReview,
|
|
182
194
|
...options.metadata,
|
|
183
195
|
roundtripEvidence: roundtripEvidence.metadata.roundtripEvidence
|
|
184
196
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import{uniqueStrings}from'../../native-import-utils.js';
|
|
2
|
+
|
|
3
|
+
export function nativeProjectionReview(input) {
|
|
4
|
+
const lossIds = (input.losses ?? []).map((loss) => loss.id).filter(Boolean);
|
|
5
|
+
const blockingLossIds = (input.losses ?? []).filter((loss) => loss.severity === 'error').map((loss) => loss.id).filter(Boolean);
|
|
6
|
+
const targetLossIds = (input.targetLosses ?? []).map((loss) => loss.id).filter(Boolean);
|
|
7
|
+
const fallbackReasons = nativeProjectionFallbackReasons(input, blockingLossIds, targetLossIds);
|
|
8
|
+
const reviewRequired = input.readiness !== 'ready' || fallbackReasons.length > 0 || blockingLossIds.length > 0;
|
|
9
|
+
const status = nativeProjectionReviewStatus(input, blockingLossIds);
|
|
10
|
+
return {
|
|
11
|
+
kind: 'frontier.lang.nativeProjectionReview',
|
|
12
|
+
version: 1,
|
|
13
|
+
status,
|
|
14
|
+
reviewRequired,
|
|
15
|
+
projectionMode: input.mode,
|
|
16
|
+
outputMode: input.outputMode ?? input.mode,
|
|
17
|
+
language: input.language,
|
|
18
|
+
sourceLanguage: input.sourceLanguage ?? input.language,
|
|
19
|
+
target: input.target,
|
|
20
|
+
sourcePath: input.sourcePath,
|
|
21
|
+
exactSourceAvailable: input.exactSourceAvailable === true,
|
|
22
|
+
sourceTextAvailable: input.sourceTextAvailable === true,
|
|
23
|
+
sourceHashVerified: input.sourceHashVerified === true,
|
|
24
|
+
declarationCount: input.declarationCount ?? 0,
|
|
25
|
+
sourceMapCount: input.sourceMapCount ?? 0,
|
|
26
|
+
readiness: input.readiness,
|
|
27
|
+
targetLossClass: input.targetCoverage?.lossClass,
|
|
28
|
+
targetReadiness: input.targetCoverage?.readiness,
|
|
29
|
+
targetSupported: input.targetCoverage?.supported,
|
|
30
|
+
targetProjectionAdapterId: input.targetProjection?.adapter?.id,
|
|
31
|
+
fallbackReasons,
|
|
32
|
+
lossIds: uniqueStrings(lossIds),
|
|
33
|
+
blockingLossIds: uniqueStrings(blockingLossIds),
|
|
34
|
+
targetLossIds: uniqueStrings(targetLossIds),
|
|
35
|
+
queryKeys: nativeProjectionReviewQueryKeys(input, status, fallbackReasons, reviewRequired)
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function nativeProjectionFallbackReasons(input, blockingLossIds, targetLossIds) {
|
|
40
|
+
const reasons = [];
|
|
41
|
+
if (input.exactSourceAvailable !== true) reasons.push('no-exact-source');
|
|
42
|
+
if (input.sourceHashVerified !== true) reasons.push('source-hash-unverified');
|
|
43
|
+
if (input.mode === 'native-source-stubs') reasons.push('declaration-stubs');
|
|
44
|
+
if (input.outputMode === 'target-stubs') reasons.push('target-stubs');
|
|
45
|
+
if (input.targetCoverage?.supported === false) reasons.push('target-unsupported');
|
|
46
|
+
if (input.targetCoverage?.lossClass === 'missingAdapter') reasons.push('missing-target-adapter');
|
|
47
|
+
if (blockingLossIds.length > 0) reasons.push('blocking-losses');
|
|
48
|
+
if (targetLossIds.length > 0) reasons.push('target-losses');
|
|
49
|
+
return uniqueStrings(reasons);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function nativeProjectionReviewStatus(input, blockingLossIds) {
|
|
53
|
+
if (blockingLossIds.length > 0 || input.readiness === 'blocked' || input.targetCoverage?.readiness === 'blocked') return 'blocked';
|
|
54
|
+
if (input.outputMode === 'target-adapter') return 'target-adapter';
|
|
55
|
+
if (input.outputMode === 'target-stubs' || input.mode === 'native-source-stubs') return 'stub-only';
|
|
56
|
+
if (input.sourceHashVerified === true && input.exactSourceAvailable === true) return 'preserved-source';
|
|
57
|
+
return 'needs-review';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function nativeProjectionReviewQueryKeys(input, status, fallbackReasons, reviewRequired) {
|
|
61
|
+
return uniqueStrings([
|
|
62
|
+
`projection-review:${status}`,
|
|
63
|
+
reviewRequired ? 'review-required' : 'review-not-required',
|
|
64
|
+
input.language ? `language:${input.language}` : undefined,
|
|
65
|
+
input.sourceLanguage ? `source-language:${input.sourceLanguage}` : undefined,
|
|
66
|
+
input.target ? `target:${input.target}` : undefined,
|
|
67
|
+
input.sourcePath ? `source:${input.sourcePath}` : undefined,
|
|
68
|
+
input.mode ? `projection-mode:${input.mode}` : undefined,
|
|
69
|
+
input.outputMode ? `output-mode:${input.outputMode}` : undefined,
|
|
70
|
+
input.targetCoverage?.lossClass ? `target-loss-class:${input.targetCoverage.lossClass}` : undefined,
|
|
71
|
+
...fallbackReasons.map((reason) => `fallback:${reason}`)
|
|
72
|
+
].filter(Boolean));
|
|
73
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
|
|
2
|
-
import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{nativeImportProjectionContext}from'./nativeImportProjectionContext.js';import{nativeProjectionDeclarations}from'./nativeProjectionDeclarations.js';import{nativeProjectionSourceCandidate}from'./nativeProjectionSourceCandidate.js';import{nativeProjectionStubLosses}from'./nativeProjectionStubLosses.js';import{renderNativeProjectionStubs}from'./renderNativeProjectionStubs.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
|
|
2
|
+
import{classifyNativeImportReadiness}from'./classifyNativeImportReadiness.js';import{createNativeRoundtripEvidence}from'./createNativeRoundtripEvidence.js';import{nativeImportProjectionContext}from'./nativeImportProjectionContext.js';import{nativeProjectionDeclarations}from'./nativeProjectionDeclarations.js';import{nativeProjectionReview}from'./nativeProjectionReview.js';import{nativeProjectionSourceCandidate}from'./nativeProjectionSourceCandidate.js';import{nativeProjectionStubLosses}from'./nativeProjectionStubLosses.js';import{renderNativeProjectionStubs}from'./renderNativeProjectionStubs.js';import{summarizeNativeImportLosses}from'./summarizeNativeImportLosses.js';
|
|
3
3
|
export function projectNativeImportToSource(importResult, options = {}) {
|
|
4
4
|
if (!importResult || typeof importResult !== 'object') {
|
|
5
5
|
throw new Error('projectNativeImportToSource requires a native import result');
|
|
@@ -49,6 +49,14 @@ export function projectNativeImportToSource(importResult, options = {}) {
|
|
|
49
49
|
parser: context.parser,
|
|
50
50
|
semanticStatus: context.semanticStatus
|
|
51
51
|
});
|
|
52
|
+
const projectionReview = nativeProjectionReview({
|
|
53
|
+
mode, language: context.language, sourcePath: context.sourcePath,
|
|
54
|
+
exactSourceAvailable: candidateSource?.exact === true,
|
|
55
|
+
sourceTextAvailable: typeof candidateSource?.sourceText === 'string',
|
|
56
|
+
sourceHashVerified: candidateSource?.hashVerified ?? false,
|
|
57
|
+
declarationCount: declarations.length, losses, readiness: readiness.readiness
|
|
58
|
+
});
|
|
59
|
+
evidence[0].metadata.projectionReview = projectionReview;
|
|
52
60
|
const result = {
|
|
53
61
|
kind: 'frontier.lang.nativeSourceProjection',
|
|
54
62
|
version: 1,
|
|
@@ -75,6 +83,7 @@ export function projectNativeImportToSource(importResult, options = {}) {
|
|
|
75
83
|
sourcePreservationId: candidateSource?.sourcePreservationId,
|
|
76
84
|
sourceHashVerified: candidateSource?.hashVerified ?? false,
|
|
77
85
|
nativeImportLossSummary,
|
|
86
|
+
projectionReview,
|
|
78
87
|
...options.metadata
|
|
79
88
|
}
|
|
80
89
|
};
|
|
@@ -3,6 +3,7 @@ import type { NativeImportRegionTaxonomyKind } from './index.js';
|
|
|
3
3
|
|
|
4
4
|
export type SemanticImportImpactRisk = 'low' | 'medium' | 'high' | string;
|
|
5
5
|
export type SemanticImportImpactConfidence = 'source-exact' | 'source-addressed' | 'estimated-source-region' | 'review-required' | string;
|
|
6
|
+
export type SemanticImportMergeSignalStatus = 'strong' | 'partial' | 'weak' | 'blocked' | string;
|
|
6
7
|
|
|
7
8
|
export interface SemanticImportImpactVerificationStep {
|
|
8
9
|
readonly kind: 'dependency-review' | 'source-map-review' | 'reject-or-reprove' | 'proof-review' | 'patch-admission' | 'evidence-review' | string;
|
|
@@ -10,6 +11,20 @@ export interface SemanticImportImpactVerificationStep {
|
|
|
10
11
|
readonly required: boolean;
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
export interface SemanticImportMergeSignal {
|
|
15
|
+
readonly status: SemanticImportMergeSignalStatus;
|
|
16
|
+
readonly score: number;
|
|
17
|
+
readonly missing: readonly string[];
|
|
18
|
+
readonly reviewRequired: boolean;
|
|
19
|
+
readonly queryKeys: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SemanticImportMergeSignalScoreSummary {
|
|
23
|
+
readonly min: number;
|
|
24
|
+
readonly max: number;
|
|
25
|
+
readonly average: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
13
28
|
export interface SemanticImportImpactRecord {
|
|
14
29
|
readonly id: string;
|
|
15
30
|
readonly kind: 'ownership-region-impact' | string;
|
|
@@ -39,6 +54,7 @@ export interface SemanticImportImpactRecord {
|
|
|
39
54
|
readonly readiness: SemanticMergeReadiness;
|
|
40
55
|
readonly risk: SemanticImportImpactRisk;
|
|
41
56
|
readonly confidence: SemanticImportImpactConfidence;
|
|
57
|
+
readonly mergeSignal: SemanticImportMergeSignal;
|
|
42
58
|
}
|
|
43
59
|
|
|
44
60
|
export interface SemanticImportImpactSummary {
|
|
@@ -63,5 +79,10 @@ export interface SemanticImportImpactSummary {
|
|
|
63
79
|
readonly evidenceIds: number;
|
|
64
80
|
readonly verificationPlans: readonly string[];
|
|
65
81
|
readonly requiredVerificationSteps: number;
|
|
82
|
+
readonly byMergeSignal: Readonly<Record<string, number>>;
|
|
83
|
+
readonly weakMergeSignals: number;
|
|
84
|
+
readonly reviewRequiredMergeSignals: number;
|
|
85
|
+
readonly mergeSignalQueryKeys: readonly string[];
|
|
86
|
+
readonly mergeSignalScores: SemanticImportMergeSignalScoreSummary;
|
|
66
87
|
};
|
|
67
88
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { countBy, idFragment, maxSemanticMergeReadiness, uniqueRecordsById, uniqueStrings } from './native-import-utils.js';
|
|
2
2
|
import { semanticDependencyPredicateKey } from './semantic-import-dependencies.js';
|
|
3
|
+
import { semanticImpactMergeSignal, summarizeSemanticImpactMergeSignals } from './semantic-import-merge-signal.js';
|
|
3
4
|
|
|
4
5
|
function createSemanticImportImpact(input) {
|
|
5
6
|
const relations = collectDependencyRelations(input.imports, input.dependencies);
|
|
@@ -60,7 +61,7 @@ function semanticImpactRecord(input) {
|
|
|
60
61
|
relationCount: input.relations.length,
|
|
61
62
|
verificationPlan
|
|
62
63
|
});
|
|
63
|
-
|
|
64
|
+
const record = {
|
|
64
65
|
id: `impact_${idFragment(input.region.id ?? input.region.key)}`,
|
|
65
66
|
kind: 'ownership-region-impact',
|
|
66
67
|
ownershipRegionId: input.region.id,
|
|
@@ -93,6 +94,7 @@ function semanticImpactRecord(input) {
|
|
|
93
94
|
risk,
|
|
94
95
|
confidence: semanticImpactConfidence(input.region, input.sourceMapMappings, input.sourcePreservationRecords)
|
|
95
96
|
};
|
|
97
|
+
return { ...record, mergeSignal: semanticImpactMergeSignal(record) };
|
|
96
98
|
}
|
|
97
99
|
|
|
98
100
|
function collectDependencyRelations(imports, dependencies) {
|
|
@@ -299,7 +301,8 @@ function summarizeSemanticImpactRecords(records) {
|
|
|
299
301
|
loweringRecords: uniqueStrings(records.flatMap((record) => record.loweringRecordIds)).length,
|
|
300
302
|
evidenceIds: uniqueStrings(records.flatMap((record) => record.evidenceIds)).length,
|
|
301
303
|
verificationPlans: uniqueStrings(verificationPlans),
|
|
302
|
-
requiredVerificationSteps: records.flatMap((record) => record.verificationPlan).filter((step) => step.required).length
|
|
304
|
+
requiredVerificationSteps: records.flatMap((record) => record.verificationPlan).filter((step) => step.required).length,
|
|
305
|
+
...summarizeSemanticImpactMergeSignals(records)
|
|
303
306
|
};
|
|
304
307
|
}
|
|
305
308
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { countBy, uniqueStrings } from './native-import-utils.js';
|
|
2
|
+
|
|
3
|
+
export function semanticImpactMergeSignal(record) {
|
|
4
|
+
const missing = semanticImpactMissingSignals(record);
|
|
5
|
+
const requiredSteps = (record.verificationPlan ?? []).filter((step) => step.required).length;
|
|
6
|
+
const blocked = record.readiness === 'blocked' || (record.failedProofObligationIds ?? []).length > 0;
|
|
7
|
+
const reviewRequired = blocked || record.readiness !== 'ready' || record.risk !== 'low' || requiredSteps > 0 || missing.length > 0;
|
|
8
|
+
const score = semanticImpactMergeScore(record, missing, requiredSteps, blocked);
|
|
9
|
+
const status = semanticImpactMergeStatus(record, score, blocked);
|
|
10
|
+
return {
|
|
11
|
+
status,
|
|
12
|
+
score,
|
|
13
|
+
missing,
|
|
14
|
+
reviewRequired,
|
|
15
|
+
queryKeys: semanticImpactMergeQueryKeys(record, status, missing, reviewRequired)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function summarizeSemanticImpactMergeSignals(records) {
|
|
20
|
+
const signals = (records ?? []).map((record) => record.mergeSignal).filter(Boolean);
|
|
21
|
+
return {
|
|
22
|
+
byMergeSignal: countBy(signals.map((signal) => signal.status)),
|
|
23
|
+
weakMergeSignals: signals.filter((signal) => signal.status === 'weak' || signal.status === 'blocked').length,
|
|
24
|
+
reviewRequiredMergeSignals: signals.filter((signal) => signal.reviewRequired).length,
|
|
25
|
+
mergeSignalQueryKeys: uniqueStrings(signals.flatMap((signal) => signal.queryKeys)),
|
|
26
|
+
mergeSignalScores: semanticImpactMergeScoreSummary(signals)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function semanticImpactMissingSignals(record) {
|
|
31
|
+
const missing = [];
|
|
32
|
+
if ((record.evidenceIds ?? []).length === 0) missing.push('evidence');
|
|
33
|
+
if ((record.sourceMapMappingIds ?? []).length === 0) missing.push('source-map');
|
|
34
|
+
if ((record.sourcePreservationRecordIds ?? []).length === 0) missing.push('source-preservation');
|
|
35
|
+
if (record.readiness !== 'ready' && (record.patchHintIds ?? []).length === 0) missing.push('patch-hint');
|
|
36
|
+
if ((record.openProofObligationIds ?? []).length > 0) missing.push('proof-obligations');
|
|
37
|
+
if (record.confidence === 'estimated-source-region' || record.confidence === 'review-required') missing.push('source-confidence');
|
|
38
|
+
return uniqueStrings(missing);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function semanticImpactMergeScore(record, missing, requiredSteps, blocked) {
|
|
42
|
+
let score = 100;
|
|
43
|
+
if (blocked) score -= 70;
|
|
44
|
+
else if (record.risk === 'high') score -= 35;
|
|
45
|
+
else if (record.risk === 'medium') score -= 18;
|
|
46
|
+
if (record.readiness === 'blocked') score -= 30;
|
|
47
|
+
else if (record.readiness === 'needs-review') score -= 18;
|
|
48
|
+
else if (record.readiness === 'ready-with-losses') score -= 8;
|
|
49
|
+
score -= Math.min(requiredSteps * 8, 32);
|
|
50
|
+
score -= Math.min(missing.length * 7, 35);
|
|
51
|
+
if ((record.failedProofObligationIds ?? []).length > 0) score -= 30;
|
|
52
|
+
if ((record.openProofObligationIds ?? []).length > 0) score -= 12;
|
|
53
|
+
if (record.confidence === 'source-exact') score += 5;
|
|
54
|
+
return Math.max(0, Math.min(100, Math.round(score)));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function semanticImpactMergeStatus(record, score, blocked) {
|
|
58
|
+
if (blocked || score < 25) return 'blocked';
|
|
59
|
+
if (score < 50 || record.risk === 'high') return 'weak';
|
|
60
|
+
if (score < 80 || record.risk === 'medium' || record.readiness !== 'ready') return 'partial';
|
|
61
|
+
return 'strong';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function semanticImpactMergeQueryKeys(record, status, missing, reviewRequired) {
|
|
65
|
+
return uniqueStrings([
|
|
66
|
+
`merge-signal:${status}`,
|
|
67
|
+
`risk:${record.risk ?? 'unknown'}`,
|
|
68
|
+
`readiness:${record.readiness ?? 'unknown'}`,
|
|
69
|
+
reviewRequired ? 'review-required' : 'review-not-required',
|
|
70
|
+
...missing.map((item) => `missing:${item}`),
|
|
71
|
+
record.sourcePath ? `source:${record.sourcePath}` : undefined,
|
|
72
|
+
record.ownershipKey ? `ownership:${record.ownershipKey}` : undefined,
|
|
73
|
+
...(record.symbolNames ?? []).map((name) => `symbol-name:${name}`),
|
|
74
|
+
...(record.dependencyPredicates ?? []).map((predicate) => `predicate:${predicate}`)
|
|
75
|
+
].filter(Boolean));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function semanticImpactMergeScoreSummary(signals) {
|
|
79
|
+
if (!signals.length) return { min: 0, max: 0, average: 0 };
|
|
80
|
+
const scores = signals.map((signal) => signal.score);
|
|
81
|
+
return {
|
|
82
|
+
min: Math.min(...scores),
|
|
83
|
+
max: Math.max(...scores),
|
|
84
|
+
average: Math.round(scores.reduce((sum, score) => sum + score, 0) / scores.length)
|
|
85
|
+
};
|
|
86
|
+
}
|
package/package.json
CHANGED