letopis 0.20.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,92 @@
2
2
 
3
3
  Формат: [Keep a Changelog](https://keepachangelog.com/), версии — semver.
4
4
 
5
+ ## [0.20.1] — 2026-07-31
6
+
7
+ ### Fixed — движок схемы больше не отстаёт молча
8
+
9
+ `ddl.sql` растёт аддитивно внутри одной версии движка (в 0.19.0 так появились
10
+ `purge`/`purge_closure`/`purge_account`), а существующая схема этих правок **не получала**:
11
+ приложение обновляло пакет и падало сырым
12
+ `PostgresError: function "v1.booking".purge(...) does not exist`. Обнаружено смоук-тестом
13
+ опубликованного пакета на схеме, накатанной до 0.19.0.
14
+
15
+ - Последняя строка `ddl.sql` штампует метку `COMMENT ON SCHEMA … IS 'letopis ddl_revision=N'`
16
+ (последней — чтобы метка не встала при частично применённом файле). `connect()` сверяет её
17
+ с новой константой `DDL_REVISION` и **один раз на схему за процесс** предупреждает, называя
18
+ команду апгрейда. Предупреждение, а не отказ: правки аддитивны.
19
+ - Апгрейд движка на месте: `up({ upgrade: true })` и `node db/apply.mjs … --upgrade`
20
+ перекатывают **только** `ddl.sql` (сиды не трогаются). Безопасно, потому что файл
21
+ идемпотентен — `CREATE OR REPLACE` у функций, `DROP IF EXISTS` + `CREATE` у триггеров,
22
+ `IF NOT EXISTS` у таблиц/индексов. Механизм существовал, но был недостижим: `applySchema`
23
+ при существующей схеме молча выходил.
24
+ - Ревизия ≠ версия схемы: несовместимая правка структуры таблиц по-прежнему означает смену
25
+ `version` в имени схемы (`v1` → `v2`). README § 10.8a, грабля #18 в шпаргалке.
26
+
27
+ ### Fixed — под `enforceAcl` каждый `db.as()` делал три SELECT вместо одного
28
+
29
+ Словарь `Resource`/`Rule` одинаков для всех субъектов, но снимался на каждый scope — то есть
30
+ в вебе (scope на HTTP-запрос) два лишних запроса к БД на каждый запрос приложения. Теперь
31
+ снимок берётся один раз на подключение и переиспользуется; per-scope остались чтение своего
32
+ аккаунта и компиляция энфорсера (один энфорсер = один субъект — иначе memo отдаст чужое
33
+ решение). Снимок сбрасывает `db.reloadSchema()`. Провал чтения не кэшируется.
34
+
35
+ ### Added — проверки и воспроизводимость
36
+
37
+ - `check:docs` — десятая проверка: маркер `-- DDL_REVISION:` в `ddl.sql`, штамп `COMMENT` и
38
+ константа в `types.ts` обязаны совпадать, а штамп — быть последним выражением файла.
39
+ - `release.yml` — смоук **артефакта** после публикации: пакет ставится из реестра в чистую
40
+ папку, проверяются ESM-импорт, ключевые экспорты и наличие `dist`/`sql`/`scripts` в тарболе.
41
+ Тесты гоняют `lib/src`, а в npm уезжает сборка — сломанные `exports`/`files` иначе
42
+ обнаружил бы первый пользователь.
43
+ - `bench/tenants-seed.mjs` + `bench/isolation.bench.mjs` — многоарендаторный полигон
44
+ (10 аккаунтов, перекос 50 %…0.3 %, 1 млн строк) и цена изоляции. Таблица README § 10.6
45
+ была измерена временным скриптом; попутно из неё убрана колонка «без сужения» — это форма
46
+ SQL, которой в публичном API нет.
47
+ - Тайминги README § 11 перенесены с проанализированного полигона точным сопоставлением по
48
+ коду вызова (151 из 208; остальные — иллюстративные фрагменты, у них добавлена оговорка).
49
+ - Тесты: 198 (было 193 на 0.20.0). Новые — ревизия движка и апгрейд, `ANALYZE` при накате,
50
+ кэш словаря ACL. Каждый проверен негативно.
51
+
52
+ ### Changed — на каждое событие ровно одно действие в Actions
53
+
54
+ Тесты гонялись трижды на одном и том же коммите: прогон от push в `dev`, второй от
55
+ `pull_request` при открытии релизного PR и третий от push в `main` при merge. Причём на merge
56
+ `ci` и `tag` стартовали **одновременно** — тег мог встать раньше, чем закончатся тесты.
57
+
58
+ Контур приведён к одному действию на событие:
59
+
60
+ ```
61
+ push dev → ci (typecheck + check:docs + 198 тестов)
62
+ merge dev→main → tag (аннотированный тег из lib/package.json)
63
+ publish Release → release (заметки git-cliff + npm publish + смоук артефакта)
64
+ ```
65
+
66
+ - `ci.yml` — только `push: dev`. Ни `pull_request`, ни `push: main`: релизный PR и сам merge
67
+ несут ТОТ ЖЕ коммит, что уже проверен на `dev` (ветка всегда пушится до PR). `concurrency` —
68
+ быстрые последовательные пуши в `dev` отменяют предыдущий прогон.
69
+ - `tag.yml` — `push: main`, тегирует сразу: ждать нечего, тесты прошли на `dev`.
70
+ - убраны шаги `npm run build` + `npm pack` с выгрузкой артефакта: тарбол никто не забирал —
71
+ `release.yml` публикует сам (`prepublishOnly` гоняет typecheck + build), а результат
72
+ проверяется смоуком уже из реестра; компиляция дублировала шаг Typecheck. CI — 7 шагов.
73
+
74
+ **Остаётся настройкой репозитория:** branch protection на `main` с обязательной проверкой
75
+ `test`. Без неё запрет «не мерджить на красном» держится на дисциплине: у PR своей проверки
76
+ нет, гарантию даёт зелёный прогон того же SHA на `dev`.
77
+
78
+ ### Changed — флоу релиза по логике VP
79
+
80
+ `tag.yml` ставит **аннотированный** тег: аннотация несёт changelog коммитов по Conventional
81
+ Commits (`git-cliff`, конфиг `cliff.toml`), так что `git show <tag>` и GitHub → Tags
82
+ показывают состав версии без GitHub Release.
83
+
84
+ `release.yml` при публикации **сам собирает тело релиза**: тот же `git-cliff`, диапазон — от
85
+ предыдущего **опубликованного** релиза до этого тега (черновики и pre-release не считаются,
86
+ поэтому заметки не теряют коммиты между публикациями). Описание релиза писать руками не нужно.
87
+
88
+ Источник версии — `lib/package.json` (тег обязан равняться тому, что уедет в npm); расчёт
89
+ `git-cliff` печатается предупреждением, если бамп забыли.
90
+
5
91
  ## [0.20.0] — 2026-07-29
6
92
 
7
93
  ### Fixed — `ANALYZE` при накате схемы: чтения были медленнее на порядок