cut: schema gate — refuse to release an undisclosed querylog schema change
the gate recomputes the previous release tag's ddl fingerprint from the remote peeled object and compares it against the tree's; a change must be disclosed by 'resets your query history' in the version's changelog section. the 0.0.9 reset shipped with an announcement claiming no schema change; this makes the impact mechanical instead of remembered.
This commit is contained in:
@@ -54,3 +54,18 @@ Pure functions unit-tested: semver validation (accept/reject table incl. leading
|
||||
- [ ] `just --list` shows the recipes; `just verify` passes locally.
|
||||
- [ ] `zig build cut -- patch` derives the next version and refuses in preflight on a dirty tree or a missing changelog section, mutating nothing; `zig build cut -- 0.0.9` and `-- banana` refuse naming the three kinds.
|
||||
- [ ] `zig build test` and `-Dintegration` 0 failed; `zig fmt --check` clean.
|
||||
|
||||
## Addendum: the schema gate (post-0.0.9)
|
||||
|
||||
0.0.9 changed the `query_log` DDL and its announcement said nothing about it. `querylog.db` is never migrated: the server stamps `PRAGMA user_version` with a CRC32 of the DDL text, and on a mismatch it renames the file aside and creates an empty one, so the first start after such a release destroys the operator's query history. Nothing in the cut noticed, because nothing in the cut had ever read the schema.
|
||||
|
||||
`schema-gate` is a read-only preflight check beside the others. It compares releases, not commits:
|
||||
|
||||
1. `git ls-remote --tags origin`, and the highest `vMAJOR.MINOR.PATCH` strictly below the version being cut is the previous release. Strictly below, because a rerun may already see the tag it is cutting. What is kept is the OBJECT ID origin published for that tag — the peeled `^{}` commit where there is one — not the tag name: a local tag of the same name can be stale or replaced, and reading its tree would compare against a schema origin never shipped, which passes silently whenever that schema happens to match this one. No such tag PASSES trivially — a first release has nothing to compare against.
|
||||
2. `git show <oid>:src/storage/querylog_schema.zig`, and `extractDdl` recovers the `ddl` constant from that source the way the compiler reads a multiline string: the lines after `pub const ddl: [:0]const u8 =` that begin with `\\`, stripped of indentation and the `\\`, joined with newlines, ending at the `;`. Blank lines and `//` comments may appear before, between and after the `\\` lines and contribute nothing, exactly as the compiler treats them. A test applies the same function to the file on disk and asserts the result fingerprints to `querylog_schema.fingerprint` — that equality is what makes the text scan trustworthy.
|
||||
3. The old DDL goes through `querylog_schema.fingerprintOf`, factored out of the comptime `fingerprint` so the gate and the server share one hash rather than two copies of one expression. The tool imports the schema module (build.zig, `querylog_schema_mod`); only these two decls are referenced, so no SQLite symbol comes with them.
|
||||
4. Equal fingerprints PASS. Different fingerprints require the `## [<v>]` changelog section to contain the literal phrase `resets your query history`; present PASSES, absent is a soft FAIL naming both fingerprints, the phrase and what the change costs.
|
||||
|
||||
Every step that cannot answer — the `ls-remote`, the `git show`, the extraction, an unreadable CHANGELOG.md — is a soft FAIL naming the step. A gate that does not know whether the schema moved must never report that it did not.
|
||||
|
||||
Fixing a FAIL is a sentence in the changelog, not a flag: there is no override, because the only thing the gate asks for is that the release notes be true.
|
||||
|
||||
Reference in New Issue
Block a user