From e71447b27de4806f750a1cde56f11588e312dcb1 Mon Sep 17 00:00:00 2001 From: Nils Lehnen <30603423+iderex@users.noreply.github.com> Date: Mon, 24 Aug 2026 21:20:08 +0200 Subject: [PATCH] Record two of the answers the plan's decision issue took Issue #46 collected the questions this plan does not decide by engineering judgement, and all eight were answered on 2026-08-24. Record 0000 says a decision that exists only in an issue is not yet recorded, so an answer sitting in a tracker comment is what this change ends for two of the eight. 0021 records that this board publishes downloadable release artefacts, that they are signed rather than carrying a bare checksum, and that the release notes say they exist for checking this board rather than as something the organisation ships to users. It names the tension with the scope this board opened with instead of resolving it by silence, says the separating sentence depends on being read, and names what publishing costs: signing, checksums, a bill of materials, a vulnerability surface and an expectation of continuity. That is issue #182. 0023 records that a commit on the default branch carries a verified signature, effective as the keys operations#1609 sets up land. It names the costs that arrive after the decision - a key held and rotated, a repair that rebuilds a branch at the end of the work rather than adding a commit at the start, and what is left of the web interface and of automation - and it says plainly that earlier history does not become signed, because a property that holds from a date read as a property of the whole is worse than no property at all. That is issue #184. The two are one change rather than two because they are one key-custody story. Signing a release artefact and signing a commit both need a key held somewhere and rotated eventually, and each record names operations#1609 as where that story lives rather than restating it, so the failure this prevents is two custody stories with two different answers. Both carry the four sections record 0000 fixes, and both name in sections three and four every option the entry rejected with what taking it would have cost. Neither record claims a mechanism: 0023 says the requirement is a branch setting rather than anything in this tree and hands the reader the command that reads the live state, and 0021 says it decides that artefacts are signed and not what checks a signature or what a reader does when the check fails. The gate at this head: go build, go vet and gofmt are silent, every package passes, and the runner reads 20 decision records over its own tree and refuses nothing. Refs #182, #184 Signed-off-by: Nils Lehnen <30603423+iderex@users.noreply.github.com> --- .../0021-what-this-board-publishes.md | 87 ++++++++++++++++++ ...23-signed-commits-on-the-default-branch.md | 88 +++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 docs/decisions/0021-what-this-board-publishes.md create mode 100644 docs/decisions/0023-signed-commits-on-the-default-branch.md diff --git a/docs/decisions/0021-what-this-board-publishes.md b/docs/decisions/0021-what-this-board-publishes.md new file mode 100644 index 0000000..bffbd6c --- /dev/null +++ b/docs/decisions/0021-what-this-board-publishes.md @@ -0,0 +1,87 @@ +# 0021. What this board publishes + +## What was decided + +This board publishes downloadable release artefacts. They are signed. The +release notes say, in the notes themselves rather than only here, that the +artefacts exist for checking this board and are not part of what the +organisation ships to users. + +The reason is the independent-verification argument, which is the whole point of +handing somebody a runner at all. The runner's job is reading a checkout and +reporting what it examined, and somebody who has to build that runner from the +repository they are checking is in a weaker position than somebody who downloads +it. Most people who might want to check this board's claims have no toolchain. +Publishing source only would have cost exactly that, and it would have left the +verification argument resting on the reader trusting the build they made from +the tree under examination. + +The tension with the scope this board opened with is real and is not resolved by +being unwritten. That scope excludes anything a user is asked to install. What +separates the two is who the operator is: somebody checking this repository, +rather than somebody using a media server. The release-notes sentence is what +carries that distinction to the person holding the file, and its weakness is +that it depends on being read. Both halves are stated here so that a later +reader meets the residual rather than the assurance. + +The artefacts are signed rather than published with a bare checksum. A checksum +published next to the file it checksums proves the download arrived intact and +says nothing about who built it, which is the claim somebody verifying this +board actually needs. The keys are the ones operations#1609 sets up for the +working accounts, and that is what makes this one key-custody story rather than +two: record 0023 requires a verified signature on a commit from the same keys. +Where those keys are held and how they are rotated belongs to that issue and is +not restated here, because a custody story written twice is a custody story with +two answers. + +What publishing costs, named rather than discovered later. Signing. Checksums. +A bill of materials. A vulnerability surface, which a repository publishing +nothing does not have. And an expectation of continuity, which is the one that +cannot be withdrawn once somebody is running a version. + +## What it applies to + +Every release this board publishes, from the commit this record lands on, and +the issues that build them: the release workflow, the third-party notices and +bill of materials, the smoke run against a published artefact, and the first +release. + +It does not apply to what an experiment produces. An experiment's prototype is +not published, is not something anybody is asked to install, and leaves this +board by promotion, which is +[0005-how-a-result-leaves.md](0005-how-a-result-leaves.md). + +It decides that the artefacts are signed and does not decide what a signature is +checked with, by whom, or what a reader does when the check fails. A published +signature nobody verifies is a file beside a file. + +## What else was considered + +Publishing source only, with the tool run from a checkout. + +Publishing artefacts with a checksum beside each one and no signature. + +Publishing artefacts with no release-notes sentence separating them from what +the organisation ships to users. + +## What each rejected option would have cost + +Source only costs the reader a toolchain, which most people who would want to +check this board do not have, and it weakens the argument the publishing exists +to make. Somebody who builds the tool from the repository they are checking has +verified that the tree builds, not that the tree is what it claims to be. The +option is cheap for this board and expensive for exactly the person it was +supposed to serve. + +A checksum with no signature costs the claim that matters. It proves the bytes +arrived as they left and nothing about where they left from, so anybody who can +place a file can place a checksum beside it. It is also the cheaper option only +until entry seven of the plan is answered, since a signed commit needs a key +held somewhere regardless, and taking it would have meant writing the custody +story once for commits and discovering later that artefacts needed their own. + +Publishing with no separating sentence costs the scope exclusion its meaning. An +artefact with no such note is read as something the organisation ships, which is +the reading the exclusion was written against, and the cost of correcting that +reading arrives after somebody has already deployed against it. The sentence is +weak because it depends on being read; absent, there is nothing to depend on. diff --git a/docs/decisions/0023-signed-commits-on-the-default-branch.md b/docs/decisions/0023-signed-commits-on-the-default-branch.md new file mode 100644 index 0000000..84c3cbb --- /dev/null +++ b/docs/decisions/0023-signed-commits-on-the-default-branch.md @@ -0,0 +1,88 @@ +# 0023. A commit on the default branch carries a verified signature + +## What was decided + +A commit on the default branch of this board has to carry a verified signature. +It becomes effective as the account keys operations#1609 sets up for the working +accounts land, and not before, because a rule that refuses every merge before +anybody holds a key is a rule that gets turned off rather than followed. + +The reason is that two claims are otherwise collapsed into one. That an account +pushed a commit and that a key signed it are different statements, and only the +second survives somebody else holding the account. Not requiring a signature +costs nothing to operate and rests authorship entirely on the account, which is +one credential and one recovery route away from being somebody else's. + +The costs are real, they arrive later than the decision does, and each of them +lands on somebody who did not take it. They are written here rather than +discovered. + +A key has to be held somewhere and rotated eventually. That is the same key +story record 0021 needs for signed release artefacts, which is why the two +answers were taken together: one custody story, written once, in +operations#1609. + +An unsigned commit anywhere in a branch's history refuses the merge rather than +refusing the commit. So the repair is rebuilding the branch rather than adding +one more commit to it, and it lands at the end of the work rather than at the +start, which is the moment it is most expensive and least expected. + +Edits made through the web interface and anything an automation authors are +signed by the platform's key or not at all. That decides what those routes can +still be used for, and it is a consequence rather than a side effect. + +**Earlier history does not become signed.** This covers what arrives after the +day it takes effect, whatever was intended by setting it, so a reader must not +take a signed default branch for a branch that is signed end to end. Stating +that here is the point: the rule buys a property from a date, and a property +from a date read as a property of the whole is worse than no property at all. + +The requirement is a setting on the branch protection rather than anything in +this tree, so nothing here refuses an unsigned commit and this record does not +claim otherwise. Read the live state rather than trusting this paragraph: + + gh api repos/Flowfin/lab/rules/branches/main --jq '.[].type' + +Neither this board nor the board the quality-parity work targets required a +signature when this was decided, so parity settles nothing here and the ruleset +walk points at this record instead of deciding it. + +## What it applies to + +Every commit reaching the default branch of this board from the day the keys +land, whoever authors it, with no bypass for whoever administers the repository. +A gate with an exception for the person most likely to be in a hurry is not a +gate. + +It applies to the ruleset work that configures it and to the quality-parity +document that walks the ruleset. + +It does not apply to a feature branch, which no ruleset covers, and it does not +apply to anything already in history. + +It decides that a signature is required and does not decide what happens to a +contributor who has no key. This board takes experiments from anybody, so that +question is real rather than hypothetical, and the record answering who may run +an experiment here is where it belongs. + +## What else was considered + +Not requiring a signature at all, and resting authorship on the account. + +Requiring one from the first release onward rather than from the day the keys +land. + +## What each rejected option would have cost + +Resting on the account costs the distinction the whole decision is about. It is +free to operate and it is exactly as strong as the weakest recovery route on one +account, which is not a property this board controls or can measure. The cost is +invisible until the day it is total. + +Tying it to the first release costs the same thing the effective date already +costs, and more of it. A history carrying unsigned commits does not become +signed afterwards, so the later the rule starts the more of the branch it does +not cover, and the release is later than the keys. It also splits the key story +from record 0021 by a stretch of calendar for no gain, since the keys that sign +the release artefacts are the keys that sign the commits, and having them +without using them is a cost already paid and not collected.