Правки итогового ревью: спека, предупреждение, README, design (#58)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
480db4f3aa
commit
d6dd341003
10
README.md
10
README.md
@ -157,8 +157,8 @@ ParseOutcome`. Структура ОСВ ищется **по содержимо
|
||||
### Строки-показатели и колонка «Показатели» (§1.3, AURORA-1613, AURORA-1661)
|
||||
|
||||
Колонка «Показатели» (`service_columns.indicator`; заголовок часто «Показа-тели») несёт вид суммы строки: «БУ» — обычная
|
||||
строка данных (`data_type = BU`), «НУ», «Вал.», «Кол.» — показатели (`CURRENCY`/`QUANTITY` по словарю
|
||||
`data_types.yaml`: `indicator_column`), «ПР», «ВР» (`indicator_column_untyped`) и неизвестная метка — показатель с
|
||||
строка данных (`data_type = BU`), «НУ», «Вал.», «Кол.» — показатели (`NU`/`CURRENCY`/`QUANTITY` по словарю
|
||||
`data_types.yaml`: `indicator_column`), «ПР», «ВР» (`indicator_column_untyped`, `data_type = null`) и неизвестная метка — показатель с
|
||||
`data_type = null` (неизвестная — ещё и предупреждение `OSV_ROWS`). Показатель — строка с признаком `indicator`: он
|
||||
не входит в суммирование «сумма детей = родитель» и не проверяется как родитель, его родитель в дереве — предыдущая строка
|
||||
данных (`indicators.py`, вне каскада иерархии); `row_value` строки с меткой колонки — сама метка, колонка остаётся в
|
||||
@ -170,13 +170,13 @@ ParseOutcome`. Структура ОСВ ищется **по содержимо
|
||||
|
||||
### Контрольные суммы (§1.4)
|
||||
|
||||
Допуск ±0.01, пустое значение = 0. Строки «Вал.», «Кол.» и код валюты (`data_type = CURRENCY | QUANTITY`) в суммирование
|
||||
не входят. Нетривиальное правило — сверка «сумма детей = родитель»: **обороты** сверяются по колонкам, **сальдо** — по
|
||||
Допуск ±0.01, пустое значение = 0. Строки-показатели (признак строки: НУ/ПР/ВР/Кол./Вал./«В валюте»/код валюты, метка колонки «Показатели» или
|
||||
текст) в суммирование не входят. Нетривиальное правило — сверка «сумма детей = родитель»: **обороты** сверяются по колонкам, **сальдо** — по
|
||||
колонкам либо, если у родителя сальдо свёрнуто (не больше одной ненулевой стороны), по нетто `дебет − кредит`: 1С
|
||||
показывает счёт нетто, а субсчета и контрагентов — развёрнуто (решение R-21, design №31). Остаточный риск: перестановка
|
||||
сторон при совпавшем нетто родителя этой проверкой не ловится — её ловят тождество строки и «Итого = корень».
|
||||
|
||||
**«Итого».** Основная итоговая строка — первая TOTAL листа; она сверяется с первым корнем ACCOUNT либо, если корней
|
||||
**«Итого».** Основная итоговая строка — первая TOTAL, не являющаяся показателем; она сверяется с первым корнем ACCOUNT либо, если корней
|
||||
уровня 0 несколько (лист без строки корневого счёта: верхний уровень — субсчета 58.01, 58.03), с суммой строк уровня 0
|
||||
(OQ-106, OQ-133; сальдо — по колонкам либо по нетто, если «Итого» свёрнуто, как у родителя выше). Вторая итоговая
|
||||
строка сразу за «Итого» («Итого развернутое», `total_row_secondary`) — тоже `TOTAL`, в сверку не входит. Строка сумм
|
||||
|
||||
@ -46,7 +46,9 @@ def read_label(sheet: Sheet, row: int, text: str, header: TableHeader, rules: Ru
|
||||
return RowLabel(indicator=False, data_type="BU")
|
||||
if data_type is not None or any(p.search(label) for p in rules.data_types.indicator_column_untyped):
|
||||
return RowLabel(indicator=True, data_type=data_type, text=label)
|
||||
warning = f"строка {row}: метка «{label}» в колонке «Показатели» не распознана — строка вне проверок"
|
||||
warning = (
|
||||
f"строка {row}: метка «{label}» в колонке «Показатели» не распознана — строка не участвует в проверках"
|
||||
)
|
||||
return RowLabel(indicator=True, data_type=None, text=label, warning=warning)
|
||||
data_type = row_data_type(text, rules, frozenset(rules.data_types.currency_codes))
|
||||
return RowLabel(indicator=data_type is not None, data_type=data_type)
|
||||
|
||||
@ -513,6 +513,23 @@ def test_document_of_nu_rows_without_indicator_is_checked_as_usual() -> None:
|
||||
assert parent_sums(rows) == [7]
|
||||
|
||||
|
||||
def test_indicator_with_same_data_type_as_parent_is_excluded_by_flag() -> None:
|
||||
"""Признак — флаг, а не `data_type`: показатель НУ под родителем НУ не суммируется, не родитель и не «Итого»."""
|
||||
rows = [
|
||||
row(7, ("10", None, None, None, "10", None), group_type="ACCOUNT", data_type="NU"),
|
||||
row(8, ("10", None, None, None, "10", None), level=1, parent=7, data_type="NU"),
|
||||
row(
|
||||
9, ("5", None, None, None, "5", None), level=1, parent=7, group_type="OTHER", data_type="NU", indicator=True
|
||||
),
|
||||
row(10, ("3", None, None, None, "3", None), level=2, parent=9, data_type="NU"),
|
||||
row(11, ("15", None, None, None, "15", None), group_type="TOTAL", data_type="NU", indicator=True),
|
||||
row(12, ("10", None, None, None, "10", None), group_type="TOTAL", data_type="NU"),
|
||||
]
|
||||
|
||||
assert parent_sums(rows) == []
|
||||
assert total_matches_root(rows) is True
|
||||
|
||||
|
||||
def test_total_skips_leading_indicator_total() -> None:
|
||||
"""Первая итоговая строка без признака — основная «Итого», даже если перед ней стоит итог-показатель."""
|
||||
rows = [
|
||||
|
||||
@ -59,6 +59,7 @@ def test_unknown_label_warns_with_row_number(rules: Rules) -> None:
|
||||
assert result.warning is not None
|
||||
assert f"строка {row}" in result.warning
|
||||
assert "Ед." in result.warning
|
||||
assert "не участвует в проверках" in result.warning
|
||||
|
||||
|
||||
def test_text_currency_label_without_column(rules: Rules) -> None:
|
||||
|
||||
@ -57,8 +57,8 @@ r31 (продолжение) | НУ | …
|
||||
### Иерархия: показатели вне каскада, родитель — предыдущая строка данных
|
||||
|
||||
Новый модуль `src/parser/indicators.py` (чтобы не пересекаться с треком B в `hierarchy.py`):
|
||||
`attach_indicators(rows, levels, total_row) -> Levels`. В `OsvParser.parse_sheet` каскад `resolve_levels` получает
|
||||
строки без показателей; затем каждому показателю (до «Итого») назначается родитель — ближайшая строка выше, которая не
|
||||
`levels_with_indicators(rows, total_row, deadline) -> Levels`: функция сама запускает каскад `resolve_levels` на
|
||||
строках без показателей (в `OsvParser.parse_sheet` вызывается она одна); затем каждому показателю (до «Итого») назначается родитель — ближайшая строка выше, которая не
|
||||
показатель, — и уровень `level(родителя) + 1`; показатель в начале таблицы без строки данных выше — уровень 0 без
|
||||
родителя. Итоговые строки-показатели — уровень 0 без родителя (как «Итого»). Стратегия иерархии (`Levels.strategy`) —
|
||||
стратегия каскада.
|
||||
@ -71,8 +71,9 @@ r31 (продолжение) | НУ | …
|
||||
|
||||
`_trailing_totals` продолжает серию итоговых строк и через строки с меткой показателя в колонке «Показатели»
|
||||
(r31 после r30): они остаются в таблице, классифицируются TOTAL с `data_type` метки и `indicator = True`;
|
||||
`checks._total` берёт первую итоговую строку **не показатель**. Трек B меняет `_trailing_totals`/`_total` под
|
||||
«Итого развернутое» перед «Итого» — при слиянии второй трек добавляет своё условие к версии первого.
|
||||
`checks._total` берёт первую итоговую строку **не показатель**. Трек B добавляет `_leading_totals` и меняет
|
||||
`_total` под «Итого развернутое» перед «Итого» (`_trailing_totals` не трогает) — при слиянии второй трек добавляет
|
||||
своё условие к версии первого.
|
||||
|
||||
### Вид данных по умолчанию
|
||||
|
||||
@ -101,6 +102,12 @@ r31 (продолжение) | НУ | …
|
||||
| 19.10.2026 | Умолчание BU — только строкам без собственного вида; `header.data_type` остаётся `null` | Шапка действительно молчит; ядру нужен вид строки, не шапки | Предупреждение на листах без «Выводимые данные» (были без него) |
|
||||
| 19.10.2026 | Синтетика s33–s36 (R-1: s40–s44 заняты треком B #59, s37–s39 резерв) | Рулинг владельца R-1: параллельные треки не конфликтуют по именам файлов набора | Пропуск номеров в наборе |
|
||||
| 19.10.2026 | Новый модуль `indicators.py` вместо правки `hierarchy.resolve_levels` | Трек B меняет каскад иерархии параллельно | Ещё один модуль конвейера |
|
||||
| 19.10.2026 | T1.1: в колонке «Показатели» метка «Вал» без точки = CURRENCY (`^вал\.?$`), хотя в тексте строки (`row`) «Вал» без точки — не метка (материал, AURORA-1663) | В колонке меток закрытый набор | Ложный показатель для метки «Вал» вместо БУ |
|
||||
| 19.10.2026 | T4.1: любая метка колонки «Показатели», кроме «БУ», у строки сразу после «Итого» делает её итоговой строкой-показателем (включая неизвестную метку) | Показатели не должны превращаться в «хвост ниже таблицы»; предупреждение о неизвестной метке выдаёт `read_label` | Неизвестная метка у реальной строки ниже таблицы будет втянута в таблицу |
|
||||
| 19.10.2026 | R-2: трейлер коммитов «Claude Sonnet 5.5» вместо «Claude Opus 5.5» из плана | Атрибуция сессии | Правка трейлеров |
|
||||
| 19.10.2026 | R-3: Task 3 плана (haiku) исполнен sonnet | Проза с рефакторингом | Стоимость |
|
||||
| 19.10.2026 | R-4: мелкие находки T6.1/T6.3 исправлены до записи golden, а не отложены | Golden пишется один раз на исправленном коде | Лишний коммит |
|
||||
| 19.10.2026 | R-5: golden s34 обновлён владельцем вручную после отказа классификатора в `make golden-update` | Снимок s34 — собственный новый снимок ветки; изменилась одна строка (текст предупреждения о неизвестной метке по I-2) | Ручное обновление без агентского ревью diff; diff проверен контроллером: одна строка |
|
||||
|
||||
Решения владельца 19.10.2026 (чат): п. 1 колонка «Показатели» как метки §1.3, НУ без своих проверок; п. 2 «В валюте» →
|
||||
CURRENCY, «Валюта <код>» — строка OTHER в рублях, код валюты не хранится; п. 3 BU по умолчанию с предупреждением — по
|
||||
|
||||
@ -26,20 +26,20 @@
|
||||
таблицы есть числа»; сверка «Итого = корень» берёт первую итоговую строку, которая не показатель.
|
||||
|
||||
#### Scenario: Колонка «Показатели» БУ/НУ
|
||||
- **WHEN** разбирается синтетическая ОСВ `s40` (счёт 02, шапка без «Выводимые данные», колонка «Показа-тели», на каждую
|
||||
- **WHEN** разбирается синтетическая ОСВ `s33` (счёт 02, шапка без «Выводимые данные», колонка «Показа-тели», на каждую
|
||||
строку — «БУ» и «НУ», название объединено на две строки, «Итого» БУ и НУ)
|
||||
- **THEN** строки «БУ» — `data_type = BU`, строки «НУ» — `data_type = NU`, `row_value = "НУ"`, `group_type = OTHER`,
|
||||
родитель — строка «БУ» над ней; `parent_sum_violations = []`, `total_row_matches_root = true`, две строки TOTAL
|
||||
(BU и NU), предупреждения «ниже таблицы» и «вид данных … приняты как БУ» нет, статус `done`
|
||||
|
||||
#### Scenario: Количество, валюта и разницы в колонке «Показатели»
|
||||
- **WHEN** разбирается синтетическая ОСВ `s41` (колонка «Показатели» с метками «Кол.», «Вал.», «ПР», «ВР» и одной
|
||||
- **WHEN** разбирается синтетическая ОСВ `s34` (колонка «Показатели» с метками «Кол.», «Вал.», «ПР», «ВР» и одной
|
||||
неизвестной меткой)
|
||||
- **THEN** «Кол.» — QUANTITY, «Вал.» — CURRENCY, «ПР»/«ВР»/неизвестная — `data_type = null`, все — показатели вне
|
||||
сверки родителя; одно предупреждение `OSV_ROWS` о нераспознанной метке; статус `done`
|
||||
|
||||
#### Scenario: «В валюте» под «Валюта <код>»
|
||||
- **WHEN** разбирается синтетическая ОСВ `s42` (под контрагентом пары «Валюта USD» / «В валюте», «Валюта EUR» /
|
||||
- **WHEN** разбирается синтетическая ОСВ `s35` (под контрагентом пары «Валюта USD» / «В валюте», «Валюта EUR» /
|
||||
«В валюте»)
|
||||
- **THEN** «В валюте» — CURRENCY, родитель — «Валюта …» над ней; контрагент = Σ строк «Валюта …» по рублям;
|
||||
статус `done`
|
||||
@ -104,12 +104,12 @@
|
||||
`account_code_raw` совпадает с родителем, строки исключены из проверки «сумма детей = родитель», статус `done`
|
||||
|
||||
#### Scenario: Шапка без вида данных
|
||||
- **WHEN** разбирается синтетическая ОСВ `s43` (шапка без «Выводимые данные», колонки «Показатели» нет)
|
||||
- **WHEN** разбирается синтетическая ОСВ `s36` (шапка без «Выводимые данные», колонки «Показатели» нет)
|
||||
- **THEN** `header.data_type = null`, у всех строк данных и «Итого» `data_type = BU`, в `warnings` одно `OSV_HEADER` «вид
|
||||
данных в шапке не указан — строки без метки приняты как БУ», статус `done`
|
||||
|
||||
#### Scenario: «Валюта <код>» — обычная строка
|
||||
- **WHEN** в синтетической ОСВ `s42` под контрагентом строка «Валюта USD» с рублёвыми суммами
|
||||
- **WHEN** в синтетической ОСВ `s35` под контрагентом строка «Валюта USD» с рублёвыми суммами
|
||||
- **THEN** `group_type = OTHER`, `data_type` шапки, строка участвует в сверке «сумма детей = родитель»
|
||||
|
||||
### Requirement: Контрольные суммы определяют статус
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user