@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.
@@ -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 = projectBounded(value, compareEvidenceValue, limit);
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
- if (ts8.isParenthesizedExpression(expr) || ts8.isAwaitExpression(expr)) return queryEntityFromAst(expr.expression, initializers);
3051
- if (ts8.isIdentifier(expr) && initializers.has(expr.text)) return queryEntityFromAst(initializers.get(expr.text), initializers);
3052
- if (ts8.isCallExpression(expr)) {
3053
- const name = expressionName(expr.expression);
3054
- if (name === "cds.run") return queryEntityFromAst(expr.arguments[0], initializers);
3055
- if (["SELECT.one.from", "SELECT.from", "SELECT.one", "INSERT.into", "UPSERT.into", "DELETE.from", "UPDATE.entity"].includes(name)) return entityFromExpression(expr.arguments[0]);
3056
- if (name === "UPDATE") return entityFromExpression(expr.arguments[0]);
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 = projectBounded(candidates2, compareCandidateEvidence);
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
- candidates: candidates2.map((candidate, index) => candidateEvidence(candidate, index + 1))
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,hc.source_line sourceLine,
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, contextualEvidence) {
6555
- const evidence = { ...persistedEvidence, ...contextualEvidence ?? {} };
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(contextualEvidence?.contextualServiceBindingAttempted),
6895
+ contextualResolutionParticipated: Boolean(contextualEvidence2?.contextualServiceBindingAttempted),
6570
6896
  persistedResolution: persistedResolution(row)
6571
6897
  };
6572
6898
  }
6573
- function runtimeResolution(db, row, evidence, options, workspaceId, contextualUnresolvedReason) {
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
- contextualUnresolvedReason
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, enriched);
6597
- if (dynamicMode === "infer") {
6598
- const inferred = inferredTarget(analysis);
6599
- if (inferred)
6600
- return resolvedRuntimeResolution(row, enriched, inferred, inferred.reasons);
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(enriched, row, unresolvedReason2),
6607
- unresolvedReason: unresolvedReason2
6954
+ evidence: withEffectiveResolution(
6955
+ evidence,
6956
+ row,
6957
+ unresolvedReason,
6958
+ void 0,
6959
+ contextualState
6960
+ ),
6961
+ unresolvedReason
6608
6962
  };
6609
6963
  }
6610
- if (!hasApplicableRuntimeVariables(evidence, options.vars)) {
6611
- const unresolvedReason2 = contextualUnresolvedReason ?? row.unresolved_reason;
6612
- const withSections = withEffectiveResolution(enriched, row, unresolvedReason2);
6613
- return { row, evidence: withSections, unresolvedReason: unresolvedReason2 };
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
- enriched,
6971
+ evidence,
6620
6972
  resolution.target,
6621
6973
  resolution.reasons
6622
6974
  );
6623
6975
  const unresolvedReason = runtimeUnresolvedReason(resolution);
6624
- return { row, evidence: withEffectiveResolution(enriched, row, unresolvedReason, resolution), unresolvedReason };
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, contextualUnresolvedReason) {
6627
- const unresolvedReason = contextualUnresolvedReason ?? row.unresolved_reason;
6988
+ function unchangedRuntimeResolution(row, evidence, contextualState) {
6989
+ const unresolvedReason = contextualReason(contextualState) ?? row.unresolved_reason;
6628
6990
  return {
6629
6991
  row,
6630
- evidence: withEffectiveResolution(evidence, row, unresolvedReason),
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(evidence, row, unresolvedReason),
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(row, evidence, unresolvedReason, resolution);
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 { ...rest, effectiveResolution: current, linker: { status: current.status, confidence: current.confidence, reason: unresolvedReason, edgeType: current.edgeType } };
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 isRecord5(value) ? value : {};
7594
+ return isRecord6(value) ? value : {};
7201
7595
  }
7202
- function isRecord5(value) {
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 = { ...parseEvidence(impl.edge.evidence_json), startResolution: { strategy: "indexed_operation_graph", matchedOperationId: scope.startOperationId, implementationEdgeId: impl.edge.id, implementationStatus: impl.edge.status, selectedHandlerMethodId: selectedMethodId }, implementationSelection: startSelection.methodId ? startSelection.evidence : void 0 };
7648
- const handlerNode = selectedMethodId ? handlerMethodNode(db, selectedMethodId) : void 0;
7649
- if (handlerNode) nodes.set(String(handlerNode.id), handlerNode);
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: handlerNode?.label ? String(handlerNode.label) : `${impl.edge.to_kind}:${impl.edge.to_id}`, evidence: implEvidence, confidence: Number(impl.edge.confidence ?? 0), unresolvedReason: impl.edge.status === "resolved" || startSelection.methodId ? void 0 : String(impl.edge.unresolved_reason ?? impl.edge.status) });
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.unresolvedReason);
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
- const contextNode = contextMethodId ? handlerMethodNode(db, contextMethodId) : void 0;
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 handlerNode = implementation.edge.status === "resolved" ? handlerMethodNode(db, implementation.edge.to_id) : contextNode;
7750
- const implTo = handlerNode?.label ? String(handlerNode.label) : `${implementation.edge.to_kind}:${implementation.edge.to_id}`;
7751
- if (handlerNode) nodes.set(String(handlerNode.id), handlerNode);
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: contextMethodId ? { ...implEvidence, contextualImplementationSelected: contextSelection.evidence.strategy !== "implementation_repo_hint", contextualImplementation: contextSelection.evidence, implementationSelection: contextSelection.evidence } : { ...implEvidence, contextualImplementation: contextSelection.evidence, implementationSelection: contextSelection.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
- projectBounded,
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-LFH7C46B.js.map
8344
+ //# sourceMappingURL=chunk-GXYVIHJ5.js.map