Build the tail-vocabulary gate the refusal only named: honour escaped pipes, read the register weight from the front, and judge the tail by vocabulary rather than cell count
This commit is contained in:
parent
371f15ff2b
commit
fb1d09be5f
3 changed files with 43 additions and 6 deletions
|
|
@ -13,6 +13,7 @@
|
|||
> ⚠ **Эррата 27.08 (D39.158 п.7):** D39.153 п.7б объявляет «ОСТАТКА-РАТИФИКАЦИИ НЕТ… гейт проверяет полноту ФАЙЛА решений, а не подписей, и ОДИН файл со всем банком его снимает — конфликта с моделью владельца нет». Читать так: диспозиция отвечала на вопрос «снимает ли гейт один файл» (снимает) и верифицировала СОСТАВНОЕ поведение — платформа снимает флаг, движок уходит по авто-ветке. Вопрос «работает ли флажок БЕЗ обхода» ею не закрывался, и заказанное той же строкой 191(б) «ослабить границу самой паузы» исполнено не было. Исполнено D39.158: движковая половина УСТРАНЕНА, не обойдена.
|
||||
> ⚠ **Эррата 27.08-б (D39.158, страница `18-bank-ontology.md`):** названный там класс дефекта «проекция без потребителя и без якоря свежести» на момент ратификации имел ОДИН ярус и не судил носитель с ДВУМЯ писателями и нулём читателей. Дописан второй ярус: расхождение писателей ничем не судится, пока читателя нет, а в день его появления СТАНЕТ семантикой, разрешаемой задним числом по накопленной истории. Найдено платформенной сессией при вычитке приёмки D39.159 (живой член — `PD-396`); правило «у источника РОВНО один писатель» с этого дня читается в обе стороны.
|
||||
> ⚠ **Эррата 27.08-в (D39.158 п.1):** «движок исполняет продуктовую модель сам» сказано без ратифицированной ОГОВОРКИ — правка ОТДЕЛЬНОГО термина через дверь доступна только для mined-термов; правка СИД-терма дверью отклоняется по имени (`internal/membank/decisions.go:359`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка бэклога 192). Ещё три места, где модель шире кода, названы строками: окно глав одним решением не правится (named-узость v1) · банк-экспорт на стопе пуст (224) · «полный останов» — это граница ПЕРЕД редакторской волной, черновая довершается (S16). Найдено вычиткой старшего при ревью D39.159.
|
||||
> ⚠ **Эррата 27.08-г (D39.159 п.8):** отказ от правки `n != shape` СТОИТ, но обоснование было шире истины — «краснит семь ЗАКОННЫХ строк» неверно для двух из них. `PD-99` несла корректно markdown-экранированные черты (виноват был парсер, не строка), а `PD-197` — сырую черту в регексе, которая молча сдвигала ВЕС, потому что он читался с конца, а от конца далеко. Названный там остаточный риск ПОСТРОЕН 27.08 на эмпирике зоны (три молчаливых случая за двое суток): парсер уважает экранирование · вес регистра читается с НАЧАЛА · гейт `tail_vocab` судит словарь хвоста. Проверено подсадкой; числа не сдвинулись. Строка `PD-398` остаётся открытой на отсутствие автоматического пина у самого гейта.
|
||||
|
||||
> ⚠ **Навигация (актуализация 07.08, эра D39.1xx):** append-only-дисциплина (D23.3) означает, что
|
||||
> НЕВЕРНЫЙ ФАКТ внутри старой ноты не переписывается, а получает эрратау — и тогда он опасен ровно
|
||||
|
|
|
|||
|
|
@ -126,8 +126,13 @@ def read(rel: str) -> str:
|
|||
return got.stdout
|
||||
|
||||
|
||||
# `\|` — ЗАКОННОЕ markdown-экранирование: таблица рендерит его как черту внутри ячейки. Наивный
|
||||
# split() его не понимает и дробит строку лишний раз (поймано на PD-99 27.08).
|
||||
CELL_SPLIT = re.compile(r"(?<!\\)\|")
|
||||
|
||||
|
||||
def cells(line: str) -> list[str]:
|
||||
return [c.strip() for c in line.split("|")]
|
||||
return [c.strip() for c in CELL_SPLIT.split(line)]
|
||||
|
||||
|
||||
# ⚠ Колонки читаются С КОНЦА, а не с начала. Первая содержательная ячейка («Хвост»/«Суть») законно
|
||||
|
|
@ -140,7 +145,7 @@ REGISTER_SHAPE = 9 # '' | ID | класс | серьёзность | где |
|
|||
|
||||
def col(line: str, from_end: int) -> str:
|
||||
"""Ячейка, считая с конца: 2 = последняя содержательная, 3 = предпоследняя и так далее."""
|
||||
c = line.split("|")
|
||||
c = CELL_SPLIT.split(line)
|
||||
return c[-from_end].strip()
|
||||
|
||||
|
||||
|
|
@ -148,9 +153,9 @@ def malformed(rows: list, shape: int, what: str) -> list:
|
|||
"""Строка таблицы неожиданной формы — расхождение, а не тихий IndexError."""
|
||||
bad = []
|
||||
for l in rows:
|
||||
n = len(l.split("|"))
|
||||
n = len(CELL_SPLIT.split(l))
|
||||
if n < shape:
|
||||
bad.append(f"{what}: строка «{l.split('|')[1].strip()}» имеет {n - 2} колонок, ожидалось {shape - 2}")
|
||||
bad.append(f"{what}: строка «{cells(l)[1]}» имеет {n - 2} колонок, ожидалось {shape - 2}")
|
||||
return bad
|
||||
|
||||
|
||||
|
|
@ -174,11 +179,40 @@ def backlog(text: str) -> dict:
|
|||
}
|
||||
|
||||
|
||||
# ⚠ Хвостовой словарь — вторая половина PD-398, построена 27.08 по эмпирике трёх случаев за двое
|
||||
# суток (правка PD-396 · первая редакция PD-398 · пере-формулировка PD-398 приёмкой). Счёт ячеек
|
||||
# ловить ИЗБЫТОК не может: `|` внутри первой содержательной ячейки легален и намеренно (см. col()).
|
||||
# Но смягчение «читаем с конца, значит лишняя черта безвредна» ОПРОВЕРГНУТО: когда черта попадает в
|
||||
# одну из трёх ПОСЛЕДНИХ колонок, статус или вес съезжает МОЛЧА — счёт печатает мусорный ключ или
|
||||
# «иное», и никто не смотрит. Поэтому судим не форму, а словарь хвоста.
|
||||
STATUS_VOCAB = ("open", "fixed", "accepted-risk", "closed")
|
||||
WEIGHT_VOCAB = ("major", "minor", "info", "blocker")
|
||||
# Доброкачественные исключения — статус прозой, заведены ДО словаря. Расширять только сознательно:
|
||||
# каждая новая строка здесь — это строка, которую гейт перестал проверять.
|
||||
STATUS_GRANDFATHERED = {"PD-59"}
|
||||
|
||||
|
||||
def tail_vocab(rows: list, what: str) -> list:
|
||||
"""Статус и вес читаются С КОНЦА: лишний «|» в хвосте сдвигает их молча. Судим по словарю."""
|
||||
bad = []
|
||||
for l in rows:
|
||||
pid = cells(l)[1]
|
||||
st = col(l, 3).replace("*", "").strip().lower()
|
||||
if not st.startswith(STATUS_VOCAB) and pid not in STATUS_GRANDFATHERED:
|
||||
bad.append(f"{what}: строка «{pid}» — статус «{st[:40]}» вне словаря "
|
||||
f"(лишний «|» в одной из трёх последних колонок?)")
|
||||
sev = cells(l)[3].replace("*", "").strip().lower()
|
||||
if not any(k in sev for k in WEIGHT_VOCAB):
|
||||
bad.append(f"{what}: строка «{pid}» — вес «{sev[:40]}» вне словаря "
|
||||
f"(лишний «|» в одной из трёх последних колонок?)")
|
||||
return bad
|
||||
|
||||
|
||||
def register(text: str) -> dict:
|
||||
rows = [l for l in text.splitlines() if REGISTER_ROW.match(l)]
|
||||
weight, status, open_ids = Counter(), Counter(), []
|
||||
for l in rows:
|
||||
st, sev = col(l, 3), col(l, 6).replace("*", "")
|
||||
st, sev = col(l, 3), cells(l)[3].replace("*", "")
|
||||
if st.startswith("open"):
|
||||
status["open"] += 1
|
||||
open_ids.append(cells(l)[1])
|
||||
|
|
@ -195,6 +229,7 @@ def register(text: str) -> dict:
|
|||
"вес открытых": dict(weight),
|
||||
"открытые": open_ids,
|
||||
"битая форма": malformed(rows, REGISTER_SHAPE, "регистр"),
|
||||
"хвост вне словаря": tail_vocab(rows, "регистр"),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -570,6 +605,7 @@ def main() -> int:
|
|||
bad.append(f"дубли ID строк бэклога: {b['дубли ID']}")
|
||||
bad.extend(b["битая форма"])
|
||||
bad.extend(r["битая форма"])
|
||||
bad.extend(r["хвост вне словаря"])
|
||||
if not h["порядок = номер"]:
|
||||
bad.append(
|
||||
f"внеочередной аппенд в D-логе: последняя по порядку {h['последняя по порядку файла']}, "
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue