letopis 0.20.0 → 0.20.3

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,146 @@
2
2
 
3
3
  Формат: [Keep a Changelog](https://keepachangelog.com/), версии — semver.
4
4
 
5
+ ## [0.20.3] — 2026-07-31
6
+
7
+ ### Fixed — релиз доезжает до npm
8
+
9
+ 0.20.2 опубликовался на GitHub, но в npm **не уехал**: шаг заметок падал, а из-за `set -e`
10
+ вместе с ним пропускался `npm publish`.
11
+
12
+ Причина оказалась не в правах, а в том, откуда GitHub берёт workflow: для события `release`
13
+ файл читается **из коммита, на который указывает тег**, а не из `main`. Тег `v0.20.2` был
14
+ создан до правки, поэтому все перевыпуски крутили старую версию шага — тот, что ходил в PR-API
15
+ и получал `Resource not accessible by integration`. Исправление доехало только с новым тегом.
16
+
17
+ Сам шаг переписан: тело релиза берётся из `lib/CHANGELOG.md` тем же `scripts/release-notes.mjs`,
18
+ которым собирается описание релизного PR. Зависимости от PR-API нет, из прав нужен только
19
+ `contents: write`. Релиз 0.20.2 удалён как не дошедший до npm — его содержимое здесь, ниже.
20
+
21
+ ## [0.20.2] — 2026-07-31
22
+
23
+ ### Changed — заметки релиза перестали дублироваться
24
+
25
+ Тело GitHub Release собиралось `git-cliff`-ом, то есть из заголовков коммитов — вместо
26
+ осмысленного описания. Теперь текст живёт в одном месте и переиспользуется по цепочке:
27
+
28
+ ```
29
+ lib/CHANGELOG.md (руками) → описание PR → тело релиза → npm
30
+ ```
31
+
32
+ - `release.yml` при публикации ставит в тело релиза **описание релизного PR** `dev→main`. PR
33
+ находится по коммиту, на который указывает тег; не нашёлся или пуст — тело не трогается.
34
+ - Новый `lib/scripts/release-notes.mjs` печатает секцию `## [x.y.z]` **текущей** версии пакета —
35
+ это и есть тело PR:
36
+ `gh pr create … --body "$(cd lib && node scripts/release-notes.mjs)"`.
37
+ Версия берётся из `package.json`, а не из аргумента: иначе можно выпустить заметки одной
38
+ версии под тегом другой. Нет записи для версии — exit 1 с той же подсказкой, что у `check:docs`.
39
+ - `git-cliff` и `cliff.toml` удалены. После перехода на заметки из PR от них оставались только
40
+ аннотация тега и подсказка про bump: первое даёт обычный `git log`, второе избыточно —
41
+ забытый бамп и так виден (тег такой версии уже есть → шаг пропускается → релиза нет).
42
+ Побочно: в job, который делает `npm publish`, больше нет стороннего экшена; из workflow
43
+ осталось только first-party (`actions/checkout`, `actions/setup-node`).
44
+
45
+ - `release.yml` берёт тело релиза **тем же скриптом из CHANGELOG**, а не через PR-API. Первая
46
+ попытка читала описание PR (`gh pr list/view`) и падала `Resource not accessible by
47
+ integration` — GITHUB_TOKEN на release-событии не получает доступ к PR-API этого репозитория,
48
+ и `pull-requests: read` не помог. Из-за `set -e` падал весь job, то есть `npm publish`
49
+ пропускался. Теперь зависимости от PR нет: чекаут стоит на теге, значит CHANGELOG и
50
+ package.json — ровно той версии, что публикуется; из прав нужен только `contents: write`.
51
+
52
+ Тег остался **аннотированным** — в сообщении список коммитов от предыдущего тега
53
+ (`git log --no-merges --pretty='- %s'`), так что `git show <tag>` показывает состав версии.
54
+ Шагов в workflow стало меньше: `tag` 3 (было 6), `release` 6 (было 8).
55
+
56
+ ## [0.20.1] — 2026-07-31
57
+
58
+ ### Fixed — движок схемы больше не отстаёт молча
59
+
60
+ `ddl.sql` растёт аддитивно внутри одной версии движка (в 0.19.0 так появились
61
+ `purge`/`purge_closure`/`purge_account`), а существующая схема этих правок **не получала**:
62
+ приложение обновляло пакет и падало сырым
63
+ `PostgresError: function "v1.booking".purge(...) does not exist`. Обнаружено смоук-тестом
64
+ опубликованного пакета на схеме, накатанной до 0.19.0.
65
+
66
+ - Последняя строка `ddl.sql` штампует метку `COMMENT ON SCHEMA … IS 'letopis ddl_revision=N'`
67
+ (последней — чтобы метка не встала при частично применённом файле). `connect()` сверяет её
68
+ с новой константой `DDL_REVISION` и **один раз на схему за процесс** предупреждает, называя
69
+ команду апгрейда. Предупреждение, а не отказ: правки аддитивны.
70
+ - Апгрейд движка на месте: `up({ upgrade: true })` и `node db/apply.mjs … --upgrade`
71
+ перекатывают **только** `ddl.sql` (сиды не трогаются). Безопасно, потому что файл
72
+ идемпотентен — `CREATE OR REPLACE` у функций, `DROP IF EXISTS` + `CREATE` у триггеров,
73
+ `IF NOT EXISTS` у таблиц/индексов. Механизм существовал, но был недостижим: `applySchema`
74
+ при существующей схеме молча выходил.
75
+ - Ревизия ≠ версия схемы: несовместимая правка структуры таблиц по-прежнему означает смену
76
+ `version` в имени схемы (`v1` → `v2`). README § 10.8a, грабля #18 в шпаргалке.
77
+
78
+ ### Fixed — под `enforceAcl` каждый `db.as()` делал три SELECT вместо одного
79
+
80
+ Словарь `Resource`/`Rule` одинаков для всех субъектов, но снимался на каждый scope — то есть
81
+ в вебе (scope на HTTP-запрос) два лишних запроса к БД на каждый запрос приложения. Теперь
82
+ снимок берётся один раз на подключение и переиспользуется; per-scope остались чтение своего
83
+ аккаунта и компиляция энфорсера (один энфорсер = один субъект — иначе memo отдаст чужое
84
+ решение). Снимок сбрасывает `db.reloadSchema()`. Провал чтения не кэшируется.
85
+
86
+ ### Added — проверки и воспроизводимость
87
+
88
+ - `check:docs` — десятая проверка: маркер `-- DDL_REVISION:` в `ddl.sql`, штамп `COMMENT` и
89
+ константа в `types.ts` обязаны совпадать, а штамп — быть последним выражением файла.
90
+ - `release.yml` — смоук **артефакта** после публикации: пакет ставится из реестра в чистую
91
+ папку, проверяются ESM-импорт, ключевые экспорты и наличие `dist`/`sql`/`scripts` в тарболе.
92
+ Тесты гоняют `lib/src`, а в npm уезжает сборка — сломанные `exports`/`files` иначе
93
+ обнаружил бы первый пользователь.
94
+ - `bench/tenants-seed.mjs` + `bench/isolation.bench.mjs` — многоарендаторный полигон
95
+ (10 аккаунтов, перекос 50 %…0.3 %, 1 млн строк) и цена изоляции. Таблица README § 10.6
96
+ была измерена временным скриптом; попутно из неё убрана колонка «без сужения» — это форма
97
+ SQL, которой в публичном API нет.
98
+ - Тайминги README § 11 перенесены с проанализированного полигона точным сопоставлением по
99
+ коду вызова (151 из 208; остальные — иллюстративные фрагменты, у них добавлена оговорка).
100
+ - Тесты: 198 (было 193 на 0.20.0). Новые — ревизия движка и апгрейд, `ANALYZE` при накате,
101
+ кэш словаря ACL. Каждый проверен негативно.
102
+
103
+ ### Changed — на каждое событие ровно одно действие в Actions
104
+
105
+ Тесты гонялись трижды на одном и том же коммите: прогон от push в `dev`, второй от
106
+ `pull_request` при открытии релизного PR и третий от push в `main` при merge. Причём на merge
107
+ `ci` и `tag` стартовали **одновременно** — тег мог встать раньше, чем закончатся тесты.
108
+
109
+ Контур приведён к одному действию на событие:
110
+
111
+ ```
112
+ push dev → ci (typecheck + check:docs + 198 тестов)
113
+ merge dev→main → tag (аннотированный тег из lib/package.json)
114
+ publish Release → release (описание из PR + npm publish + смоук артефакта)
115
+ ```
116
+
117
+ - `ci.yml` — только `push: dev`. Ни `pull_request`, ни `push: main`: релизный PR и сам merge
118
+ несут ТОТ ЖЕ коммит, что уже проверен на `dev` (ветка всегда пушится до PR). `concurrency` —
119
+ быстрые последовательные пуши в `dev` отменяют предыдущий прогон.
120
+ - `tag.yml` — `push: main`, тегирует сразу: ждать нечего, тесты прошли на `dev`.
121
+ - убраны шаги `npm run build` + `npm pack` с выгрузкой артефакта: тарбол никто не забирал —
122
+ `release.yml` публикует сам (`prepublishOnly` гоняет typecheck + build), а результат
123
+ проверяется смоуком уже из реестра; компиляция дублировала шаг Typecheck. CI — 7 шагов.
124
+
125
+ **Остаётся настройкой репозитория:** branch protection на `main` с обязательной проверкой
126
+ `test`. Без неё запрет «не мерджить на красном» держится на дисциплине: у PR своей проверки
127
+ нет, гарантию даёт зелёный прогон того же SHA на `dev`.
128
+
129
+ ### Changed — флоу релиза: тег с историей, заметки из PR, без сторонних экшенов
130
+
131
+ `tag.yml` ставит **аннотированный** тег: в сообщении — список коммитов от предыдущего тега,
132
+ поэтому `git show <tag>` и GitHub → Tags показывают состав версии без GitHub Release.
133
+
134
+ `release.yml` при публикации ставит в тело релиза **описание релизного PR** `dev→main`: оно
135
+ писалось осмысленно (что и почему, с замерами), в отличие от списка заголовков коммитов. PR
136
+ находится по коммиту, на который указывает тег; если PR не нашёлся или пуст — тело не трогается.
137
+
138
+ Источник версии — `lib/package.json`: тег обязан равняться тому, что уедет в npm. Забытый бамп
139
+ виден сразу — тег такой версии уже существует, шаг пропускается, релиза нет.
140
+
141
+ `git-cliff` и `cliff.toml` (заводились по образцу VP) удалены: после перехода на заметки из PR
142
+ от них оставались только аннотация тега и подсказка про bump — первое даёт обычный `git log`,
143
+ второе избыточно. Побочно ушла и зависимость от стороннего экшена в job, который публикует в npm.
144
+
5
145
  ## [0.20.0] — 2026-07-29
6
146
 
7
147
  ### Fixed — `ANALYZE` при накате схемы: чтения были медленнее на порядок