Этап 4 corrective pack 2 по family isolation после текущих routing fixes
This commit is contained in:
@@ -5,7 +5,12 @@ import type { EvidenceItem } from "../types/stage1Contracts";
|
||||
import type { ProblemUnit } from "../types/stage2ProblemUnits";
|
||||
import type { ClaimBoundAnchorAudit } from "./assistantClaimBoundEvidence";
|
||||
|
||||
type P0DomainHint = "settlements_60_62" | "vat_document_register_book" | "month_close_costs_20_44" | null;
|
||||
type P0DomainHint =
|
||||
| "settlements_60_62"
|
||||
| "vat_document_register_book"
|
||||
| "month_close_costs_20_44"
|
||||
| "fixed_asset_amortization"
|
||||
| null;
|
||||
|
||||
const JULY_YEAR = "2020";
|
||||
const JULY_MONTH = "07";
|
||||
@@ -161,10 +166,37 @@ function collectPercentLikeSpans(text: string): Array<{ start: number; end: numb
|
||||
return spans;
|
||||
}
|
||||
|
||||
function collectContractLikeSpans(text: string): Array<{ start: number; end: number }> {
|
||||
const spans: Array<{ start: number; end: number }> = [];
|
||||
const patterns = [
|
||||
/(?:\b(?:договор(?:а|у|ом|е)?|contract)\b[^\r\n]{0,24}(?:№|#|n|no\.?)\s*[a-zа-я0-9][a-zа-я0-9/_-]{1,})/giu,
|
||||
/(?:№|#)\s*[a-zа-я0-9_-]{1,10}\/[a-zа-я0-9_-]{1,12}/giu,
|
||||
/\b\d{2}\/\d{2}(?:-[a-zа-я]{1,10})?\b/giu
|
||||
];
|
||||
for (const pattern of patterns) {
|
||||
let match: RegExpExecArray | null = null;
|
||||
while ((match = pattern.exec(text)) !== null) {
|
||||
spans.push({
|
||||
start: match.index,
|
||||
end: match.index + match[0].length
|
||||
});
|
||||
}
|
||||
}
|
||||
return spans;
|
||||
}
|
||||
|
||||
function intersectsSpan(start: number, end: number, spans: Array<{ start: number; end: number }>): boolean {
|
||||
return spans.some((span) => start < span.end && end > span.start);
|
||||
}
|
||||
|
||||
function hasAccountContextAround(text: string, start: number, end: number): boolean {
|
||||
const left = text.slice(Math.max(0, start - 28), start);
|
||||
const right = text.slice(end, Math.min(text.length, end + 28));
|
||||
return /(?:счет|сч\.?|account|schet|оплат|расч[её]т|расчет|аванс|зач[её]т|долг|постав|покуп|supplier|customer|settlement|payment|ндс|vat|проводк|posting)/iu.test(
|
||||
`${left} ${right}`
|
||||
);
|
||||
}
|
||||
|
||||
interface AccountExtractionAudit {
|
||||
resolved_account_anchors: string[];
|
||||
raw_numeric_tokens: string[];
|
||||
@@ -181,7 +213,12 @@ function extractAccountsFromTextDetailed(text: string, options?: { forceAccountC
|
||||
const dateSpans = collectDateLikeSpans(lower);
|
||||
const amountSpans = collectAmountLikeSpans(lower);
|
||||
const percentSpans = collectPercentLikeSpans(lower);
|
||||
const blockedSpans = [...dateSpans, ...amountSpans, ...percentSpans];
|
||||
const contractSpans = collectContractLikeSpans(lower);
|
||||
const blockedSpans = [...dateSpans, ...amountSpans, ...percentSpans, ...contractSpans];
|
||||
const hasAccountingLexeme =
|
||||
/(?:\bсчет(?:а|у|ом|ов)?\b|\bсч\.?\b|\baccount(?:s)?\b|\bschet(?:a|u|om|ov)?\b|оплат|расч[её]т|расчет|аванс|долг|settlement|payment|supplier|customer|постав|покуп)/iu.test(
|
||||
lower
|
||||
);
|
||||
const contextualPattern =
|
||||
/(?:\b(?:счет(?:а|у|ом|ов)?|сч\.?|account(?:s)?|schet(?:a|u|om|ov)?)\b\s*(?:№|#|:)?\s*)(\d{2}(?:\.\d{2})?)/giu;
|
||||
let contextualMatch: RegExpExecArray | null = null;
|
||||
@@ -246,6 +283,14 @@ function extractAccountsFromTextDetailed(text: string, options?: { forceAccountC
|
||||
rejectedAsNonAccounts.add(token);
|
||||
continue;
|
||||
}
|
||||
if (intersectsSpan(start, end, contractSpans)) {
|
||||
classifiedNumericTokens.push({
|
||||
token,
|
||||
classification: "other_numeric"
|
||||
});
|
||||
rejectedAsNonAccounts.add(token);
|
||||
continue;
|
||||
}
|
||||
if (!prefix || !KNOWN_ACCOUNT_PREFIXES.has(prefix)) {
|
||||
classifiedNumericTokens.push({
|
||||
token,
|
||||
@@ -254,6 +299,14 @@ function extractAccountsFromTextDetailed(text: string, options?: { forceAccountC
|
||||
rejectedAsNonAccounts.add(token);
|
||||
continue;
|
||||
}
|
||||
if (!hasAccountingLexeme || !hasAccountContextAround(lower, start, end)) {
|
||||
classifiedNumericTokens.push({
|
||||
token,
|
||||
classification: "other_numeric"
|
||||
});
|
||||
rejectedAsNonAccounts.add(token);
|
||||
continue;
|
||||
}
|
||||
accounts.add(token);
|
||||
classifiedNumericTokens.push({
|
||||
token,
|
||||
@@ -509,7 +562,7 @@ function resolveJulyAnchor(rawText: string): TemporalAnchorResolution {
|
||||
const raw = String(rawText ?? "");
|
||||
const lower = raw.toLowerCase();
|
||||
const explicitYear = lower.match(/\b(20\d{2})\b/)?.[1] ?? null;
|
||||
const dayByNamedJuly = lower.match(/(?:^|\D)(0?[1-9]|[12]\d|3[01])\s+(?:июл(?:я|ь)?|july|РёСЋР»(?:СЏ|СЊ)?)(?:\D|$)/i);
|
||||
const dayByNamedJuly = lower.match(/(?:^|\D)(0?[1-9]|[12]\d|3[01])\s+(?:июл(?:я|ь)?|july)(?:\D|$)/i);
|
||||
const dayByNumeric = lower.match(/\b(0?[1-9]|[12]\d|3[01])[./-](0?7)(?:[./-](\d{2}|\d{4}))?\b/);
|
||||
const monthByNamed = /(?:июл|july|РёСЋР»)/i.test(lower);
|
||||
const monthByNumeric = /\b20\d{2}[-/.]0?7\b/.test(lower);
|
||||
@@ -1044,6 +1097,10 @@ function isMonthClosePrefix(prefix: string): boolean {
|
||||
return numeric >= 20 && numeric <= 44;
|
||||
}
|
||||
|
||||
function isFixedAssetPrefix(prefix: string): boolean {
|
||||
return prefix === "01" || prefix === "02" || prefix === "08";
|
||||
}
|
||||
|
||||
function expectedAccountPrefixes(input: {
|
||||
focusDomainHint: P0DomainHint;
|
||||
polarity: DomainPolarity;
|
||||
@@ -1062,6 +1119,9 @@ function expectedAccountPrefixes(input: {
|
||||
if (input.focusDomainHint === "month_close_costs_20_44") {
|
||||
return ["20", "25", "26", "44", "97", "01", "02", "08"];
|
||||
}
|
||||
if (input.focusDomainHint === "fixed_asset_amortization") {
|
||||
return ["01", "02", "08"];
|
||||
}
|
||||
if (input.focusDomainHint === "settlements_60_62") {
|
||||
if (input.polarity === "supplier_payable") {
|
||||
return ["60", "51", "76"];
|
||||
@@ -1121,6 +1181,13 @@ function hasWrongDomainByAccounts(accounts: string[], focusDomainHint: P0DomainH
|
||||
if (focusDomainHint === "month_close_costs_20_44") {
|
||||
return prefixes.every((prefix) => isSettlementPrefix(prefix) || isVatPrefix(prefix));
|
||||
}
|
||||
if (focusDomainHint === "fixed_asset_amortization") {
|
||||
const hasFixedAsset = prefixes.some((prefix) => isFixedAssetPrefix(prefix));
|
||||
if (hasFixedAsset) {
|
||||
return false;
|
||||
}
|
||||
return prefixes.every((prefix) => isSettlementPrefix(prefix) || isVatPrefix(prefix) || isMonthClosePrefix(prefix));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1531,3 +1598,4 @@ export function applyEligibilityToGroundingCheck<T extends { status: string; rea
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user