diff --git a/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-1-arm-statements.md b/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-1-arm-statements.md index da5b75e..4e2aeb5 100644 --- a/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-1-arm-statements.md +++ b/openspec/changes/unified-statement-normalization/plans/2026-10-18-plan-1-arm-statements.md @@ -411,8 +411,9 @@ git -C "$R" commit -m "feat: типы шага 1 и выхода шагов 2– auditor: tuple[re.Pattern[str], ...], legal_form: tuple[re.Pattern[str], ...])` - `UnitRules(spellings: tuple[tuple[re.Pattern[str], str], ...], okei: Mapping[str, str], thousands: str, fractional_share_percent: int)` - - `CodeOrders(sequences: Mapping[tuple[Edition, DocumentType, FormVariant], tuple[str, ...]])` с методом - `sequence(edition: Edition, form: DocumentType, variant: FormVariant) -> tuple[str, ...]` + - `CodeOrders(editions: tuple[Edition, ...], sequences: Mapping[tuple[Edition, DocumentType, FormVariant], + tuple[str, ...]])` с методом `sequence(edition: Edition, form: DocumentType, variant: FormVariant) -> + tuple[str, ...]`; `editions` — порядок редакций в файле (`(RAS_66N, FSBU4)`) - `WarningRule(code: str, severity: Severity, scope: Literal["document", "file"])` - `Rules(checks: CheckRules, periods: PeriodRules, headers: HeaderRules, units: UnitRules, code_ranges: CodeRanges, code_orders: CodeOrders, lookalikes: Mapping[str, str], warnings: Mapping[str, WarningRule])` @@ -512,6 +513,7 @@ def test_code_orders_with_repeats(rules: Rules) -> None: assert fsbu.count("1220") == len(("1220", "1220")) and "1120" not in fsbu ras = rules.code_orders.sequence(Edition.RAS_66N, DocumentType.BALANCE, FormVariant.FULL) assert "1120" in ras and ras.index("1110") < ras.index("1100") + assert rules.code_orders.editions == (Edition.RAS_66N, Edition.FSBU4) def test_no_code_to_name_mapping_anywhere() -> None: @@ -2629,6 +2631,7 @@ PUBLIC = { "StatementLine", "FailedRelation", "StatementChecks", "StatementDocument", "CandidateResult", "NormalizationResult", "Rules", "RulesError", "load_rules", "default_rules", "normalize_candidate", "normalize", "parse_header", "type_hint", "continuation_type", "sheet_joins", "parse_code", "parse_amount", "parse_date", + "resolve_relative", "fix_lookalikes", "make_warning", "StatusInput", "StatusLine", "StatusValue", "document_status", "envelope_status", "StoredForm", "StoredColumn", "StoredLine", "StoredValue", "StoredWarning", "RecomputeResult", "recompute", "to_jsonable", "candidate_from_dict", "statements_version", @@ -2748,6 +2751,8 @@ parse_code(text: str | None, rules: Rules) -> CodeParse # parse_amount(text: str | None, source: Source, rules: Rules) -> AmountParse # AmountParse(amount: Decimal | None, string_value: str | None, is_recognized: bool, sign_form: SignForm | None) parse_date(text: str | None, rules: Rules) -> date | None +resolve_relative(kind: PeriodKind, effective: date | None) -> date | None + # дата относительной колонки от эффективной даты (ядро — после правки даты отчёта) fix_lookalikes(text: str, lookalikes: Mapping[str, str], *, anywhere: bool = False) -> str make_warning(code: str, message: str, rules: Rules, *, line_refs: Sequence[str] = (), column_index: int | None = None, field: str | None = None, locator: str | None = None) -> StatementWarning @@ -2799,8 +2804,9 @@ RecomputeResult(form_variant: FormVariant | None, edition: Edition | None, check ### Словари (`Rules`) — что нужно хостам `Rules.headers.labels` / `auditor` / `legal_form` / `form_titles` / `okud` / `continuation` — метки шапки и заголовки -для адаптера Excel (план 3); `Rules.code_orders.sequence(edition, form, variant)` — перечень кодов редакции (ядру — -порядок и состав строк формы, план 4); `Rules.lookalikes` — буквы-двойники; `Rules.warnings` — уровни предупреждений. +для адаптера Excel; `Rules.code_orders.sequence(edition, form, variant)` и `Rules.code_orders.editions` — перечень +кодов редакции и порядок редакций (ядру — порядок и состав строк формы); `Rules.checks.tolerance` — допуск ±1 (ядру — +для межформенной проверки); `Rules.lookalikes` — буквы-двойники; `Rules.warnings` — уровни предупреждений. --- @@ -2874,3 +2880,15 @@ RecomputeResult(form_variant: FormVariant | None, edition: Edition | None, check `pytest.ini` хоста задаёт `env` (`APP_ENV=test`) — тестам пакета он не нужен и не мешает; подтверждение — в плане 2. - **O-4.** Dockerfile хостов должен копировать `api/arm_statements/rules/*.yaml` в образ (словари читаются с диска) — в план 2 или планы сервисов. +- **O-5.** План 3 (arm-core, `2026-10-18-plan-3-arm-core.md`, таблица «Ожидаемые имена пакета») написан параллельно + и ждёт сверки с этим разделом (его O-8). Расхождения, которые правит адаптер `statements_engine.py` плана 3: + `recompute_stored_form` / `StoredFormResult` → `recompute` / `RecomputeResult`; `load_code_orders()`, + `CodeOrders.order`, `.editions` → `default_rules().code_orders.sequence(...)`, `.editions`; `relative_period_date` → + `resolve_relative`; `load_check_rules().tolerance` → `default_rules().checks.tolerance`; уверенности — + `float | None`, а не `Decimal`; `StoredValue.is_recognized` — `bool` (не `bool | None`); `StoredColumn.column_index` + — `int | None`; `period_kind`, `line_status`, `severity`, `document_type`, `edition`, `form_variant` — `StrEnum` + пакета (подкласс `str`, значения — строки контракта); `edition` результата — `Edition | None`; + `FailedRelation` — `column_index: int | None` плюс `column_key: str`, `expected` и `actual` — `Decimal` (не + `None`); `StatusInput` — `lines: tuple[StatusLine, ...]`, `values: tuple[StatusValue, ...]`, `hard_failures` + вместо `relations_failed`, дополнительно `needs_review_fields`. Решить, какая сторона меняется (по умолчанию — + адаптер плана 3, как он сам предусматривает).