NODEDC_1C/llm_normalizer/backend/dist/services/addressTruthGatePolicy.js

254 lines
9.6 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ADDRESS_TRUTH_GATE_SCHEMA_VERSION = void 0;
exports.resolveAddressTruthGate = resolveAddressTruthGate;
exports.toAddressTruthGateContract = toAddressTruthGateContract;
exports.buildAddressTruthGateDebugFields = buildAddressTruthGateDebugFields;
exports.attachAddressTruthGate = attachAddressTruthGate;
exports.ADDRESS_TRUTH_GATE_SCHEMA_VERSION = "address_truth_gate_v1";
function toRecordObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
return value;
}
function toNonEmptyString(value) {
if (value === null || value === undefined) {
return null;
}
const text = String(value).trim();
return text.length > 0 ? text : null;
}
function toStringList(value) {
if (!Array.isArray(value)) {
return [];
}
return value
.map((item) => toNonEmptyString(item))
.filter((item) => Boolean(item));
}
function isTruthGateStatus(value) {
return (value === "full_confirmed" ||
value === "partial_supported" ||
value === "blocked_missing_anchor" ||
value === "blocked_route_expectation_failure" ||
value === "blocked_execution_error" ||
value === "limited_temporal_or_contextual" ||
value === "unknown");
}
function isCarryoverDepth(value) {
return value === "full" || value === "root_only" || value === "object_only" || value === "meta_only" || value === "none";
}
function isLimitedReasonCategory(value) {
return (value === "empty_match" ||
value === "missing_anchor" ||
value === "recipe_visibility_gap" ||
value === "execution_error" ||
value === "unsupported");
}
function isRuntimeReadiness(value) {
return (value === "LIVE_QUERYABLE" ||
value === "LIVE_QUERYABLE_WITH_LIMITS" ||
value === "REQUIRES_SPECIALIZED_RECIPE" ||
value === "DEEP_ONLY" ||
value === "UNKNOWN");
}
function normalizeReasonCode(value) {
const normalized = value
.trim()
.replace(/[^\p{L}\p{N}_.:-]+/gu, "_")
.replace(/^_+|_+$/g, "")
.toLowerCase();
return normalized.length > 0 ? normalized.slice(0, 120) : null;
}
function pushReason(target, value) {
const text = toNonEmptyString(value);
if (!text) {
return;
}
const normalized = normalizeReasonCode(text);
if (normalized && !target.includes(normalized)) {
target.push(normalized);
}
}
function hasFilterScope(filters) {
if (!filters) {
return false;
}
const scopeKeys = [
"period_from",
"period_to",
"as_of_date",
"organization",
"counterparty",
"contract",
"account",
"item",
"warehouse",
"document_type",
"document_ref",
"status"
];
return scopeKeys.some((key) => toNonEmptyString(filters[key]) !== null);
}
function hasObjectFocus(input) {
if (toNonEmptyString(input.filters?.item)) {
return true;
}
if (input.semanticFrame?.selected_object_scope_detected) {
return true;
}
if (input.semanticFrame?.anchor_kind === "selected_object" || input.semanticFrame?.anchor_kind === "item") {
return true;
}
return (input.intent === "inventory_purchase_provenance_for_item" ||
input.intent === "inventory_purchase_documents_for_item" ||
input.intent === "inventory_sale_trace_for_item" ||
input.intent === "inventory_profitability_for_item" ||
input.intent === "inventory_purchase_to_sale_chain" ||
input.intent === "inventory_aging_by_purchase_date");
}
function hasReusableRootScope(input) {
if (hasFilterScope(input.filters)) {
return true;
}
return Boolean(input.semanticFrame && input.semanticFrame.scope_kind !== "none");
}
function truthGateStatusFrom(input) {
if (input.truthGateStatusHint) {
return input.truthGateStatusHint;
}
const missingRequiredFilters = input.missingRequiredFilters ?? [];
const reasonCodes = input.reasons ?? [];
const heuristicOpenItemsFallback = Boolean(input.intent === "open_items_by_counterparty_or_contract" &&
(reasonCodes.includes("confirmed_balance_unavailable_fallback_to_heuristic_candidates") ||
reasonCodes.includes("open_items_account_query_override_to_movements")));
if (input.routeExpectationStatus === "mismatch") {
return "blocked_route_expectation_failure";
}
if (input.limitedReasonCategory === "execution_error") {
return "blocked_execution_error";
}
if (missingRequiredFilters.length > 0 || input.limitedReasonCategory === "missing_anchor") {
return "blocked_missing_anchor";
}
if (input.temporalGuardOutcome === "ambiguous_limited" || input.temporalAlignmentStatus === "conflicting") {
return "limited_temporal_or_contextual";
}
if (input.replyType === "factual" && input.limitedReasonCategory === "empty_match") {
return "full_confirmed";
}
if (heuristicOpenItemsFallback) {
return "partial_supported";
}
if (input.limitedReasonCategory === "empty_match" ||
input.limitedReasonCategory === "recipe_visibility_gap" ||
input.limitedReasonCategory === "unsupported" ||
input.replyType === "partial_coverage") {
return "partial_supported";
}
if ((input.rowsMatched ?? 0) > 0) {
return "full_confirmed";
}
return "unknown";
}
function carryoverEligibilityFor(input, truthGateStatus) {
if (truthGateStatus.startsWith("blocked")) {
return "none";
}
if (input.limitedReasonCategory === "recipe_visibility_gap" || input.limitedReasonCategory === "unsupported") {
return "meta_only";
}
if (hasObjectFocus(input)) {
return "object_only";
}
if (truthGateStatus === "limited_temporal_or_contextual") {
return hasReusableRootScope(input) ? "root_only" : "meta_only";
}
if (truthGateStatus === "full_confirmed" || truthGateStatus === "partial_supported") {
return hasReusableRootScope(input) ? "root_only" : "meta_only";
}
return "none";
}
function explanationFor(truthGateStatus, limitedReasonCategory) {
if (truthGateStatus === "full_confirmed") {
return null;
}
if (truthGateStatus === "blocked_missing_anchor") {
return "required_anchor_missing";
}
if (truthGateStatus === "blocked_route_expectation_failure") {
return "route_expectation_failed";
}
if (truthGateStatus === "blocked_execution_error") {
return "execution_failed";
}
if (truthGateStatus === "limited_temporal_or_contextual") {
return "temporal_or_contextual_limit";
}
if (limitedReasonCategory === "recipe_visibility_gap") {
return "specialized_recipe_required";
}
if (limitedReasonCategory === "unsupported") {
return "unsupported_in_current_contour";
}
return truthGateStatus === "partial_supported" ? "evidence_or_coverage_is_partial" : "truth_gate_not_confirmed";
}
function collectReasonCodes(input, truthGateStatus) {
const reasons = [];
pushReason(reasons, `address_truth_gate_${truthGateStatus}`);
pushReason(reasons, input.routeExpectationReason);
pushReason(reasons, input.limitedReasonCategory ? `limited_category_${input.limitedReasonCategory}` : null);
(input.missingRequiredFilters ?? []).forEach((item) => pushReason(reasons, `missing_filter_${item}`));
(input.limitations ?? []).forEach((item) => pushReason(reasons, item));
(input.reasons ?? []).forEach((item) => pushReason(reasons, item));
return reasons.slice(0, 32);
}
function resolveAddressTruthGate(input) {
const truthGateStatus = truthGateStatusFrom(input);
return {
schema_version: exports.ADDRESS_TRUTH_GATE_SCHEMA_VERSION,
policy_owner: "addressTruthGatePolicy",
truth_gate_status: truthGateStatus,
carryover_eligibility: carryoverEligibilityFor(input, truthGateStatus),
limited_reason_category: input.limitedReasonCategory ?? null,
runtime_readiness: input.runtimeReadiness ?? "UNKNOWN",
reason_codes: collectReasonCodes(input, truthGateStatus),
blocked_or_limited_explanation: explanationFor(truthGateStatus, input.limitedReasonCategory ?? null)
};
}
function toAddressTruthGateContract(value) {
const record = toRecordObject(value);
if (!record) {
return null;
}
const truthGateStatus = toNonEmptyString(record.truth_gate_status);
const carryoverEligibility = toNonEmptyString(record.carryover_eligibility);
const limitedReasonCategory = toNonEmptyString(record.limited_reason_category);
const runtimeReadiness = toNonEmptyString(record.runtime_readiness);
if (!isTruthGateStatus(truthGateStatus) || !isCarryoverDepth(carryoverEligibility) || !isRuntimeReadiness(runtimeReadiness)) {
return null;
}
return {
schema_version: exports.ADDRESS_TRUTH_GATE_SCHEMA_VERSION,
policy_owner: "addressTruthGatePolicy",
truth_gate_status: truthGateStatus,
carryover_eligibility: carryoverEligibility,
limited_reason_category: isLimitedReasonCategory(limitedReasonCategory) ? limitedReasonCategory : null,
runtime_readiness: runtimeReadiness,
reason_codes: toStringList(record.reason_codes).slice(0, 32),
blocked_or_limited_explanation: toNonEmptyString(record.blocked_or_limited_explanation)
};
}
function buildAddressTruthGateDebugFields(input) {
return {
address_truth_gate_v1: resolveAddressTruthGate(input)
};
}
function attachAddressTruthGate(debugPayload, input) {
return {
...debugPayload,
...buildAddressTruthGateDebugFields(input)
};
}