Land the platform zone's re-aimed anchors in its defect register and journal, where its own pack had moved the targets
This commit is contained in:
parent
ba734199d4
commit
3c6920ad8f
2 changed files with 26 additions and 26 deletions
File diff suppressed because one or more lines are too long
|
|
@ -289,7 +289,7 @@ go version → go1.26.7 ≥ 1.26.6
|
|||
|
||||
| Находка | Чья ошибка | Что сделано | Чем предъявлено |
|
||||
|---|---|---|---|
|
||||
| **F1.** Канон описывал происхождение согласия У́ЖЕ, чем оно есть: «даёт `resume` над поправленным банком» — а `runs.go:470`=`resnapshot := book.BankMoved \|\| book.HasPriorRun` плюс `:579`=`func rebillConsent` дают non-null согласие и на ОБЫЧНОЙ второй покупке книги | моя, в тексте канона | описание расширено до истинной популяции: согласие несёт всякий прогон, идущий с пере-снапшотом, и назван довод, почему вторая покупка — защита, а не аппетит (проекция, выросшая за виденное покупателем, обязана ОТКАЗАТЬ, а не быть купленной молча). Фраза «never by the platform's own restart» оставлена: свип передаёт нули | пере-снято мной по коду до правки; канон разобран YAML-парсером |
|
||||
| **F1.** Канон описывал происхождение согласия У́ЖЕ, чем оно есть: «даёт `resume` над поправленным банком» — а `platform/internal/runs/runs.go:470`=`resnapshot := book.BankMoved` плюс `:579`=`func rebillConsent` дают non-null согласие и на ОБЫЧНОЙ второй покупке книги | моя, в тексте канона | описание расширено до истинной популяции: согласие несёт всякий прогон, идущий с пере-снапшотом, и назван довод, почему вторая покупка — защита, а не аппетит (проекция, выросшая за виденное покупателем, обязана ОТКАЗАТЬ, а не быть купленной молча). Фраза «never by the platform's own restart» оставлена: свип передаёт нули | пере-снято мной по коду до правки; канон разобран YAML-парсером |
|
||||
| **F2.** `progress_lagging` объявлен «Always sent», а в `Run.required` его не было ⇒ клиент, сгенерированный по канону, сделал бы член опциональным — канон противоречил бы себе на одном свойстве | моя | член внесён в `required` (12 вместо 11), рядом — довод и ссылка на зеркальный корректирующий минор `0.13.1` | `requiredOf` парсит канон: `progress_lagging` в required = да, `rebill_consent_micro_usd` = нет (nullable по замыслу) |
|
||||
| **F2⭐ класс, а не случай** | предложение оркестратора, аргумент мой | построен гейт `httpapi.TestEveryAlwaysSentMemberOfARunIsPromisedByTheCanon`: он ходит по ЖСОНу, который провод отдаёт для пустого прогона, и требует, чтобы каждый всегда-посылаемый член был либо в `required`, либо в ИМЕННОМ реестре исключений с причиной. Реестр честен в обе стороны: исключённый член, который канон уже обещает, и исключённый член, которого провод не шлёт, — обе строки краснеют | две посадки каталога: канон перестаёт обещать член · провод переименовывает член |
|
||||
| **F4.** `failureReasonsInDDL` читает миграцию целиком, не различая `+goose Up` и `+goose Down` | моя | условие, при котором вывод перестаёт держаться, дописано в хелпере, и названо лечение (резать файл по маркеру `+goose Down`, а не нацеливать гейт на файл по имени) | по нашему же правилу про выводы в комментариях |
|
||||
|
|
@ -1563,7 +1563,7 @@ re-pass не был запинен) и M26 (ветвь проигравшего)
|
|||
дерево глав · живой прогон), и форма заказа о них не знала: вердикт считался из остатка книги и баланса,
|
||||
а `ErrRunInFlight` жил только у двери. Человек видел `covers_all`, жал и получал 409.
|
||||
|
||||
Сделано: три проверки вынесены в **один предикат** `platform/internal/runs/runs.go:666`=`func startable`,
|
||||
Сделано: три проверки вынесены в **один предикат** `platform/internal/runs/runs.go:689`=`func startable`,
|
||||
у него две привязки РАЗНОЙ авторитетности — `Start` зовёт его под замком книги (решает), `Order` зовёт
|
||||
на опрашиваемом пути (`runs.go:304`, совещательно и заведомо устаревает). Мерило пака — «сколько
|
||||
ОПРЕДЕЛЕНИЙ придётся тронуть, если правило изменится» — выполнено: одно.
|
||||
|
|
@ -1593,7 +1593,7 @@ re-pass не был запинен) и M26 (ветвь проигравшего)
|
|||
|
||||
### `PD-162` — отказ до денег, и вторая дверь, которой ряд не называл
|
||||
|
||||
Проверка каталога книги стоит на допуске ДО холда (`runs.go:707`=`func (s *Service) sourceThere`, зовётся
|
||||
Проверка каталога книги стоит на допуске ДО холда (`platform/internal/runs/runs.go:741`=`func (s *Service) sourceThere`, зовётся
|
||||
из `Start` после предиката книги и перед чтением счёта). ⚠ **Трудности, которую промт объявлял главной,
|
||||
действительно нет** (§4.3 промта): каталог создаётся на интейке ДО строки в БД, а исключение первого
|
||||
прогона принадлежит ЖУРНАЛУ внутри каталога (`journalSize` мапит ENOENT в нулевой офсет) — так что
|
||||
|
|
@ -1619,7 +1619,7 @@ re-pass не был запинен) и M26 (ветвь проигравшего)
|
|||
|
||||
Предикат корня не скопирован, а **вызван**: `books.storageIsThere` стал экспортируемым
|
||||
`platform/internal/books/books.go:606`=`func StorageIsThere(booksDir string) bool`, а «книга под нашим
|
||||
корнем?» — `books.go:594`=`func Owns(booksDir, dir string) bool`; методы остались обёртками в одну
|
||||
корнем?» — `platform/internal/books/books.go:626`=`func Owns(booksDir, dir string) bool`; методы остались обёртками в одну
|
||||
строку. Копия была бы вторым экземпляром правила, у которого первая редакция стоила зоны всех книг
|
||||
хоста — и мутация, ломающая `StorageIsThere`, красит не только мой тест, но и ДВА чужих пина `PD-192`
|
||||
в `internal/books`, что и есть доказательство, что предикат один.
|
||||
|
|
@ -1634,14 +1634,14 @@ re-pass не был запинен) и M26 (ветвь проигравшего)
|
|||
⚠ Ниже — ТОЛЬКО разбор; кода по этому ряду я не написал ни строки.
|
||||
|
||||
**Механика, снятая чтением (адреса пере-сняты сегодня).** `Resume` читает состояние прогона ДО замка
|
||||
книги: `platform/internal/runs/reconcile.go:1702`=`s.Store.ReadRunForResume`, затем
|
||||
`reconcile.go:1663`=`unlock, err := s.lockBook(ctx, l.BookID)`, и только потом судит по `l.Status`
|
||||
книги: `platform/internal/runs/reconcile.go:1804`=`s.Store.ReadRunForResume`, затем
|
||||
`platform/internal/runs/reconcile.go:1815`=`unlock, err := s.lockBook(ctx, l.BookID)`, и только потом судит по `l.Status`
|
||||
(`reconcile.go:1696`) — по значению, прочитанному ДО замка. Из этого следуют два разных проигравших:
|
||||
|
||||
* **проигравший ВНУТРИ окна** (его чтение случилось до коммита победителя) держит устаревший
|
||||
`stopped`, доходит до `reopen`, его вставка `run_attempts` падает на уникальном индексе
|
||||
`run_attempts_run_id_attempt_no_key` → `ErrNoRun` → `Resume` отвечает **прогоном**
|
||||
(`reconcile.go:1736`=`return s.Store.ReadRun(ctx, userID, runID)`), и холд не берётся: транзакция
|
||||
(`platform/internal/runs/reconcile.go:1973`=`return s.Store.ReadRun(ctx, userID, runID)`), и холд не берётся: транзакция
|
||||
откатывается целиком;
|
||||
* **проигравший СНАРУЖИ окна** (его чтение случилось уже после коммита победителя) видит
|
||||
`translating`, падает в `default:` и получает `ErrNotResumable` — «the run cannot be continued: it
|
||||
|
|
@ -1649,7 +1649,7 @@ re-pass не был запинен) и M26 (ветвь проигравшего)
|
|||
|
||||
⇒ **Окно дефекта — НЕ гонка за индекс, а интервал между чтением состояния и взятием замка.** И отсюда
|
||||
же объяснение, почему изолированно тест зелёный, а в полном пакете под нагрузкой красный: замок книги
|
||||
(`platform/internal/runs/bank.go:400`=`func (s *Service) lockBook`) — ВНУТРИПРОЦЕССНЫЙ мьютекс, так что
|
||||
(`platform/internal/runs/bank.go:439`=`func (s *Service) lockBook`) — ВНУТРИПРОЦЕССНЫЙ мьютекс, так что
|
||||
два резюма одного демона идут друг за другом, и под голоданием по процессору горутины стартуют дальше
|
||||
друг от друга — проигравший чаще успевает прочитать уже переведённое состояние. Формулировка в шапке
|
||||
теста («both calls pass the state check together and race for attempt N+1») описывает состояние ДВУХ
|
||||
|
|
@ -2901,7 +2901,7 @@ ratified canon is 0.13.0». Улика: файл-носитель (`internal/htt
|
|||
| `docs/PROGRESS.md`, `docs/architecture/05-decisions-log.md` | **4** | ЧУЖАЯ зона — ушли пингом с готовыми адресами и токенами |
|
||||
|
||||
⭐ **Находка из этого же хода:** экранирование `\|` в ячейке регистра (§4.5) **ломает якорь**, если черта
|
||||
попала в его токен. `PD-422` держал `internal/runs/runs.go:447`=`resnapshot := book.BankMoved || book.HasPriorRun`;
|
||||
попала в его токен. `PD-422` держал `internal/runs/runs.go:470`=`resnapshot := book.BankMoved || book.HasPriorRun`;
|
||||
после экранирования токен перестал совпадать с кодом. Вылечено укорочением токена до
|
||||
`resnapshot := book.BankMoved` (единственный хит в файле). Счёт колонок и сверка токена тянут ячейку в
|
||||
разные стороны — следующий, кто пойдёт экранировать черты, наступит на то же. Ушло пингом.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue