diff --git a/docs/TECH/1CLLMARCH-FACT.md b/docs/TECH/1CLLMARCH-FACT.md index d3192eb..6a9fa81 100644 --- a/docs/TECH/1CLLMARCH-FACT.md +++ b/docs/TECH/1CLLMARCH-FACT.md @@ -2043,7 +2043,60 @@ Validation: - `assistantDeepTurnAttemptRuntimeAdapter.test.ts` - `assistantDeepTurnAttemptInputBuilder.test.ts` -Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 + 2.42 + 2.43 + 2.44 + 2.45 + 2.46 + 2.47 + 2.48 + 2.49 + 2.50 + 2.51 + 2.52 + 2.53 + 2.54 + 2.55 + 2.56 + 2.57 + 2.58 + 2.59 + 2.60 + 2.61 + 2.62 + 2.63 + 2.64 + 2.65 + 2.66 + 2.67 + 2.68 + 2.69 + 2.70 + 2.71 + 2.72 + 2.73 + 2.74 + 2.75 + 2.76 + 2.77 + 2.78 + 2.79 + 2.80 + 2.81 + 2.82 + 2.83 + 2.84 + 2.85 + 2.86 + 2.87 + 2.88 + 2.89 + 2.90 + 2.91 + 2.92 + 2.93 + 2.94 + 2.95 + 2.96 + 2.97 + 2.98 + 2.99 + 2.100 completed)** +Implemented in current pass (Phase 2.101 + 2.102 + 2.103 + 2.104): +1. Tightened company-anchors and business-scope contracts in deep analysis runtime: + - `assistantDeepTurnContextRuntimeAdapter.ts` + - `assistantDeepTurnAnalysisRuntimeAdapter.ts` + - `companyAnchors` now typed as `CompanyAnchorSet | null`; + - `businessScopeResolution` now typed as `AssistantBusinessScopeResolution`. +2. Aligned composition runtime input to accept typed anchors: + - `assistantDeepTurnAnalysisRuntimeAdapter.ts` + - `runCompositionRuntime` now expects `CompanyAnchorSet | null`. +3. Preserved behavior: + - no runtime logic changes; type alignment only. + +Validation: +1. `npm run build` passed. +2. Targeted deep analysis pack passed: + - `assistantDeepTurnAnalysisRuntimeAdapter.test.ts` + - `assistantDeepTurnAnalysisAttemptRuntimeAdapter.test.ts` + - `assistantDeepTurnCompositionRuntimeAdapter.test.ts` + +Implemented in current pass (Phase 2.105 + 2.106 + 2.107 + 2.108): +1. Hardened raw retrieval normalization without changing output: + - `retrievalResultNormalizer.ts` + - added `normalizeRawRetrievalResult(...)` to avoid unsafe raw casting; + - added `normalizeNumberRecord(...)` to replace `Record` casts for lifecycle distributions. +2. Preserved behavior: + - no logic changes; only safer normalization of raw payload shapes. + +Validation: +1. `npm run build` passed. +2. Targeted retrieval normalization pack passed: + - `retrievalResultEvidenceEnrichment.test.ts` + - `retrievalProblemUnitDualPayload.test.ts` + - `retrievalLifecycleRuntimeRollout.test.ts` + - `retrievalGraphRuntimeDualPayload.test.ts` + +Implemented in current pass (Phase 2.109 + 2.110 + 2.111 + 2.112): +1. Tightened plan-audit and live-route audit typing for deep grounding: + - `assistantDeepTurnPlanRuntimeAdapter.ts` + - `assistantDeepTurnGroundingRuntimeAdapter.ts` + - `assistantDeepTurnAnalysisRuntimeAdapter.ts` + - `rbpPlanAudit` / `faPlanAudit` now use `Record | null` contract; + - live route audits now typed to `RbpLiveRouteAuditDebug | null` / `FaLiveRouteAuditDebug | null`; + - grounded eligibility guard now typed to `GroundedAnswerEligibilityGuardDebug`. +2. Preserved behavior: + - no runtime logic changes; type alignment only. + +Validation: +1. `npm run build` passed. +2. Targeted deep grounding pack passed: + - `assistantDeepTurnGroundingRuntimeAdapter.test.ts` + - `assistantDeepTurnAnalysisRuntimeAdapter.test.ts` + - `assistantDeepTurnAnalysisAttemptRuntimeAdapter.test.ts` + +Status: **In progress (Phase 2.1 + 2.2 + 2.3 + 2.4 + 2.5 + 2.6 + 2.7 + 2.8 + 2.9 + 2.10 + 2.11 + 2.12 + 2.13 + 2.14 + 2.15 + 2.16 + 2.17 + 2.18 + 2.19 + 2.20 + 2.21 + 2.22 + 2.23 + 2.24 + 2.25 + 2.26 + 2.27 + 2.28 + 2.29 + 2.30 + 2.31 + 2.32 + 2.33 + 2.34 + 2.35 + 2.36 + 2.37 + 2.38 + 2.39 + 2.40 + 2.41 + 2.42 + 2.43 + 2.44 + 2.45 + 2.46 + 2.47 + 2.48 + 2.49 + 2.50 + 2.51 + 2.52 + 2.53 + 2.54 + 2.55 + 2.56 + 2.57 + 2.58 + 2.59 + 2.60 + 2.61 + 2.62 + 2.63 + 2.64 + 2.65 + 2.66 + 2.67 + 2.68 + 2.69 + 2.70 + 2.71 + 2.72 + 2.73 + 2.74 + 2.75 + 2.76 + 2.77 + 2.78 + 2.79 + 2.80 + 2.81 + 2.82 + 2.83 + 2.84 + 2.85 + 2.86 + 2.87 + 2.88 + 2.89 + 2.90 + 2.91 + 2.92 + 2.93 + 2.94 + 2.95 + 2.96 + 2.97 + 2.98 + 2.99 + 2.100 + 2.101 + 2.102 + 2.103 + 2.104 + 2.105 + 2.106 + 2.107 + 2.108 + 2.109 + 2.110 + 2.111 + 2.112 completed)** ## Stage 3 (P2): Hybrid Semantic Layer (LLM + Deterministic Guards) diff --git a/llm_normalizer/backend/dist/services/retrievalResultNormalizer.js b/llm_normalizer/backend/dist/services/retrievalResultNormalizer.js index 667ee17..316aba4 100644 --- a/llm_normalizer/backend/dist/services/retrievalResultNormalizer.js +++ b/llm_normalizer/backend/dist/services/retrievalResultNormalizer.js @@ -11,6 +11,26 @@ function toObject(value) { } return value; } +function normalizeRawRetrievalResult(raw) { + const source = toObject(raw); + if (!source) { + return {}; + } + return { + status: source.status, + result_type: source.result_type, + items: source.items, + summary: source.summary, + evidence: source.evidence, + why_included: source.why_included, + selection_reason: source.selection_reason, + risk_factors: source.risk_factors, + business_interpretation: source.business_interpretation, + confidence: source.confidence, + limitations: source.limitations, + errors: source.errors + }; +} function toStringOrNull(value) { if (typeof value !== "string") return null; @@ -61,6 +81,19 @@ function normalizeStringArray(value) { } return value.map((item) => String(item)); } +function normalizeNumberRecord(value) { + const source = toObject(value); + if (!source) { + return {}; + } + const result = {}; + for (const [key, entry] of Object.entries(source)) { + if (typeof entry === "number" && Number.isFinite(entry)) { + result[key] = entry; + } + } + return result; +} function mergeSummaryWithProblemUnitMeta(summary, input) { return { ...summary, @@ -391,7 +424,7 @@ function normalizeEvidenceItems(fragmentId, requirementIds, route, value) { }); } function normalizeRetrievalResult(fragmentId, requirementIds, route, raw) { - const rawResult = toObject(raw) ?? {}; + const rawResult = normalizeRawRetrievalResult(raw); const items = normalizeObjectArray(rawResult.items); const summary = normalizeSummary(rawResult.summary); const evidence = normalizeEvidenceItems(fragmentId, requirementIds, route, rawResult.evidence); @@ -457,8 +490,8 @@ function normalizeRetrievalResult(fragmentId, requirementIds, route, raw) { severityDistribution: graphBoundSummary.severity_distribution, confidenceDistribution: graphBoundSummary.confidence_distribution, lifecycleEnrichedUnits: graphBoundSummary.lifecycle_enriched_units ?? 0, - lifecycleDomainDistribution: (graphBoundSummary.lifecycle_domain_distribution ?? {}), - lifecycleDefectDistribution: (graphBoundSummary.lifecycle_defect_distribution ?? {}) + lifecycleDomainDistribution: normalizeNumberRecord(graphBoundSummary.lifecycle_domain_distribution), + lifecycleDefectDistribution: normalizeNumberRecord(graphBoundSummary.lifecycle_defect_distribution) }); if (graphBuild) { enrichedSummary = mergeSummaryWithGraphMeta(enrichedSummary, graphBuild.summary); diff --git a/llm_normalizer/backend/src/services/assistantDeepTurnAnalysisRuntimeAdapter.ts b/llm_normalizer/backend/src/services/assistantDeepTurnAnalysisRuntimeAdapter.ts index e9ee695..2c44b26 100644 --- a/llm_normalizer/backend/src/services/assistantDeepTurnAnalysisRuntimeAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantDeepTurnAnalysisRuntimeAdapter.ts @@ -5,6 +5,7 @@ import type { AssistantDeepTurnRetrievalGuardPipelineInput, AssistantDeepTurnRetrievalGuardPipelineOutput } from "./assistantDeepTurnGuardRuntimeAdapter"; +import type { AssistantBusinessScopeResolution } from "./assistantDeepTurnContextRuntimeAdapter"; import type { AssistantPlanEnforcementAuditLike, AssistantRequirementExtractionLike @@ -20,17 +21,15 @@ import type { } from "./assistantDeepTurnGroundingRuntimeAdapter"; import type { AssistantDeepTurnCompositionOutput } from "./assistantDeepTurnCompositionRuntimeAdapter"; import type { DomainPolarityGuardAudit, TemporalGuardAudit } from "./assistantRuntimeGuards"; +import type { CompanyAnchorSet } from "./companyAnchorResolver"; export interface AssistantDeepTurnRuntimeContextLike { - companyAnchors: AssistantDeepTurnRetrievalGuardPipelineInput["companyAnchors"]; + companyAnchors: CompanyAnchorSet | null; focusDomainForGuards: AssistantDeepTurnRetrievalGuardPipelineInput["focusDomainForGuards"]; temporalGuard: TemporalGuardAudit; domainPolarityGuardInitial: DomainPolarityGuardAudit; claimAnchorAudit: ClaimBoundAnchorAudit; - businessScopeResolution: { - business_scope_resolved?: string[] | null; - [key: string]: unknown; - }; + businessScopeResolution: AssistantBusinessScopeResolution; resolvedRouteSummary: RouteHintSummary | null; liveTemporalHint: AssistantLiveTemporalHint | null; } @@ -65,8 +64,8 @@ export interface RunAssistantDeepTurnAnalysisRuntimeInput { runGroundingRuntime: (input: { claimType: string; retrievalResults: UnifiedRetrievalResult[]; - rbpPlanAudit: unknown; - faPlanAudit: unknown; + rbpPlanAudit: AssistantDeepTurnGroundingRuntimeInput["rbpPlanAudit"]; + faPlanAudit: AssistantDeepTurnGroundingRuntimeInput["faPlanAudit"]; routeSummary: RouteHintSummary | null; requirementExtraction: AssistantRequirementExtractionLike; temporalGuard: AssistantDeepTurnGroundingRuntimeInput["temporalGuard"]; @@ -82,13 +81,13 @@ export interface RunAssistantDeepTurnAnalysisRuntimeInput { requirements: AssistantRequirement[]; coverageReport: RequirementCoverageReport; groundingCheck: AnswerGroundingCheck; - companyAnchors: unknown; + companyAnchors: CompanyAnchorSet | null; }) => AssistantDeepTurnCompositionOutput; } export interface RunAssistantDeepTurnAnalysisRuntimeOutput { - companyAnchors: unknown; - temporalGuard: unknown; + companyAnchors: CompanyAnchorSet | null; + temporalGuard: TemporalGuardAudit; claimAnchorAudit: AssistantDeepTurnRuntimeContextLike["claimAnchorAudit"]; businessScopeResolution: AssistantDeepTurnRuntimeContextLike["businessScopeResolution"]; resolvedRouteSummary: RouteHintSummary | null; diff --git a/llm_normalizer/backend/src/services/assistantDeepTurnContextRuntimeAdapter.ts b/llm_normalizer/backend/src/services/assistantDeepTurnContextRuntimeAdapter.ts index 2341025..43a7def 100644 --- a/llm_normalizer/backend/src/services/assistantDeepTurnContextRuntimeAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantDeepTurnContextRuntimeAdapter.ts @@ -3,6 +3,7 @@ import type { ClaimBoundAnchorAudit } from "./assistantClaimBoundEvidence"; import type { AssistantLiveTemporalHint } from "./assistantDeepTurnRetrievalRuntimeAdapter"; import { isAssistantFollowupApplied, type AssistantFollowupUsage } from "./assistantFollowupUsage"; import type { DomainPolarityGuardAudit, TemporalGuardAudit } from "./assistantRuntimeGuards"; +import type { CompanyAnchorSet } from "./companyAnchorResolver"; const KNOWN_P0_DOMAINS = new Set([ "settlements_60_62", @@ -37,31 +38,28 @@ export interface BuildAssistantDeepTurnRuntimeContextInput { source: string | null; }; followupUsage: AssistantFollowupUsage | null | undefined; - resolveCompanyAnchors: (userMessage: string) => unknown; + resolveCompanyAnchors: (userMessage: string) => CompanyAnchorSet; resolveBusinessScopeAlignment: (input: { userMessage: string; - companyAnchors: unknown; + companyAnchors: CompanyAnchorSet; normalized: NormalizeResponsePayload["normalized"]; routeSummary: RouteHintSummary | null; - }) => { - route_summary_resolved: RouteHintSummary | null; - [key: string]: unknown; - }; + }) => AssistantBusinessScopeResolution; inferP0DomainFromMessage: (userMessage: string) => string | null; resolveTemporalGuard: (input: { userMessage: string; normalized: NormalizeResponsePayload["normalized"]; - companyAnchors: unknown; + companyAnchors: CompanyAnchorSet; analysisContext: AssistantLiveTemporalHint | null; }) => TemporalGuardAudit; resolveDomainPolarityGuard: (input: { userMessage: string; - companyAnchors: unknown; + companyAnchors: CompanyAnchorSet; focusDomainHint: string | null; }) => DomainPolarityGuardAudit; resolveClaimBoundAnchors: (input: { userMessage: string; - companyAnchors: unknown; + companyAnchors: CompanyAnchorSet; focusDomainHint: string | null; primaryPeriod: unknown; }) => ClaimBoundAnchorAudit; @@ -74,29 +72,29 @@ export interface BuildAssistantDeepTurnRuntimeContextInput { claimType: string; focusDomainHint: string | null; userMessage: string; - companyAnchors: unknown; + companyAnchors: CompanyAnchorSet; followupApplied: boolean; - }) => { - route_summary_resolved: RouteHintSummary | null; - [key: string]: unknown; - }; + }) => AssistantBusinessScopeResolution; +} + +export interface AssistantBusinessScopeResolution { + route_summary_resolved: RouteHintSummary | null; + business_scope_raw?: string[]; + business_scope_resolved?: string[]; + company_grounding_applied?: boolean; + scope_resolution_reason?: string[]; + [key: string]: unknown; } export interface BuildAssistantDeepTurnRuntimeContextOutput { - companyAnchors: unknown; - initialBusinessScopeResolution: { - route_summary_resolved: RouteHintSummary | null; - [key: string]: unknown; - }; + companyAnchors: CompanyAnchorSet; + initialBusinessScopeResolution: AssistantBusinessScopeResolution; inferredDomainByMessage: string | null; focusDomainForGuards: string | null; temporalGuard: TemporalGuardAudit; domainPolarityGuardInitial: DomainPolarityGuardAudit; claimAnchorAudit: ClaimBoundAnchorAudit; - businessScopeResolution: { - route_summary_resolved: RouteHintSummary | null; - [key: string]: unknown; - }; + businessScopeResolution: AssistantBusinessScopeResolution; resolvedRouteSummary: RouteHintSummary | null; liveTemporalHint: AssistantLiveTemporalHint | null; } diff --git a/llm_normalizer/backend/src/services/assistantDeepTurnGroundingRuntimeAdapter.ts b/llm_normalizer/backend/src/services/assistantDeepTurnGroundingRuntimeAdapter.ts index f5fc50b..89336cb 100644 --- a/llm_normalizer/backend/src/services/assistantDeepTurnGroundingRuntimeAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantDeepTurnGroundingRuntimeAdapter.ts @@ -2,6 +2,9 @@ import type { AnswerGroundingCheck, AssistantRequirement, RequirementCoverageReport, + RbpLiveRouteAuditDebug, + FaLiveRouteAuditDebug, + GroundedAnswerEligibilityGuardDebug, UnifiedRetrievalResult } from "../types/assistant"; import type { NormalizeResponsePayload, RouteHintSummary } from "../types/normalizer"; @@ -16,8 +19,8 @@ import { export interface AssistantDeepTurnGroundingRuntimeInput { claimType: string; retrievalResults: UnifiedRetrievalResult[]; - rbpPlanAudit: unknown; - faPlanAudit: unknown; + rbpPlanAudit: RbpLiveRouteAuditDebug["plan_override"]; + faPlanAudit: FaLiveRouteAuditDebug["plan_override"]; routeSummary: RouteHintSummary | null; normalizedPayload: NormalizeResponsePayload["normalized"] | null | undefined; userMessage: string; @@ -46,13 +49,13 @@ export interface AssistantDeepTurnGroundingRuntimeInput { collectRbpLiveRouteAudit: (input: { claimType: string; retrievalResults: UnifiedRetrievalResult[]; - planAudit: unknown; - }) => unknown; + planAudit: RbpLiveRouteAuditDebug["plan_override"]; + }) => RbpLiveRouteAuditDebug | null; collectFaLiveRouteAudit: (input: { claimType: string; retrievalResults: UnifiedRetrievalResult[]; - planAudit: unknown; - }) => unknown; + planAudit: FaLiveRouteAuditDebug["plan_override"]; + }) => FaLiveRouteAuditDebug | null; runCoverageGroundingPipelineFn?: typeof runAssistantCoverageGroundingPipeline; applyGroundingEligibilityFn?: ( input: AssistantDeepTurnGroundingEligibilityInput @@ -60,11 +63,11 @@ export interface AssistantDeepTurnGroundingRuntimeInput { } export interface AssistantDeepTurnGroundingRuntimeOutput { - rbpLiveRouteAudit: unknown; - faLiveRouteAudit: unknown; + rbpLiveRouteAudit: RbpLiveRouteAuditDebug | null; + faLiveRouteAudit: FaLiveRouteAuditDebug | null; coverageEvaluation: AssistantCoverageEvaluationResult; groundingCheckBase: AnswerGroundingCheck; - groundedAnswerEligibilityGuard: unknown; + groundedAnswerEligibilityGuard: GroundedAnswerEligibilityGuardDebug; groundingCheck: AnswerGroundingCheck; } diff --git a/llm_normalizer/backend/src/services/assistantDeepTurnPlanRuntimeAdapter.ts b/llm_normalizer/backend/src/services/assistantDeepTurnPlanRuntimeAdapter.ts index 8b0e482..94d0580 100644 --- a/llm_normalizer/backend/src/services/assistantDeepTurnPlanRuntimeAdapter.ts +++ b/llm_normalizer/backend/src/services/assistantDeepTurnPlanRuntimeAdapter.ts @@ -9,7 +9,7 @@ export interface AssistantRequirementExtractionLike { export interface AssistantPlanEnforcementAuditLike { executionPlan: AssistantExecutionPlanItem[]; - audit: unknown; + audit: Record | null; } export interface BuildAssistantDeepTurnExecutionPlanInput { diff --git a/llm_normalizer/backend/src/services/retrievalResultNormalizer.ts b/llm_normalizer/backend/src/services/retrievalResultNormalizer.ts index 5a9bedd..cbf9828 100644 --- a/llm_normalizer/backend/src/services/retrievalResultNormalizer.ts +++ b/llm_normalizer/backend/src/services/retrievalResultNormalizer.ts @@ -44,6 +44,27 @@ function toObject(value: unknown): Record | null { return value as Record; } +function normalizeRawRetrievalResult(raw: unknown): RawRetrievalResult { + const source = toObject(raw); + if (!source) { + return {}; + } + return { + status: source.status as string | undefined, + result_type: source.result_type as string | undefined, + items: source.items, + summary: source.summary, + evidence: source.evidence, + why_included: source.why_included, + selection_reason: source.selection_reason, + risk_factors: source.risk_factors, + business_interpretation: source.business_interpretation, + confidence: source.confidence, + limitations: source.limitations, + errors: source.errors + }; +} + function toStringOrNull(value: unknown): string | null { if (typeof value !== "string") return null; const trimmed = value.trim(); @@ -101,6 +122,20 @@ function normalizeStringArray(value: unknown): string[] { return value.map((item) => String(item)); } +function normalizeNumberRecord(value: unknown): Record { + const source = toObject(value); + if (!source) { + return {}; + } + const result: Record = {}; + for (const [key, entry] of Object.entries(source)) { + if (typeof entry === "number" && Number.isFinite(entry)) { + result[key] = entry; + } + } + return result; +} + function mergeSummaryWithProblemUnitMeta( summary: Record, input: { @@ -511,7 +546,7 @@ export function normalizeRetrievalResult( route: string, raw: unknown ): UnifiedRetrievalResult { - const rawResult = (toObject(raw) as RawRetrievalResult | null) ?? {}; + const rawResult = normalizeRawRetrievalResult(raw); const items = normalizeObjectArray(rawResult.items); const summary = normalizeSummary(rawResult.summary); const evidence = normalizeEvidenceItems(fragmentId, requirementIds, route, rawResult.evidence); @@ -584,8 +619,8 @@ export function normalizeRetrievalResult( severityDistribution: graphBoundSummary.severity_distribution, confidenceDistribution: graphBoundSummary.confidence_distribution, lifecycleEnrichedUnits: graphBoundSummary.lifecycle_enriched_units ?? 0, - lifecycleDomainDistribution: (graphBoundSummary.lifecycle_domain_distribution ?? {}) as Record, - lifecycleDefectDistribution: (graphBoundSummary.lifecycle_defect_distribution ?? {}) as Record + lifecycleDomainDistribution: normalizeNumberRecord(graphBoundSummary.lifecycle_domain_distribution), + lifecycleDefectDistribution: normalizeNumberRecord(graphBoundSummary.lifecycle_defect_distribution) }); if (graphBuild) {