Skip to content

0.1.0: the schema squashed into one migration per context, and an encryption check that can decide - #99

Merged
kisielewski merged 7 commits into
mainfrom
release/0.1.0
Sep 7, 2026
Merged

0.1.0: the schema squashed into one migration per context, and an encryption check that can decide#99
kisielewski merged 7 commits into
mainfrom
release/0.1.0

Conversation

@kisielewski

Copy link
Copy Markdown
Member

Everything 0.1.0 needs from this repository — and the first CI run this branch has ever had, since ci.yml triggers on main and pull requests only.

The squash

Eight migrations and one became version_0_1_0, named for the release that creates the schema. That is the standing rule from now on: before each release the migrations added since the previous one become one, called version_<major>_<minor>_<patch>. Only unreleased migrations are ever squashed, so no released history row is removed and no released database is stranded.

Carried across by hand: the FileContents block and its SET STORAGE EXTERNAL, which is not an EF entity and no regeneration produces. Dropped on purpose: three column defaults — EvaluationJobs.Releases, EvaluationJobs.Refunds, Instance.ShowHero — each left by an AddColumn backfilling a table that already held rows. A table created in one statement has none, the model declares no default for any of them, and each has a CLR initializer.

Verified by comparing schemas, not by reading the generated file. pg_dump --schema-only of an empty database migrated by the old chain and by the new one: 2610 lines each, 53 tables, 102 indexes, 4 check constraints, 61 foreign keys on both sides. The whole difference is pg_dump's session token, column order inside two tables, and those three DEFAULTs. RunnerTags' '{}'::text[] survives, because that one is in the model. One history row per context afterwards.

docs/RELEASE.md carries the procedure and, with it, the case this release does not exercise: from 0.1.1 the squash is a delta — released migrations stay, the snapshot rolls back to the released state, every backfill decision is made again, and a schema dump stops being the whole proof.

The encryption check could not decide what it was asked

The disk grep behind §13.3's last item was unsound. Measured against SeaweedFS: the object's bytes are on disk, complete and contiguous — od shows all forty-eight characters of the needle — while at that same moment grep finds a forty-four character prefix of it in that very file and not the whole string.

It failed in the dangerous direction. false is what the assertion read as "encrypted", so a store that encrypted nothing would have passed — and the control invented to rule that out was built from the same instrument.

What replaces it asserts what the S3 contract can state: the store takes bucket-default AES256, keeps accepting writes, and reports AES256 for the object. 824 tests pass with none skipped, against 823 and two before.

SeaweedFS skips it for a measured reason rather than a remembered one: 4.43 and 4.45 alike accept PutBucketEncryption, return the rule from GetBucketEncryption, and then fail every write to that bucket.

Images

rustfs 1.0.0-rc.4rc.5: the full suite is identical on either. chrislusf/seaweedfs 4.434.45: the pin had stood two versions back on a comparison confounded by the test above — ten runs showed one failure in five against three in five, that test and nothing else, p = 0.52.

Two comments that had stopped being true

  • CLAUDE.md said the schema was one migration per context; seven had followed the 2026-08-28 squash.
  • ci.yml said the application service has no healthcheck. The image has carried one since 2026-08-09 (d05babc) and --wait reports it Healthy. The polling stays — it asks from the host, through the published port.

Checked locally on 2026-09-07

dotnet build -c Release -warnaserror 0 warnings, 0 errors
dotnet test -c Release 824 passed, 0 skipped, 0 failed
openapi.json vs the running container identical, sha256 79f61ee5…
development stack up, all three services healthy
.env.example vs compose three keys, exact both ways
.env in tree or index none — only .env.example
Directory.Build.props, README docker pull 0.1.0

A Documentation section near the top, linking the sections of
docs.algojudge.pl that document this repository rather than the site's
front page, and saying which reader each half is for: the site is written
for somebody without this source open, and the README is the other half.

The Related repositories bullet no longer repeats which sections those
are, so the fact lives in one place.
Every migration added since the previous release becomes one named
version_0_1_0, in both contexts. Names what a regeneration drops -- the
hand-written FileContents block and three column defaults -- and how the
squashed schema is compared against the chain it replaces.

The rest of the checklist is verified and dated: dependency currency,
.env.example in both directions, no .env, documentation currency, and the
release order Runner then External-Runner then Ops.
Eight migrations and one became version_0_1_0, named for the release that
creates the schema. The FileContents block was carried across by hand; the
three column defaults left behind by AddColumn backfills are gone, which is
what a table created in one statement should have.

Verified by comparing pg_dump of both chains against empty databases: 2610
lines each, 53 tables, 102 indexes, 61 foreign keys, differing only in
column order and those three defaults.
The image has carried a HEALTHCHECK since 2026-08-09, so `--wait` waits for
the application and not merely for the container. The polling stays: it asks
the same question from the host, through the published port.
0.1.0 is the case where nothing has been released and everything collapses
into one CREATE TABLE. From 0.1.1 the squash is a delta: released migrations
stay, the snapshot rolls back to the released state, every backfill decision
is made again, and a schema dump stops being the whole proof.
The disk grep that stood behind §13.3's last item could not decide it.
Measured 2026-09-07 against SeaweedFS: the object's bytes are on disk,
complete and contiguous -- od shows all forty-eight characters of the
needle -- while at that same moment grep finds a forty-four character
prefix of it in that very file and not the whole string.

It failed in the dangerous direction. `false` was what the assertion read
as "encrypted", so a store that encrypted nothing would have passed, and
the control invented to rule that out was built from the same instrument.

What replaces it asserts what the S3 contract can state: the store takes
bucket-default AES256, keeps accepting writes, and reports AES256 for the
object. It runs on the default endpoint, where the old pair only skipped
-- 824 tests pass with none skipped, against 823 and two.

SeaweedFS skips it, and the reason is measured rather than remembered:
4.43 and 4.45 alike accept PutBucketEncryption, return the rule from
GetBucketEncryption, and then fail every write to that bucket.
rustfs rc.4 to rc.5 and seaweedfs 4.43 to 4.45, both pinned in two places,
beside the two NuGet patches that were deliberately not taken.
@kisielewski
kisielewski merged commit 1c4ff41 into main Sep 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant