@saptools/service-flow 0.1.53 → 0.1.55
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/CHANGELOG.md +11 -0
- package/README.md +12 -5
- package/TECHNICAL-NOTE.md +13 -0
- package/dist/{chunk-LFH7C46B.js → chunk-GXYVIHJ5.js} +635 -135
- package/dist/chunk-GXYVIHJ5.js.map +1 -0
- package/dist/cli.js +71 -26
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/cli/001-doctor-projection.ts +3 -7
- package/src/cli.ts +24 -16
- package/src/linker/000-implementation-candidates.ts +35 -2
- package/src/linker/001-implementation-evidence-projection.ts +78 -6
- package/src/output/000-stdout-policy.ts +65 -0
- package/src/output/table-output.ts +11 -2
- package/src/parsers/outbound-call-parser.ts +116 -11
- package/src/trace/008-contextual-runtime-state.ts +294 -0
- package/src/trace/009-selected-handler-provenance.ts +186 -0
- package/src/trace/evidence.ts +103 -31
- package/src/trace/trace-engine.ts +67 -82
- package/src/utils/000-bounded-projection.ts +20 -15
- package/dist/chunk-LFH7C46B.js.map +0 -1
|
@@ -13,6 +13,16 @@ function projectBounded(values, compare, limit = DEFAULT_EVIDENCE_CANDIDATE_LIMI
|
|
|
13
13
|
items
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
function projectBoundedInOrder(values, limit = DEFAULT_EVIDENCE_CANDIDATE_LIMIT) {
|
|
17
|
+
const normalizedLimit = positiveLimit(limit);
|
|
18
|
+
const items = values.slice(0, normalizedLimit);
|
|
19
|
+
return {
|
|
20
|
+
totalCount: values.length,
|
|
21
|
+
shownCount: items.length,
|
|
22
|
+
omittedCount: Math.max(0, values.length - items.length),
|
|
23
|
+
items
|
|
24
|
+
};
|
|
25
|
+
}
|
|
16
26
|
function positiveLimit(value) {
|
|
17
27
|
return Number.isFinite(value) && Number(value) > 0 ? Math.floor(Number(value)) : DEFAULT_EVIDENCE_CANDIDATE_LIMIT;
|
|
18
28
|
}
|
|
@@ -51,7 +61,7 @@ function boundCandidateLikeEvidence(evidence, limit = DEFAULT_EVIDENCE_CANDIDATE
|
|
|
51
61
|
output[key] = boundNestedEvidence(value, limit);
|
|
52
62
|
continue;
|
|
53
63
|
}
|
|
54
|
-
const projection =
|
|
64
|
+
const projection = projectBoundedInOrder(value, limit);
|
|
55
65
|
output[key] = projection.items.map((item) => boundNestedEvidence(item, limit));
|
|
56
66
|
addCollectionCounts(output, evidence, key, projection);
|
|
57
67
|
}
|
|
@@ -106,17 +116,6 @@ function collectionStem(key) {
|
|
|
106
116
|
};
|
|
107
117
|
return stems[key] ?? "candidate";
|
|
108
118
|
}
|
|
109
|
-
function compareEvidenceValue(left, right) {
|
|
110
|
-
return stableProjectionValue(left).localeCompare(stableProjectionValue(right));
|
|
111
|
-
}
|
|
112
|
-
function stableProjectionValue(value) {
|
|
113
|
-
if (Array.isArray(value))
|
|
114
|
-
return `[${value.map(stableProjectionValue).join(",")}]`;
|
|
115
|
-
if (isEvidenceRecord(value)) {
|
|
116
|
-
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableProjectionValue(value[key])}`).join(",")}}`;
|
|
117
|
-
}
|
|
118
|
-
return JSON.stringify(value) ?? "";
|
|
119
|
-
}
|
|
120
119
|
function numericValue(value) {
|
|
121
120
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
122
121
|
}
|
|
@@ -3046,19 +3045,105 @@ function variableInitializers(source) {
|
|
|
3046
3045
|
}
|
|
3047
3046
|
return initializers;
|
|
3048
3047
|
}
|
|
3048
|
+
function unwrapQueryExpression(expr) {
|
|
3049
|
+
if (ts8.isParenthesizedExpression(expr) || ts8.isAwaitExpression(expr) || ts8.isAsExpression(expr) || ts8.isTypeAssertionExpression(expr) || ts8.isNonNullExpression(expr) || ts8.isSatisfiesExpression(expr))
|
|
3050
|
+
return unwrapQueryExpression(expr.expression);
|
|
3051
|
+
return expr;
|
|
3052
|
+
}
|
|
3049
3053
|
function queryEntityFromAst(expr, initializers = /* @__PURE__ */ new Map()) {
|
|
3050
|
-
|
|
3051
|
-
if (ts8.isIdentifier(
|
|
3052
|
-
if (ts8.isCallExpression(
|
|
3053
|
-
const name = expressionName(
|
|
3054
|
-
if (name === "cds.run") return queryEntityFromAst(
|
|
3055
|
-
if (
|
|
3056
|
-
|
|
3057
|
-
const receiver = ts8.isPropertyAccessExpression(expr.expression) ? expr.expression.expression : void 0;
|
|
3054
|
+
const unwrapped = unwrapQueryExpression(expr);
|
|
3055
|
+
if (ts8.isIdentifier(unwrapped) && initializers.has(unwrapped.text)) return queryEntityFromAst(initializers.get(unwrapped.text), initializers);
|
|
3056
|
+
if (ts8.isCallExpression(unwrapped)) {
|
|
3057
|
+
const name = expressionName(unwrapped.expression);
|
|
3058
|
+
if (name === "cds.run") return queryEntityFromAst(unwrapped.arguments[0], initializers);
|
|
3059
|
+
if (capQueryBuilderRoots.has(name)) return entityFromExpression(unwrapped.arguments[0]);
|
|
3060
|
+
const receiver = ts8.isPropertyAccessExpression(unwrapped.expression) ? unwrapped.expression.expression : void 0;
|
|
3058
3061
|
if (receiver) return queryEntityFromAst(receiver, initializers);
|
|
3059
3062
|
}
|
|
3060
3063
|
return void 0;
|
|
3061
3064
|
}
|
|
3065
|
+
var capQueryBuilderRoots = /* @__PURE__ */ new Set([
|
|
3066
|
+
"SELECT.from",
|
|
3067
|
+
"SELECT.one.from",
|
|
3068
|
+
"SELECT.one",
|
|
3069
|
+
"INSERT.into",
|
|
3070
|
+
"UPSERT.into",
|
|
3071
|
+
"UPDATE.entity",
|
|
3072
|
+
"UPDATE",
|
|
3073
|
+
"DELETE.from"
|
|
3074
|
+
]);
|
|
3075
|
+
function wrapperParent(node) {
|
|
3076
|
+
const parent = node.parent;
|
|
3077
|
+
if ((ts8.isParenthesizedExpression(parent) || ts8.isAsExpression(parent) || ts8.isTypeAssertionExpression(parent) || ts8.isNonNullExpression(parent) || ts8.isSatisfiesExpression(parent)) && parent.expression === node)
|
|
3078
|
+
return parent;
|
|
3079
|
+
return void 0;
|
|
3080
|
+
}
|
|
3081
|
+
function fluentCallParent(node) {
|
|
3082
|
+
const property = node.parent;
|
|
3083
|
+
if (!ts8.isPropertyAccessExpression(property) || property.expression !== node) return void 0;
|
|
3084
|
+
const call = property.parent;
|
|
3085
|
+
return ts8.isCallExpression(call) && call.expression === property ? call : void 0;
|
|
3086
|
+
}
|
|
3087
|
+
function queryBuilderRoot(expr) {
|
|
3088
|
+
const unwrapped = unwrapQueryExpression(expr);
|
|
3089
|
+
if (!ts8.isCallExpression(unwrapped)) return void 0;
|
|
3090
|
+
if (capQueryBuilderRoots.has(expressionName(unwrapped.expression))) return unwrapped;
|
|
3091
|
+
return ts8.isPropertyAccessExpression(unwrapped.expression) ? queryBuilderRoot(unwrapped.expression.expression) : void 0;
|
|
3092
|
+
}
|
|
3093
|
+
function outerFluentQueryCall(root) {
|
|
3094
|
+
let current = root;
|
|
3095
|
+
let outer = root;
|
|
3096
|
+
while (true) {
|
|
3097
|
+
const wrapper = wrapperParent(current);
|
|
3098
|
+
if (wrapper) {
|
|
3099
|
+
current = wrapper;
|
|
3100
|
+
continue;
|
|
3101
|
+
}
|
|
3102
|
+
const next = fluentCallParent(current);
|
|
3103
|
+
if (!next) return outer;
|
|
3104
|
+
outer = next;
|
|
3105
|
+
current = next;
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
function directQueryBuilderStatement(node) {
|
|
3109
|
+
const root = queryBuilderRoot(node);
|
|
3110
|
+
if (!root) return void 0;
|
|
3111
|
+
const logicalCall = outerFluentQueryCall(root);
|
|
3112
|
+
if (logicalCall !== node) return void 0;
|
|
3113
|
+
let current = logicalCall;
|
|
3114
|
+
while (true) {
|
|
3115
|
+
const wrapper = wrapperParent(current);
|
|
3116
|
+
if (wrapper) {
|
|
3117
|
+
current = wrapper;
|
|
3118
|
+
continue;
|
|
3119
|
+
}
|
|
3120
|
+
const parent = current.parent;
|
|
3121
|
+
return ts8.isAwaitExpression(parent) && parent.expression === current ? { root, logicalCall, awaitExpression: parent } : void 0;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
function queryBuilderEvidence(source, statement) {
|
|
3125
|
+
return {
|
|
3126
|
+
classifier: "cap_query_builder_direct",
|
|
3127
|
+
queryDispatch: "direct_query_builder",
|
|
3128
|
+
queryRoot: expressionName(statement.root.expression),
|
|
3129
|
+
queryRootStartOffset: statement.root.getStart(source),
|
|
3130
|
+
queryRootEndOffset: statement.root.getEnd(),
|
|
3131
|
+
queryStatementStartOffset: statement.awaitExpression.getStart(source),
|
|
3132
|
+
queryStatementEndOffset: statement.awaitExpression.getEnd()
|
|
3133
|
+
};
|
|
3134
|
+
}
|
|
3135
|
+
function queryRunEvidence(source, argument) {
|
|
3136
|
+
const root = argument ? queryBuilderRoot(argument) : void 0;
|
|
3137
|
+
return {
|
|
3138
|
+
classifier: "cap_query_run_wrapper",
|
|
3139
|
+
queryDispatch: "cds_run_wrapper",
|
|
3140
|
+
...root ? {
|
|
3141
|
+
queryRoot: expressionName(root.expression),
|
|
3142
|
+
queryRootStartOffset: root.getStart(source),
|
|
3143
|
+
queryRootEndOffset: root.getEnd()
|
|
3144
|
+
} : {}
|
|
3145
|
+
};
|
|
3146
|
+
}
|
|
3062
3147
|
function extractQueryEntity(expr) {
|
|
3063
3148
|
const source = ts8.createSourceFile("query.ts", `const __query = (${expr});`, ts8.ScriptTarget.Latest, true, ts8.ScriptKind.TS);
|
|
3064
3149
|
const initializers = variableInitializers(source);
|
|
@@ -3411,11 +3496,16 @@ function classifyOutboundCallsInSource(source, filePath) {
|
|
|
3411
3496
|
}
|
|
3412
3497
|
const expr = node.expression;
|
|
3413
3498
|
const exprText = expr.getText(source);
|
|
3499
|
+
const directQuery = directQueryBuilderStatement(node);
|
|
3414
3500
|
if (exprText === "cds.run") {
|
|
3415
3501
|
const arg = node.arguments[0];
|
|
3416
3502
|
const entity = arg ? queryEntityFromAst(arg, initializers) : void 0;
|
|
3417
3503
|
const payload = arg?.getText(source) ?? "";
|
|
3418
|
-
add(node, { callType: "local_db_query", queryEntity: entity, payloadSummary: summarizeExpression(payload), confidence: entity ? 0.9 : 0.55, unresolvedReason: entity ? void 0 : queryWarning(payload) });
|
|
3504
|
+
add(node, { callType: "local_db_query", queryEntity: entity, payloadSummary: summarizeExpression(payload), confidence: entity ? 0.9 : 0.55, unresolvedReason: entity ? void 0 : queryWarning(payload) }, queryRunEvidence(source, arg));
|
|
3505
|
+
} else if (directQuery) {
|
|
3506
|
+
const entity = queryEntityFromAst(directQuery.logicalCall, initializers);
|
|
3507
|
+
const payload = directQuery.logicalCall.getText(source);
|
|
3508
|
+
add(directQuery.logicalCall, { callType: "local_db_query", queryEntity: entity, payloadSummary: summarizeExpression(payload), confidence: entity ? 0.9 : 0.55, unresolvedReason: entity ? void 0 : queryWarning(payload) }, queryBuilderEvidence(source, directQuery));
|
|
3419
3509
|
} else if (ts8.isPropertyAccessExpression(expr) && expr.name.text === "send" && (ts8.isIdentifier(expr.expression) || ts8.isPropertyAccessExpression(expr.expression))) {
|
|
3420
3510
|
const objectArg = node.arguments[0];
|
|
3421
3511
|
if (objectArg && ts8.isObjectLiteralExpression(objectArg)) {
|
|
@@ -3931,9 +4021,41 @@ function buildRemoteQueryTarget(input) {
|
|
|
3931
4021
|
}
|
|
3932
4022
|
|
|
3933
4023
|
// src/linker/001-implementation-evidence-projection.ts
|
|
4024
|
+
function selectedHandlerProvenance(source) {
|
|
4025
|
+
return {
|
|
4026
|
+
status: "selected",
|
|
4027
|
+
accepted: true,
|
|
4028
|
+
graphTargetId: String(source.methodId),
|
|
4029
|
+
methodId: source.methodId,
|
|
4030
|
+
className: source.className,
|
|
4031
|
+
methodName: source.methodName,
|
|
4032
|
+
repository: {
|
|
4033
|
+
id: source.repositoryId,
|
|
4034
|
+
name: source.repositoryName,
|
|
4035
|
+
packageName: source.repositoryPackageName
|
|
4036
|
+
},
|
|
4037
|
+
sourceFile: source.sourceFile,
|
|
4038
|
+
sourceLine: source.sourceLine
|
|
4039
|
+
};
|
|
4040
|
+
}
|
|
4041
|
+
function displayImplementationCandidates(candidates2, selectedMethodId) {
|
|
4042
|
+
return [...candidates2].sort((left, right) => compareDisplayCandidate(
|
|
4043
|
+
left,
|
|
4044
|
+
right,
|
|
4045
|
+
selectedMethodId
|
|
4046
|
+
)).map((candidate, index) => ({
|
|
4047
|
+
...candidate,
|
|
4048
|
+
discoveryRank: candidate.rank,
|
|
4049
|
+
displayRank: index + 1,
|
|
4050
|
+
selected: selectedMethodId !== void 0 && Number(candidate.methodId) === selectedMethodId
|
|
4051
|
+
}));
|
|
4052
|
+
}
|
|
4053
|
+
function compareDisplayCandidate(left, right, selectedMethodId) {
|
|
4054
|
+
return Number(Number(right.methodId) === selectedMethodId) - Number(Number(left.methodId) === selectedMethodId) || Number(right.accepted === true) - Number(left.accepted === true) || numberValue(left.rank) - numberValue(right.rank) || compareTargetCandidates(left, right);
|
|
4055
|
+
}
|
|
3934
4056
|
function boundedImplementationEvidence(evidence, targetCandidateCount) {
|
|
3935
4057
|
const candidates2 = recordArray(evidence.candidates);
|
|
3936
|
-
const candidateProjection =
|
|
4058
|
+
const candidateProjection = projectBoundedInOrder(candidates2);
|
|
3937
4059
|
const families = recordArray(evidence.candidateFamilies);
|
|
3938
4060
|
const familyProjection = projectBounded(families, compareFamilies);
|
|
3939
4061
|
const hints = recordArray(evidence.implementationHintSuggestions);
|
|
@@ -3996,9 +4118,6 @@ function boundedFamilyEvidence(family) {
|
|
|
3996
4118
|
function compareTargetCandidates(left, right) {
|
|
3997
4119
|
return Number(right.score ?? 0) - Number(left.score ?? 0) || String(left.className ?? "").localeCompare(String(right.className ?? "")) || Number(left.methodId ?? 0) - Number(right.methodId ?? 0);
|
|
3998
4120
|
}
|
|
3999
|
-
function compareCandidateEvidence(left, right) {
|
|
4000
|
-
return Number(left.rank ?? 0) - Number(right.rank ?? 0) || compareTargetCandidates(left, right);
|
|
4001
|
-
}
|
|
4002
4121
|
function compareFamilies(left, right) {
|
|
4003
4122
|
return String(left.packageName ?? "").localeCompare(String(right.packageName ?? "")) || String(left.reason ?? "").localeCompare(String(right.reason ?? ""));
|
|
4004
4123
|
}
|
|
@@ -4082,7 +4201,8 @@ function implementationDecision(db, workspaceId, operation, recordDiagnostics) {
|
|
|
4082
4201
|
implementationContext,
|
|
4083
4202
|
candidates2,
|
|
4084
4203
|
duplicateFamilies,
|
|
4085
|
-
ambiguityReasons
|
|
4204
|
+
ambiguityReasons,
|
|
4205
|
+
unique3
|
|
4086
4206
|
);
|
|
4087
4207
|
const hintProjection = implementationHintSuggestionProjection(evidence);
|
|
4088
4208
|
return {
|
|
@@ -4126,7 +4246,7 @@ function insertImplementationEdge(db, workspaceId, generation, operation, decisi
|
|
|
4126
4246
|
generation
|
|
4127
4247
|
);
|
|
4128
4248
|
}
|
|
4129
|
-
function implementationEvidence(operation, context, candidates2, duplicateFamilies, ambiguityReasons) {
|
|
4249
|
+
function implementationEvidence(operation, context, candidates2, duplicateFamilies, ambiguityReasons, selected) {
|
|
4130
4250
|
return {
|
|
4131
4251
|
servicePath: operation.servicePath,
|
|
4132
4252
|
operationPath: operation.operationPath,
|
|
@@ -4141,7 +4261,11 @@ function implementationEvidence(operation, context, candidates2, duplicateFamili
|
|
|
4141
4261
|
implementationOperationId: context.operationId,
|
|
4142
4262
|
ambiguityReasons,
|
|
4143
4263
|
candidateFamilies: duplicateFamilies,
|
|
4144
|
-
|
|
4264
|
+
selectedHandler: selected ? selectedHandlerProvenance(selectedHandlerSource(selected)) : void 0,
|
|
4265
|
+
candidates: displayImplementationCandidates(
|
|
4266
|
+
candidates2.map((candidate, index) => candidateEvidence(candidate, index + 1)),
|
|
4267
|
+
selected?.methodId
|
|
4268
|
+
)
|
|
4145
4269
|
};
|
|
4146
4270
|
}
|
|
4147
4271
|
function implementationContextForOperation(db, operation) {
|
|
@@ -4271,7 +4395,7 @@ function implementationCandidates(db, workspaceId, operation) {
|
|
|
4271
4395
|
hm.id methodId,hm.method_name methodName,hm.decorator_value decoratorValue,
|
|
4272
4396
|
hm.decorator_raw_expression decoratorRawExpression,
|
|
4273
4397
|
hm.decorator_resolution_json decoratorResolutionJson,hc.id classId,
|
|
4274
|
-
hc.class_name className,hc.source_file sourceFile,
|
|
4398
|
+
hc.class_name className,hc.source_file sourceFile,hm.source_line sourceLine,
|
|
4275
4399
|
hr.id registrationId,hr.handler_class_id registrationHandlerClassId,
|
|
4276
4400
|
hr.class_name registrationClassName,hr.repo_id applicationRepoId,
|
|
4277
4401
|
hr.registration_file registrationFile,hr.registration_line registrationLine,
|
|
@@ -4440,6 +4564,7 @@ function ownershipScore(signals, acceptedReasons) {
|
|
|
4440
4564
|
function candidateEvidence(candidate, rank) {
|
|
4441
4565
|
return {
|
|
4442
4566
|
rank,
|
|
4567
|
+
rankKind: "discovery_score",
|
|
4443
4568
|
score: candidate.score,
|
|
4444
4569
|
accepted: candidate.accepted,
|
|
4445
4570
|
acceptedReasons: candidate.acceptedReasons,
|
|
@@ -4492,6 +4617,18 @@ function candidateEvidence(candidate, rank) {
|
|
|
4492
4617
|
}
|
|
4493
4618
|
};
|
|
4494
4619
|
}
|
|
4620
|
+
function selectedHandlerSource(candidate) {
|
|
4621
|
+
return {
|
|
4622
|
+
methodId: candidate.methodId,
|
|
4623
|
+
className: stringValue4(candidate.className),
|
|
4624
|
+
methodName: stringValue4(candidate.methodName),
|
|
4625
|
+
repositoryId: numberValue2(candidate.handlerRepoId),
|
|
4626
|
+
repositoryName: stringValue4(candidate.handlerRepo),
|
|
4627
|
+
repositoryPackageName: stringValue4(candidate.handlerPackage),
|
|
4628
|
+
sourceFile: stringValue4(candidate.sourceFile),
|
|
4629
|
+
sourceLine: numberValue2(candidate.sourceLine)
|
|
4630
|
+
};
|
|
4631
|
+
}
|
|
4495
4632
|
function implementationMethodSignal(row, operation) {
|
|
4496
4633
|
const resolution = objectJson(row.decoratorResolutionJson) ?? {};
|
|
4497
4634
|
if (resolution.handlerKind && resolution.handlerKind !== "operation")
|
|
@@ -6550,9 +6687,198 @@ function isConcrete(value) {
|
|
|
6550
6687
|
return typeof value === "string" && value.length > 0 && extractPlaceholders(value).length === 0;
|
|
6551
6688
|
}
|
|
6552
6689
|
|
|
6690
|
+
// src/trace/006-contextual-projection.ts
|
|
6691
|
+
function boundedContextCandidates(values) {
|
|
6692
|
+
const candidates2 = values.flatMap((value) => {
|
|
6693
|
+
return isRecord5(value) ? [value] : [];
|
|
6694
|
+
});
|
|
6695
|
+
const projection = projectBounded(candidates2, (left, right) => Number(right.score ?? 0) - Number(left.score ?? 0) || String(left.repoName ?? "").localeCompare(String(right.repoName ?? "")) || String(left.servicePath ?? "").localeCompare(String(right.servicePath ?? "")) || String(left.sourceFile ?? "").localeCompare(String(right.sourceFile ?? "")) || Number(left.sourceLine ?? 0) - Number(right.sourceLine ?? 0) || Number(left.bindingId ?? left.operationId ?? 0) - Number(right.bindingId ?? right.operationId ?? 0));
|
|
6696
|
+
return {
|
|
6697
|
+
candidates: projection.items,
|
|
6698
|
+
candidateCount: projection.totalCount,
|
|
6699
|
+
shownCandidateCount: projection.shownCount,
|
|
6700
|
+
omittedCandidateCount: projection.omittedCount
|
|
6701
|
+
};
|
|
6702
|
+
}
|
|
6703
|
+
function isRecord5(value) {
|
|
6704
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
6705
|
+
}
|
|
6706
|
+
|
|
6707
|
+
// src/trace/008-contextual-runtime-state.ts
|
|
6708
|
+
function dynamicMissingReason(keys) {
|
|
6709
|
+
const missing = normalizedKeys(keys);
|
|
6710
|
+
return missing.length > 0 ? `Dynamic target is missing runtime variables: ${missing.join(", ")}` : "Dynamic target still requires runtime variables";
|
|
6711
|
+
}
|
|
6712
|
+
function isStructuralContextualBlocker(state) {
|
|
6713
|
+
return state?.category === "ambiguous_binding" || state?.category === "ambiguous_operation" || state?.category === "no_matching_operation" || state?.category === "other_blocker";
|
|
6714
|
+
}
|
|
6715
|
+
function contextualRuntimeResolution(db, call, binding, workspaceId, persistedRows = []) {
|
|
6716
|
+
if (!binding || call.call_type !== "remote_action" || call.operation_path_expr === void 0 || call.operation_path_expr === null)
|
|
6717
|
+
return { state: { category: "none" } };
|
|
6718
|
+
if (binding.resolutionStatus === "ambiguous")
|
|
6719
|
+
return ambiguousBindingResolution(binding);
|
|
6720
|
+
return selectedBindingResolution(db, call, binding, workspaceId, persistedRows);
|
|
6721
|
+
}
|
|
6722
|
+
function ambiguousBindingResolution(binding) {
|
|
6723
|
+
const candidates2 = boundedContextCandidates(binding.bindingCandidates ?? []);
|
|
6724
|
+
const state = {
|
|
6725
|
+
category: "ambiguous_binding",
|
|
6726
|
+
message: "Ambiguous contextual service binding candidates",
|
|
6727
|
+
resolutionStatus: "ambiguous"
|
|
6728
|
+
};
|
|
6729
|
+
return {
|
|
6730
|
+
evidence: {
|
|
6731
|
+
contextualServiceBindingAttempted: true,
|
|
6732
|
+
contextualBinding: {
|
|
6733
|
+
source: binding.source,
|
|
6734
|
+
status: "tied",
|
|
6735
|
+
candidates: candidates2.candidates,
|
|
6736
|
+
candidateCount: candidates2.candidateCount,
|
|
6737
|
+
shownCandidateCount: candidates2.shownCandidateCount,
|
|
6738
|
+
omittedCandidateCount: candidates2.omittedCandidateCount
|
|
6739
|
+
},
|
|
6740
|
+
contextualResolutionStatus: "ambiguous",
|
|
6741
|
+
contextualCandidateCount: candidates2.candidateCount,
|
|
6742
|
+
contextualPreSubstitutionState: historicalState(state)
|
|
6743
|
+
},
|
|
6744
|
+
state
|
|
6745
|
+
};
|
|
6746
|
+
}
|
|
6747
|
+
function selectedBindingResolution(db, call, binding, workspaceId, persistedRows) {
|
|
6748
|
+
const normalized = normalizeODataOperationInvocationPath(
|
|
6749
|
+
String(call.operation_path_expr)
|
|
6750
|
+
);
|
|
6751
|
+
const operationPath = normalized?.normalizedOperationPath ?? withLeadingSlash(String(call.operation_path_expr));
|
|
6752
|
+
const servicePath = binding.effectiveServicePath ?? binding.servicePathExpr ?? binding.requireServicePath;
|
|
6753
|
+
const destination = binding.effectiveDestination ?? binding.destinationExpr ?? binding.requireDestination;
|
|
6754
|
+
const resolution = resolveOperation(db, {
|
|
6755
|
+
servicePath,
|
|
6756
|
+
operationPath,
|
|
6757
|
+
alias: binding.aliasExpr ?? binding.alias,
|
|
6758
|
+
destination,
|
|
6759
|
+
hasExplicitOverride: true,
|
|
6760
|
+
isDynamic: false
|
|
6761
|
+
}, workspaceId);
|
|
6762
|
+
const state = stateForResolution(resolution);
|
|
6763
|
+
const evidence = contextualEvidence(
|
|
6764
|
+
binding,
|
|
6765
|
+
normalized,
|
|
6766
|
+
operationPath,
|
|
6767
|
+
servicePath,
|
|
6768
|
+
destination,
|
|
6769
|
+
resolution,
|
|
6770
|
+
state
|
|
6771
|
+
);
|
|
6772
|
+
if (!resolution.target) return { evidence, state };
|
|
6773
|
+
const resolvedEvidence = {
|
|
6774
|
+
...evidence,
|
|
6775
|
+
contextualServiceBindingSelected: true,
|
|
6776
|
+
targetRepo: resolution.target.repoName,
|
|
6777
|
+
targetServicePath: resolution.target.servicePath,
|
|
6778
|
+
targetOperationPath: resolution.target.operationPath,
|
|
6779
|
+
targetOperation: resolution.target.operationName
|
|
6780
|
+
};
|
|
6781
|
+
if (persistedRows.some((row) => row.status === "resolved"))
|
|
6782
|
+
return { evidence: { ...resolvedEvidence, contextualPreservedPersistedResolvedEdge: true }, state };
|
|
6783
|
+
return {
|
|
6784
|
+
row: {
|
|
6785
|
+
id: -call.id,
|
|
6786
|
+
edge_type: "REMOTE_CALL_RESOLVES_TO_OPERATION",
|
|
6787
|
+
from_id: String(call.id),
|
|
6788
|
+
to_kind: "operation",
|
|
6789
|
+
to_id: String(resolution.target.operationId),
|
|
6790
|
+
confidence: resolution.target.score,
|
|
6791
|
+
evidence_json: JSON.stringify(resolvedEvidence),
|
|
6792
|
+
status: "resolved"
|
|
6793
|
+
},
|
|
6794
|
+
evidence: resolvedEvidence,
|
|
6795
|
+
state
|
|
6796
|
+
};
|
|
6797
|
+
}
|
|
6798
|
+
function contextualEvidence(binding, normalized, operationPath, servicePath, destination, resolution, state) {
|
|
6799
|
+
const candidates2 = boundedContextCandidates(resolution.candidates);
|
|
6800
|
+
return {
|
|
6801
|
+
contextualServiceBindingAttempted: true,
|
|
6802
|
+
contextualBinding: bindingEvidence2(binding),
|
|
6803
|
+
operationPath,
|
|
6804
|
+
rawOperationPath: normalized?.rawOperationPath,
|
|
6805
|
+
normalizedOperationPath: normalized?.wasInvocation ? normalized.normalizedOperationPath : void 0,
|
|
6806
|
+
invocationArgumentPlaceholderKeys: normalized?.invocationArgumentPlaceholderKeys.length ? normalized.invocationArgumentPlaceholderKeys : void 0,
|
|
6807
|
+
servicePath,
|
|
6808
|
+
serviceAlias: binding.alias,
|
|
6809
|
+
serviceAliasExpr: binding.aliasExpr,
|
|
6810
|
+
destination,
|
|
6811
|
+
requireServicePath: binding.requireServicePath,
|
|
6812
|
+
requireDestination: binding.requireDestination,
|
|
6813
|
+
effectiveServicePath: binding.effectiveServicePath,
|
|
6814
|
+
effectiveDestination: binding.effectiveDestination,
|
|
6815
|
+
contextualResolutionStatus: resolution.status,
|
|
6816
|
+
contextualCandidateCount: candidates2.candidateCount,
|
|
6817
|
+
shownContextualCandidateCount: candidates2.shownCandidateCount,
|
|
6818
|
+
omittedContextualCandidateCount: candidates2.omittedCandidateCount,
|
|
6819
|
+
candidates: candidates2.candidates,
|
|
6820
|
+
contextualResolutionReasons: resolution.reasons,
|
|
6821
|
+
resolutionReasons: resolution.reasons,
|
|
6822
|
+
contextualPreSubstitutionState: historicalState(state)
|
|
6823
|
+
};
|
|
6824
|
+
}
|
|
6825
|
+
function bindingEvidence2(binding) {
|
|
6826
|
+
return {
|
|
6827
|
+
source: binding.source,
|
|
6828
|
+
callerArgument: binding.callerArgument,
|
|
6829
|
+
callerProperty: binding.callerProperty,
|
|
6830
|
+
calleeParameter: binding.calleeParameter,
|
|
6831
|
+
calleeReceiver: binding.calleeReceiver,
|
|
6832
|
+
callerSite: binding.callerSite,
|
|
6833
|
+
calleeSite: binding.calleeSite,
|
|
6834
|
+
bindingSourceFile: binding.sourceFile,
|
|
6835
|
+
bindingSourceLine: binding.sourceLine,
|
|
6836
|
+
alias: binding.alias,
|
|
6837
|
+
aliasExpr: binding.aliasExpr,
|
|
6838
|
+
requireServicePath: binding.requireServicePath,
|
|
6839
|
+
requireDestination: binding.requireDestination,
|
|
6840
|
+
effectiveServicePath: binding.effectiveServicePath,
|
|
6841
|
+
effectiveDestination: binding.effectiveDestination
|
|
6842
|
+
};
|
|
6843
|
+
}
|
|
6844
|
+
function stateForResolution(resolution) {
|
|
6845
|
+
if (resolution.status === "resolved") return { category: "none" };
|
|
6846
|
+
if (resolution.status === "dynamic") {
|
|
6847
|
+
const missingVariables = missingVariableKeys(resolution.reasons);
|
|
6848
|
+
return {
|
|
6849
|
+
category: "dynamic_missing",
|
|
6850
|
+
message: dynamicMissingReason(missingVariables),
|
|
6851
|
+
missingVariables,
|
|
6852
|
+
resolutionStatus: resolution.status
|
|
6853
|
+
};
|
|
6854
|
+
}
|
|
6855
|
+
if (resolution.status === "ambiguous") return {
|
|
6856
|
+
category: "ambiguous_operation",
|
|
6857
|
+
message: "Ambiguous contextual operation candidates",
|
|
6858
|
+
resolutionStatus: resolution.status
|
|
6859
|
+
};
|
|
6860
|
+
return {
|
|
6861
|
+
category: resolution.status === "unresolved" ? "no_matching_operation" : "other_blocker",
|
|
6862
|
+
message: resolution.status === "unresolved" ? "No contextual operation candidate matched" : "Contextual operation resolution is blocked",
|
|
6863
|
+
resolutionStatus: resolution.status
|
|
6864
|
+
};
|
|
6865
|
+
}
|
|
6866
|
+
function historicalState(state) {
|
|
6867
|
+
return { ...state, phase: "before_runtime_substitution" };
|
|
6868
|
+
}
|
|
6869
|
+
function missingVariableKeys(reasons) {
|
|
6870
|
+
return normalizedKeys(reasons.flatMap((reason) => reason.startsWith("missing_variable:") ? [reason.slice("missing_variable:".length)] : []));
|
|
6871
|
+
}
|
|
6872
|
+
function normalizedKeys(keys) {
|
|
6873
|
+
return [...new Set(keys.filter((key) => key.length > 0))].sort();
|
|
6874
|
+
}
|
|
6875
|
+
function withLeadingSlash(value) {
|
|
6876
|
+
return value.startsWith("/") ? value : `/${value}`;
|
|
6877
|
+
}
|
|
6878
|
+
|
|
6553
6879
|
// src/trace/evidence.ts
|
|
6554
|
-
function baseTraceEvidence(row, call, persistedEvidence,
|
|
6555
|
-
const evidence = { ...persistedEvidence, ...
|
|
6880
|
+
function baseTraceEvidence(row, call, persistedEvidence, contextualEvidence2) {
|
|
6881
|
+
const evidence = { ...persistedEvidence, ...contextualEvidence2 ?? {} };
|
|
6556
6882
|
return {
|
|
6557
6883
|
...evidence,
|
|
6558
6884
|
graphEdgeId: row.id,
|
|
@@ -6566,11 +6892,11 @@ function baseTraceEvidence(row, call, persistedEvidence, contextualEvidence) {
|
|
|
6566
6892
|
file: call.source_file,
|
|
6567
6893
|
line: call.source_line,
|
|
6568
6894
|
persistedTarget: { kind: row.to_kind, id: row.to_id },
|
|
6569
|
-
contextualResolutionParticipated: Boolean(
|
|
6895
|
+
contextualResolutionParticipated: Boolean(contextualEvidence2?.contextualServiceBindingAttempted),
|
|
6570
6896
|
persistedResolution: persistedResolution(row)
|
|
6571
6897
|
};
|
|
6572
6898
|
}
|
|
6573
|
-
function runtimeResolution(db, row, evidence, options, workspaceId,
|
|
6899
|
+
function runtimeResolution(db, row, evidence, options, workspaceId, contextualState) {
|
|
6574
6900
|
const dynamicMode = options.dynamicMode ?? "strict";
|
|
6575
6901
|
const candidateCap = positiveCandidateCap(options.maxDynamicCandidates);
|
|
6576
6902
|
const boundedEvidence = boundCandidateLikeEvidence(evidence, candidateCap);
|
|
@@ -6578,7 +6904,7 @@ function runtimeResolution(db, row, evidence, options, workspaceId, contextualUn
|
|
|
6578
6904
|
return unchangedRuntimeResolution(
|
|
6579
6905
|
row,
|
|
6580
6906
|
boundDynamicEvidence(boundedEvidence, candidateCap),
|
|
6581
|
-
|
|
6907
|
+
contextualState
|
|
6582
6908
|
);
|
|
6583
6909
|
const substituted = evidenceWithRuntimeVariables(boundedEvidence, options.vars);
|
|
6584
6910
|
const analysis = analyzeDynamicTargetCandidates(
|
|
@@ -6592,50 +6918,98 @@ function runtimeResolution(db, row, evidence, options, workspaceId, contextualUn
|
|
|
6592
6918
|
analysis ? evidenceWithDynamicAnalysis(substituted, analysis) : substituted,
|
|
6593
6919
|
candidateCap
|
|
6594
6920
|
);
|
|
6921
|
+
const appliedRuntimeValues = hasApplicableRuntimeVariables(evidence, options.vars);
|
|
6922
|
+
const analyzed = analyzedRuntimeResolution(
|
|
6923
|
+
row,
|
|
6924
|
+
enriched,
|
|
6925
|
+
analysis,
|
|
6926
|
+
dynamicMode,
|
|
6927
|
+
appliedRuntimeValues,
|
|
6928
|
+
contextualState
|
|
6929
|
+
);
|
|
6930
|
+
if (analyzed) return analyzed;
|
|
6931
|
+
if (!appliedRuntimeValues) {
|
|
6932
|
+
const unresolvedReason = contextualReason(contextualState) ?? row.unresolved_reason;
|
|
6933
|
+
const withSections = withEffectiveResolution(
|
|
6934
|
+
enriched,
|
|
6935
|
+
row,
|
|
6936
|
+
unresolvedReason,
|
|
6937
|
+
void 0,
|
|
6938
|
+
contextualState
|
|
6939
|
+
);
|
|
6940
|
+
return { row, evidence: withSections, unresolvedReason };
|
|
6941
|
+
}
|
|
6942
|
+
return resolveSuppliedRuntimeOperation(db, row, enriched, workspaceId, contextualState);
|
|
6943
|
+
}
|
|
6944
|
+
function analyzedRuntimeResolution(row, evidence, analysis, dynamicMode, appliedRuntimeValues, contextualState) {
|
|
6595
6945
|
if (analysis && analysis.viableCandidateCount === 0 && Object.keys(analysis.appliedSuppliedVariables).length > 0)
|
|
6596
|
-
return noCandidateRuntimeResolution(row,
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6600
|
-
|
|
6601
|
-
|
|
6602
|
-
if (analysis && analysis.missingVariables.length > 0) {
|
|
6603
|
-
const unresolvedReason2 = contextualUnresolvedReason ?? row.unresolved_reason ?? "Dynamic target still requires runtime variables";
|
|
6946
|
+
return noCandidateRuntimeResolution(row, evidence, contextualState);
|
|
6947
|
+
const inferred = dynamicMode === "infer" ? inferredTarget(analysis) : void 0;
|
|
6948
|
+
if (inferred && !isStructuralContextualBlocker(contextualState))
|
|
6949
|
+
return resolvedRuntimeResolution(row, evidence, inferred, inferred.reasons);
|
|
6950
|
+
if (analysis && analysis.missingVariables.length > 0 && appliedRuntimeValues) {
|
|
6951
|
+
const unresolvedReason = dynamicMissingReason(analysis.missingVariables);
|
|
6604
6952
|
return {
|
|
6605
6953
|
row,
|
|
6606
|
-
evidence: withEffectiveResolution(
|
|
6607
|
-
|
|
6954
|
+
evidence: withEffectiveResolution(
|
|
6955
|
+
evidence,
|
|
6956
|
+
row,
|
|
6957
|
+
unresolvedReason,
|
|
6958
|
+
void 0,
|
|
6959
|
+
contextualState
|
|
6960
|
+
),
|
|
6961
|
+
unresolvedReason
|
|
6608
6962
|
};
|
|
6609
6963
|
}
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
}
|
|
6615
|
-
const resolution = resolveRuntimeOperation(db, enriched, workspaceId);
|
|
6964
|
+
return isStructuralContextualBlocker(contextualState) ? unchangedRuntimeResolution(row, evidence, contextualState) : void 0;
|
|
6965
|
+
}
|
|
6966
|
+
function resolveSuppliedRuntimeOperation(db, row, evidence, workspaceId, contextualState) {
|
|
6967
|
+
const resolution = resolveRuntimeOperation(db, evidence, workspaceId);
|
|
6616
6968
|
if (resolution.target)
|
|
6617
6969
|
return resolvedRuntimeResolution(
|
|
6618
6970
|
row,
|
|
6619
|
-
|
|
6971
|
+
evidence,
|
|
6620
6972
|
resolution.target,
|
|
6621
6973
|
resolution.reasons
|
|
6622
6974
|
);
|
|
6623
6975
|
const unresolvedReason = runtimeUnresolvedReason(resolution);
|
|
6624
|
-
return {
|
|
6976
|
+
return {
|
|
6977
|
+
row,
|
|
6978
|
+
evidence: withEffectiveResolution(
|
|
6979
|
+
evidence,
|
|
6980
|
+
row,
|
|
6981
|
+
unresolvedReason,
|
|
6982
|
+
resolution,
|
|
6983
|
+
contextualState
|
|
6984
|
+
),
|
|
6985
|
+
unresolvedReason
|
|
6986
|
+
};
|
|
6625
6987
|
}
|
|
6626
|
-
function unchangedRuntimeResolution(row, evidence,
|
|
6627
|
-
const unresolvedReason =
|
|
6988
|
+
function unchangedRuntimeResolution(row, evidence, contextualState) {
|
|
6989
|
+
const unresolvedReason = contextualReason(contextualState) ?? row.unresolved_reason;
|
|
6628
6990
|
return {
|
|
6629
6991
|
row,
|
|
6630
|
-
evidence: withEffectiveResolution(
|
|
6992
|
+
evidence: withEffectiveResolution(
|
|
6993
|
+
evidence,
|
|
6994
|
+
row,
|
|
6995
|
+
unresolvedReason,
|
|
6996
|
+
void 0,
|
|
6997
|
+
contextualState
|
|
6998
|
+
),
|
|
6631
6999
|
unresolvedReason
|
|
6632
7000
|
};
|
|
6633
7001
|
}
|
|
6634
|
-
function noCandidateRuntimeResolution(row, evidence) {
|
|
7002
|
+
function noCandidateRuntimeResolution(row, evidence, contextualState) {
|
|
6635
7003
|
const unresolvedReason = "No candidate remained after runtime substitution";
|
|
6636
7004
|
return {
|
|
6637
7005
|
row,
|
|
6638
|
-
evidence: withEffectiveResolution(
|
|
7006
|
+
evidence: withEffectiveResolution(
|
|
7007
|
+
evidence,
|
|
7008
|
+
row,
|
|
7009
|
+
unresolvedReason,
|
|
7010
|
+
void 0,
|
|
7011
|
+
contextualState
|
|
7012
|
+
),
|
|
6639
7013
|
unresolvedReason
|
|
6640
7014
|
};
|
|
6641
7015
|
}
|
|
@@ -6804,7 +7178,7 @@ function persistedResolution(row) {
|
|
|
6804
7178
|
edgeType: row.edge_type
|
|
6805
7179
|
};
|
|
6806
7180
|
}
|
|
6807
|
-
function effectiveResolution(row, evidence, unresolvedReason, resolution) {
|
|
7181
|
+
function effectiveResolution(row, evidence, unresolvedReason, resolution, contextualState) {
|
|
6808
7182
|
const target = resolution?.target;
|
|
6809
7183
|
return {
|
|
6810
7184
|
status: target ? "resolved" : row.status,
|
|
@@ -6817,14 +7191,34 @@ function effectiveResolution(row, evidence, unresolvedReason, resolution) {
|
|
|
6817
7191
|
confidence: target?.score ?? row.confidence,
|
|
6818
7192
|
reasons: resolution?.reasons ?? evidence.resolutionReasons,
|
|
6819
7193
|
unresolvedReason,
|
|
6820
|
-
edgeType: target ? "REMOTE_CALL_RESOLVES_TO_OPERATION" : row.edge_type
|
|
7194
|
+
edgeType: target ? "REMOTE_CALL_RESOLVES_TO_OPERATION" : row.edge_type,
|
|
7195
|
+
contextualBlocker: isStructuralContextualBlocker(contextualState) ? contextualState : void 0
|
|
6821
7196
|
};
|
|
6822
7197
|
}
|
|
6823
|
-
function withEffectiveResolution(evidence, row, unresolvedReason, resolution) {
|
|
6824
|
-
const current = effectiveResolution(
|
|
7198
|
+
function withEffectiveResolution(evidence, row, unresolvedReason, resolution, contextualState) {
|
|
7199
|
+
const current = effectiveResolution(
|
|
7200
|
+
row,
|
|
7201
|
+
evidence,
|
|
7202
|
+
unresolvedReason,
|
|
7203
|
+
resolution,
|
|
7204
|
+
contextualState
|
|
7205
|
+
);
|
|
6825
7206
|
const rest = { ...evidence };
|
|
6826
7207
|
delete rest.runtimeResolvedCandidate;
|
|
6827
|
-
return {
|
|
7208
|
+
return {
|
|
7209
|
+
...rest,
|
|
7210
|
+
effectiveResolution: current,
|
|
7211
|
+
linker: {
|
|
7212
|
+
status: current.status,
|
|
7213
|
+
confidence: current.confidence,
|
|
7214
|
+
reason: unresolvedReason,
|
|
7215
|
+
edgeType: current.edgeType,
|
|
7216
|
+
contextualBlocker: current.contextualBlocker
|
|
7217
|
+
}
|
|
7218
|
+
};
|
|
7219
|
+
}
|
|
7220
|
+
function contextualReason(state) {
|
|
7221
|
+
return state?.category === "none" ? void 0 : state?.message;
|
|
6828
7222
|
}
|
|
6829
7223
|
function resolveRuntimeOperation(db, evidence, workspaceId) {
|
|
6830
7224
|
const servicePath = stringValue10(evidence.servicePath);
|
|
@@ -7197,32 +7591,15 @@ function parsedEvidence(value) {
|
|
|
7197
7591
|
}
|
|
7198
7592
|
}
|
|
7199
7593
|
function record4(value) {
|
|
7200
|
-
return
|
|
7594
|
+
return isRecord6(value) ? value : {};
|
|
7201
7595
|
}
|
|
7202
|
-
function
|
|
7596
|
+
function isRecord6(value) {
|
|
7203
7597
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
7204
7598
|
}
|
|
7205
7599
|
function numberValue8(value) {
|
|
7206
7600
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
7207
7601
|
}
|
|
7208
7602
|
|
|
7209
|
-
// src/trace/006-contextual-projection.ts
|
|
7210
|
-
function boundedContextCandidates(values) {
|
|
7211
|
-
const candidates2 = values.flatMap((value) => {
|
|
7212
|
-
return isRecord6(value) ? [value] : [];
|
|
7213
|
-
});
|
|
7214
|
-
const projection = projectBounded(candidates2, (left, right) => Number(right.score ?? 0) - Number(left.score ?? 0) || String(left.repoName ?? "").localeCompare(String(right.repoName ?? "")) || String(left.servicePath ?? "").localeCompare(String(right.servicePath ?? "")) || String(left.sourceFile ?? "").localeCompare(String(right.sourceFile ?? "")) || Number(left.sourceLine ?? 0) - Number(right.sourceLine ?? 0) || Number(left.bindingId ?? left.operationId ?? 0) - Number(right.bindingId ?? right.operationId ?? 0));
|
|
7215
|
-
return {
|
|
7216
|
-
candidates: projection.items,
|
|
7217
|
-
candidateCount: projection.totalCount,
|
|
7218
|
-
shownCandidateCount: projection.shownCount,
|
|
7219
|
-
omittedCandidateCount: projection.omittedCount
|
|
7220
|
-
};
|
|
7221
|
-
}
|
|
7222
|
-
function isRecord6(value) {
|
|
7223
|
-
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
7224
|
-
}
|
|
7225
|
-
|
|
7226
7603
|
// src/trace/007-implementation-start-diagnostic.ts
|
|
7227
7604
|
function implementationStartDiagnostic(edge, evidence) {
|
|
7228
7605
|
return {
|
|
@@ -7262,6 +7639,137 @@ function isRecord7(value) {
|
|
|
7262
7639
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
7263
7640
|
}
|
|
7264
7641
|
|
|
7642
|
+
// src/trace/009-selected-handler-provenance.ts
|
|
7643
|
+
function handlerMethodNode(db, methodId) {
|
|
7644
|
+
const row = db.prepare(`SELECT hm.id methodId,hm.method_name methodName,
|
|
7645
|
+
hm.source_line sourceLine,hc.class_name className,hc.source_file sourceFile,
|
|
7646
|
+
r.name repoName,r.id repoId,r.package_name packageName
|
|
7647
|
+
FROM handler_methods hm JOIN handler_classes hc ON hc.id=hm.handler_class_id
|
|
7648
|
+
JOIN repositories r ON r.id=hc.repo_id WHERE hm.id=?`).get(methodId);
|
|
7649
|
+
return handlerNodeFromRow(row);
|
|
7650
|
+
}
|
|
7651
|
+
function withSelectedHandlerProvenance(evidence, targetId, handler) {
|
|
7652
|
+
if (!handler) return unavailableHandlerEvidence(evidence, targetId);
|
|
7653
|
+
const selected = selectedHandlerProvenance(handlerSource(handler));
|
|
7654
|
+
const stored = record5(evidence.selectedHandler);
|
|
7655
|
+
const mismatchedFields = storedSelectedHandlerMismatches(
|
|
7656
|
+
stored,
|
|
7657
|
+
selected,
|
|
7658
|
+
targetId
|
|
7659
|
+
);
|
|
7660
|
+
if (mismatchedFields.length === 0)
|
|
7661
|
+
return { handler, evidence: { ...evidence, selectedHandler: selected } };
|
|
7662
|
+
return {
|
|
7663
|
+
handler,
|
|
7664
|
+
evidence: {
|
|
7665
|
+
...evidence,
|
|
7666
|
+
selectedHandler: selected,
|
|
7667
|
+
selectedHandlerProvenanceAudit: {
|
|
7668
|
+
status: "mismatch",
|
|
7669
|
+
graphTargetId: targetId,
|
|
7670
|
+
mismatchedFields,
|
|
7671
|
+
persistedSelectedHandler: stored
|
|
7672
|
+
}
|
|
7673
|
+
},
|
|
7674
|
+
diagnostic: {
|
|
7675
|
+
severity: "warning",
|
|
7676
|
+
code: "selected_handler_provenance_mismatch",
|
|
7677
|
+
message: "Persisted selected handler provenance did not match the resolved graph target",
|
|
7678
|
+
graphTargetId: targetId,
|
|
7679
|
+
mismatchedFields,
|
|
7680
|
+
sourceFile: handler.sourceFile,
|
|
7681
|
+
sourceLine: handler.sourceLine
|
|
7682
|
+
}
|
|
7683
|
+
};
|
|
7684
|
+
}
|
|
7685
|
+
function unavailableHandlerEvidence(evidence, targetId) {
|
|
7686
|
+
return {
|
|
7687
|
+
evidence: {
|
|
7688
|
+
...evidence,
|
|
7689
|
+
selectedHandlerProvenanceAudit: {
|
|
7690
|
+
status: "unavailable",
|
|
7691
|
+
graphTargetId: targetId,
|
|
7692
|
+
reason: "handler_target_not_indexed"
|
|
7693
|
+
}
|
|
7694
|
+
},
|
|
7695
|
+
diagnostic: {
|
|
7696
|
+
severity: "warning",
|
|
7697
|
+
code: "selected_handler_target_not_found",
|
|
7698
|
+
message: "Resolved implementation target is not an indexed handler method",
|
|
7699
|
+
graphTargetId: targetId
|
|
7700
|
+
},
|
|
7701
|
+
unresolvedReason: "Resolved implementation target is not an indexed handler method"
|
|
7702
|
+
};
|
|
7703
|
+
}
|
|
7704
|
+
function handlerNodeFromRow(row) {
|
|
7705
|
+
const methodId = numberValue9(row?.methodId);
|
|
7706
|
+
const methodName2 = stringValue12(row?.methodName);
|
|
7707
|
+
const className = stringValue12(row?.className);
|
|
7708
|
+
const sourceFile = stringValue12(row?.sourceFile);
|
|
7709
|
+
const sourceLine2 = numberValue9(row?.sourceLine);
|
|
7710
|
+
const repoId = numberValue9(row?.repoId);
|
|
7711
|
+
const repoName = stringValue12(row?.repoName);
|
|
7712
|
+
if (methodId === void 0 || !methodName2 || !className || !sourceFile || sourceLine2 === void 0 || repoId === void 0 || !repoName)
|
|
7713
|
+
return void 0;
|
|
7714
|
+
return {
|
|
7715
|
+
id: `handler_method:${methodId}`,
|
|
7716
|
+
kind: "handler_method",
|
|
7717
|
+
label: `${repoName}:${className}.${methodName2}`,
|
|
7718
|
+
methodId,
|
|
7719
|
+
methodName: methodName2,
|
|
7720
|
+
className,
|
|
7721
|
+
sourceFile,
|
|
7722
|
+
sourceLine: sourceLine2,
|
|
7723
|
+
repoId,
|
|
7724
|
+
repoName,
|
|
7725
|
+
packageName: stringValue12(row?.packageName)
|
|
7726
|
+
};
|
|
7727
|
+
}
|
|
7728
|
+
function handlerSource(node) {
|
|
7729
|
+
return {
|
|
7730
|
+
methodId: node.methodId,
|
|
7731
|
+
methodName: node.methodName,
|
|
7732
|
+
className: node.className,
|
|
7733
|
+
repositoryId: node.repoId,
|
|
7734
|
+
repositoryName: node.repoName,
|
|
7735
|
+
repositoryPackageName: node.packageName,
|
|
7736
|
+
sourceFile: node.sourceFile,
|
|
7737
|
+
sourceLine: node.sourceLine
|
|
7738
|
+
};
|
|
7739
|
+
}
|
|
7740
|
+
function storedSelectedHandlerMismatches(stored, selected, targetId) {
|
|
7741
|
+
if (Object.keys(stored).length === 0) return [];
|
|
7742
|
+
const expectedRepository = record5(stored.repository);
|
|
7743
|
+
const selectedRepository = selected.repository ?? {};
|
|
7744
|
+
return [
|
|
7745
|
+
mismatch("graphTargetId", stored.graphTargetId, targetId),
|
|
7746
|
+
mismatch("methodId", stored.methodId, selected.methodId),
|
|
7747
|
+
mismatch("className", stored.className, selected.className),
|
|
7748
|
+
mismatch("methodName", stored.methodName, selected.methodName),
|
|
7749
|
+
mismatch("sourceFile", stored.sourceFile, selected.sourceFile),
|
|
7750
|
+
mismatch("sourceLine", stored.sourceLine, selected.sourceLine),
|
|
7751
|
+
mismatch("repository.id", expectedRepository.id, selectedRepository.id),
|
|
7752
|
+
mismatch("repository.name", expectedRepository.name, selectedRepository.name),
|
|
7753
|
+
mismatch(
|
|
7754
|
+
"repository.packageName",
|
|
7755
|
+
expectedRepository.packageName,
|
|
7756
|
+
selectedRepository.packageName
|
|
7757
|
+
)
|
|
7758
|
+
].flatMap((field) => field ? [field] : []);
|
|
7759
|
+
}
|
|
7760
|
+
function mismatch(field, stored, actual) {
|
|
7761
|
+
return stored === void 0 || stored === actual ? void 0 : field;
|
|
7762
|
+
}
|
|
7763
|
+
function record5(value) {
|
|
7764
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
7765
|
+
}
|
|
7766
|
+
function stringValue12(value) {
|
|
7767
|
+
return typeof value === "string" ? value : void 0;
|
|
7768
|
+
}
|
|
7769
|
+
function numberValue9(value) {
|
|
7770
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
7771
|
+
}
|
|
7772
|
+
|
|
7265
7773
|
// src/trace/trace-engine.ts
|
|
7266
7774
|
function normalizeOperation2(value) {
|
|
7267
7775
|
if (!value) return void 0;
|
|
@@ -7381,11 +7889,6 @@ function handlerFilesForOperation(db, operationId) {
|
|
|
7381
7889
|
function implementationEdge(db, operationId) {
|
|
7382
7890
|
return db.prepare("SELECT * FROM graph_edges WHERE edge_type='OPERATION_IMPLEMENTED_BY_HANDLER' AND from_kind='operation' AND from_id=? ORDER BY CASE status WHEN 'resolved' THEN 0 WHEN 'ambiguous' THEN 1 ELSE 2 END,id LIMIT 1").get(operationId);
|
|
7383
7891
|
}
|
|
7384
|
-
function handlerMethodNode(db, methodId) {
|
|
7385
|
-
const row = db.prepare(`SELECT hm.id methodId,hm.method_name methodName,hm.decorator_value decoratorValue,hm.source_line sourceLine,hc.class_name className,hc.source_file sourceFile,r.name repoName,r.id repoId FROM handler_methods hm JOIN handler_classes hc ON hc.id=hm.handler_class_id JOIN repositories r ON r.id=hc.repo_id WHERE hm.id=?`).get(methodId);
|
|
7386
|
-
if (!row) return void 0;
|
|
7387
|
-
return { id: `handler_method:${methodId}`, kind: "handler_method", label: `${String(row.repoName)}:${String(row.className)}.${String(row.methodName)}`, ...row };
|
|
7388
|
-
}
|
|
7389
7892
|
function implementationScope(db, operationId) {
|
|
7390
7893
|
const edge = implementationEdge(db, operationId);
|
|
7391
7894
|
if (!edge || edge.status !== "resolved") return { files: /* @__PURE__ */ new Set(), edge };
|
|
@@ -7575,40 +8078,6 @@ function contextForSymbolCall(db, symbolCall, callerBindings) {
|
|
|
7575
8078
|
});
|
|
7576
8079
|
return next;
|
|
7577
8080
|
}
|
|
7578
|
-
function contextualRuntimeResolution(db, call, binding, workspaceId, persistedRows = []) {
|
|
7579
|
-
if (!binding || String(call.call_type) !== "remote_action" || call.operation_path_expr === void 0 || call.operation_path_expr === null) return {};
|
|
7580
|
-
if (binding.resolutionStatus === "ambiguous") {
|
|
7581
|
-
const candidates3 = boundedContextCandidates(binding.bindingCandidates ?? []);
|
|
7582
|
-
return {
|
|
7583
|
-
evidence: {
|
|
7584
|
-
contextualServiceBindingAttempted: true,
|
|
7585
|
-
contextualBinding: {
|
|
7586
|
-
source: binding.source,
|
|
7587
|
-
status: "tied",
|
|
7588
|
-
candidates: candidates3.candidates,
|
|
7589
|
-
candidateCount: candidates3.candidateCount,
|
|
7590
|
-
shownCandidateCount: candidates3.shownCandidateCount,
|
|
7591
|
-
omittedCandidateCount: candidates3.omittedCandidateCount
|
|
7592
|
-
},
|
|
7593
|
-
contextualResolutionStatus: "ambiguous",
|
|
7594
|
-
contextualCandidateCount: candidates3.candidateCount
|
|
7595
|
-
},
|
|
7596
|
-
unresolvedReason: "Ambiguous contextual service binding candidates"
|
|
7597
|
-
};
|
|
7598
|
-
}
|
|
7599
|
-
const normalized = normalizeODataOperationInvocationPath(String(call.operation_path_expr));
|
|
7600
|
-
const op = normalized?.normalizedOperationPath ?? (String(call.operation_path_expr).startsWith("/") ? String(call.operation_path_expr) : `/${String(call.operation_path_expr)}`);
|
|
7601
|
-
const servicePath = binding.effectiveServicePath ?? binding.servicePathExpr ?? binding.requireServicePath;
|
|
7602
|
-
const destination = binding.effectiveDestination ?? binding.destinationExpr ?? binding.requireDestination;
|
|
7603
|
-
const resolution = resolveOperation(db, { servicePath, operationPath: op, alias: binding.aliasExpr ?? binding.alias, destination, hasExplicitOverride: true, isDynamic: false }, workspaceId);
|
|
7604
|
-
const candidates2 = boundedContextCandidates(resolution.candidates);
|
|
7605
|
-
const evidence = { contextualServiceBindingAttempted: true, contextualBinding: { source: binding.source, callerArgument: binding.callerArgument, callerProperty: binding.callerProperty, calleeParameter: binding.calleeParameter, calleeReceiver: binding.calleeReceiver, callerSite: binding.callerSite, calleeSite: binding.calleeSite, bindingSourceFile: binding.sourceFile, bindingSourceLine: binding.sourceLine, alias: binding.alias, aliasExpr: binding.aliasExpr, requireServicePath: binding.requireServicePath, requireDestination: binding.requireDestination, effectiveServicePath: binding.effectiveServicePath, effectiveDestination: binding.effectiveDestination }, operationPath: op, rawOperationPath: normalized?.rawOperationPath, normalizedOperationPath: normalized?.wasInvocation ? normalized.normalizedOperationPath : void 0, invocationArgumentPlaceholderKeys: normalized?.invocationArgumentPlaceholderKeys.length ? normalized.invocationArgumentPlaceholderKeys : void 0, servicePath, serviceAlias: binding.alias, serviceAliasExpr: binding.aliasExpr, destination, requireServicePath: binding.requireServicePath, requireDestination: binding.requireDestination, effectiveServicePath: binding.effectiveServicePath, effectiveDestination: binding.effectiveDestination, contextualResolutionStatus: resolution.status, contextualCandidateCount: candidates2.candidateCount, shownContextualCandidateCount: candidates2.shownCandidateCount, omittedContextualCandidateCount: candidates2.omittedCandidateCount, candidates: candidates2.candidates, contextualResolutionReasons: resolution.reasons, resolutionReasons: resolution.reasons };
|
|
7606
|
-
if (!resolution.target) return { evidence, unresolvedReason: resolution.status === "ambiguous" ? "Ambiguous contextual operation candidates" : resolution.status === "dynamic" ? `Dynamic contextual target is missing runtime variables: ${resolution.reasons.join(", ")}` : "No contextual operation candidate matched" };
|
|
7607
|
-
const resolvedEvidence = { ...evidence, contextualServiceBindingSelected: true, targetRepo: resolution.target.repoName, targetServicePath: resolution.target.servicePath, targetOperationPath: resolution.target.operationPath, targetOperation: resolution.target.operationName };
|
|
7608
|
-
const persistedResolved = persistedRows.find((item) => item.status === "resolved");
|
|
7609
|
-
if (persistedResolved) return { row: void 0, evidence: { ...resolvedEvidence, contextualPreservedPersistedResolvedEdge: true }, unresolvedReason: void 0 };
|
|
7610
|
-
return { row: { id: -Number(call.id), edge_type: "REMOTE_CALL_RESOLVES_TO_OPERATION", from_id: String(call.id), to_kind: "operation", to_id: String(resolution.target.operationId), confidence: resolution.target.score, evidence_json: JSON.stringify(resolvedEvidence), status: "resolved" }, evidence: resolvedEvidence, unresolvedReason: void 0 };
|
|
7611
|
-
}
|
|
7612
8081
|
function trace(db, start, options) {
|
|
7613
8082
|
const hintOptions = { implementationRepo: options.implementationRepo, implementationHints: options.implementationHints };
|
|
7614
8083
|
const scope = startScope(db, start, hintOptions, options.workspaceId);
|
|
@@ -7644,11 +8113,26 @@ function trace(db, start, options) {
|
|
|
7644
8113
|
);
|
|
7645
8114
|
if (impl.edge && (impl.edge.status === "resolved" || startSelection.methodId)) {
|
|
7646
8115
|
const selectedMethodId = impl.edge.status === "resolved" ? impl.edge.to_id : startSelection.methodId;
|
|
7647
|
-
const implEvidence = {
|
|
7648
|
-
|
|
7649
|
-
|
|
8116
|
+
const implEvidence = {
|
|
8117
|
+
...parseEvidence(impl.edge.evidence_json),
|
|
8118
|
+
startResolution: {
|
|
8119
|
+
strategy: "indexed_operation_graph",
|
|
8120
|
+
matchedOperationId: scope.startOperationId,
|
|
8121
|
+
implementationEdgeId: impl.edge.id,
|
|
8122
|
+
implementationStatus: impl.edge.status,
|
|
8123
|
+
selectedHandlerMethodId: selectedMethodId
|
|
8124
|
+
},
|
|
8125
|
+
implementationSelection: startSelection.methodId ? startSelection.evidence : void 0
|
|
8126
|
+
};
|
|
8127
|
+
const selected = selectedMethodId ? withSelectedHandlerProvenance(
|
|
8128
|
+
implEvidence,
|
|
8129
|
+
selectedMethodId,
|
|
8130
|
+
handlerMethodNode(db, selectedMethodId)
|
|
8131
|
+
) : { evidence: implEvidence };
|
|
8132
|
+
if (selected.diagnostic) prependTraceDiagnostic(diagnostics, selected.diagnostic);
|
|
8133
|
+
if (selected.handler) nodes.set(String(selected.handler.id), selected.handler);
|
|
7650
8134
|
seenEdges.add(Number(impl.edge.id));
|
|
7651
|
-
edges.push({ step: 1, type: "operation_implemented_by_handler", from: op?.label ? String(op.label) : `operation:${scope.startOperationId}`, to:
|
|
8135
|
+
edges.push({ step: 1, type: "operation_implemented_by_handler", from: op?.label ? String(op.label) : `operation:${scope.startOperationId}`, to: selected.handler?.label ? String(selected.handler.label) : `${impl.edge.to_kind}:${impl.edge.to_id}`, evidence: selected.evidence, confidence: Number(impl.edge.confidence ?? 0), unresolvedReason: selected.unresolvedReason ?? (impl.edge.status === "resolved" || startSelection.methodId ? void 0 : String(impl.edge.unresolved_reason ?? impl.edge.status)) });
|
|
7652
8136
|
}
|
|
7653
8137
|
}
|
|
7654
8138
|
const seenScopes = /* @__PURE__ */ new Set();
|
|
@@ -7708,7 +8192,7 @@ function trace(db, start, options) {
|
|
|
7708
8192
|
vars: options.vars,
|
|
7709
8193
|
dynamicMode: options.dynamicMode ?? "strict",
|
|
7710
8194
|
maxDynamicCandidates: options.maxDynamicCandidates
|
|
7711
|
-
}, workspaceIdForCall(db, String(call.id)), contextual.
|
|
8195
|
+
}, workspaceIdForCall(db, String(call.id)), contextual.state);
|
|
7712
8196
|
const evidence = effective.evidence;
|
|
7713
8197
|
const effectiveRow = effective.row;
|
|
7714
8198
|
const targetNode = `${effectiveRow.to_kind}:${effectiveRow.to_id}`;
|
|
@@ -7741,29 +8225,46 @@ function trace(db, start, options) {
|
|
|
7741
8225
|
hintOptions
|
|
7742
8226
|
);
|
|
7743
8227
|
const contextMethodId = contextSelection.methodId;
|
|
7744
|
-
|
|
8228
|
+
let selectedHandlerAvailable = true;
|
|
7745
8229
|
if (implementation.edge) {
|
|
7746
8230
|
const implEvidence = parseEvidence(implementation.edge.evidence_json);
|
|
7747
8231
|
const hintDiagnostic = implementationHintDiagnostic(contextSelection, implEvidence);
|
|
7748
8232
|
if (hintDiagnostic) prependTraceDiagnostic(diagnostics, hintDiagnostic);
|
|
7749
|
-
const
|
|
7750
|
-
const
|
|
7751
|
-
|
|
8233
|
+
const selectedMethodId = implementation.edge.status === "resolved" ? implementation.edge.to_id : contextMethodId;
|
|
8234
|
+
const selectionEvidence = contextMethodId ? {
|
|
8235
|
+
...implEvidence,
|
|
8236
|
+
contextualImplementationSelected: contextSelection.evidence.strategy !== "implementation_repo_hint",
|
|
8237
|
+
contextualImplementation: contextSelection.evidence,
|
|
8238
|
+
implementationSelection: contextSelection.evidence
|
|
8239
|
+
} : {
|
|
8240
|
+
...implEvidence,
|
|
8241
|
+
contextualImplementation: contextSelection.evidence,
|
|
8242
|
+
implementationSelection: contextSelection.evidence
|
|
8243
|
+
};
|
|
8244
|
+
const selected = selectedMethodId ? withSelectedHandlerProvenance(
|
|
8245
|
+
selectionEvidence,
|
|
8246
|
+
selectedMethodId,
|
|
8247
|
+
handlerMethodNode(db, selectedMethodId)
|
|
8248
|
+
) : { evidence: selectionEvidence };
|
|
8249
|
+
selectedHandlerAvailable = !selected.unresolvedReason;
|
|
8250
|
+
if (selected.diagnostic) prependTraceDiagnostic(diagnostics, selected.diagnostic);
|
|
8251
|
+
const implTo = selected.handler?.label ? String(selected.handler.label) : `${implementation.edge.to_kind}:${implementation.edge.to_id}`;
|
|
8252
|
+
if (selected.handler) nodes.set(String(selected.handler.id), selected.handler);
|
|
7752
8253
|
edges.push({
|
|
7753
8254
|
step: current.depth,
|
|
7754
8255
|
type: "operation_implemented_by_handler",
|
|
7755
8256
|
from: to,
|
|
7756
8257
|
to: implTo,
|
|
7757
|
-
evidence:
|
|
8258
|
+
evidence: selected.evidence,
|
|
7758
8259
|
confidence: Number(implementation.edge.confidence ?? 0),
|
|
7759
|
-
unresolvedReason: implementation.edge.status === "resolved" || contextMethodId ? void 0 : String(implementation.edge.unresolved_reason ?? implementation.edge.status)
|
|
8260
|
+
unresolvedReason: selected.unresolvedReason ?? (implementation.edge.status === "resolved" || contextMethodId ? void 0 : String(implementation.edge.unresolved_reason ?? implementation.edge.status))
|
|
7760
8261
|
});
|
|
7761
8262
|
}
|
|
7762
8263
|
if (current.depth >= maxDepth) continue;
|
|
7763
8264
|
const contextScope = contextMethodId ? handlerScope(db, contextMethodId) : void 0;
|
|
7764
8265
|
const files = contextScope?.files ?? (implementation.files.size > 0 ? implementation.files : handlerFilesForOperation(db, effectiveRow.to_id));
|
|
7765
8266
|
const symbolIds = contextScope?.symbolId ? /* @__PURE__ */ new Set([contextScope.symbolId]) : implementation.symbolId ? /* @__PURE__ */ new Set([implementation.symbolId]) : void 0;
|
|
7766
|
-
if ((implementation.edge?.status === "resolved" || contextScope) && files.size > 0) {
|
|
8267
|
+
if (selectedHandlerAvailable && (implementation.edge?.status === "resolved" || contextScope) && files.size > 0) {
|
|
7767
8268
|
const targetRepoId = contextScope?.repoId ?? implementation.repoId ?? db.prepare(
|
|
7768
8269
|
"SELECT s.repo_id repoId FROM cds_operations o JOIN cds_services s ON s.id=o.service_id WHERE o.id=?"
|
|
7769
8270
|
).get(effectiveRow.to_id)?.repoId;
|
|
@@ -7798,8 +8299,7 @@ function trace(db, start, options) {
|
|
|
7798
8299
|
}
|
|
7799
8300
|
|
|
7800
8301
|
export {
|
|
7801
|
-
|
|
7802
|
-
stableProjectionValue,
|
|
8302
|
+
projectBoundedInOrder,
|
|
7803
8303
|
upsertWorkspace,
|
|
7804
8304
|
getWorkspace,
|
|
7805
8305
|
upsertRepository,
|
|
@@ -7841,4 +8341,4 @@ export {
|
|
|
7841
8341
|
selectorRepoAmbiguousDiagnostic,
|
|
7842
8342
|
trace
|
|
7843
8343
|
};
|
|
7844
|
-
//# sourceMappingURL=chunk-
|
|
8344
|
+
//# sourceMappingURL=chunk-GXYVIHJ5.js.map
|