jwogrady Working notes on tools, and why they earn their place

Set is not the same as works

resolves JRN 26-039

You cannot read a stored secret back. You can only find out whether it works by using it.

I shipped a version that promises nothing today, on purpose, and what stayed with me afterwards was how much of it I had to take on faith right up until the moment it ran.

The job was release automation. A bot watches the commits landing on the main branch, and when it sees enough to be worth naming it opens a pull request that writes the changelog, bumps the version, and cuts the tag. It is a good deal. Setting it up, though, is almost entirely configuration — and configuration is just a pile of claims about what will happen later, sitting in a file, looking exactly as confident when it is wrong.

The first run failed in seven seconds.

A terminal card listing three GitHub Actions runs. The oldest is a failure after 7 seconds, triggered by push. Above it a success after 22 seconds, triggered by workflow_dispatch. Above that the release run, 17 seconds. Below, the failed run's log line: release-please failed: Not Found, linking to the GitHub REST docs for get-a-repository.
Seven seconds to fail, twenty-two to succeed, and the only difference between them was whether a token could see the repository.Screenshot

Not Found, pointing at the documentation page for get a repository. Which is a small masterpiece of an error message, because the repository plainly exists — I was looking at it.

That is GitHub being careful rather than unhelpful. When a token asks about a private repository it has no access to, the API does not say forbidden, because forbidden would confirm the thing exists to somebody who has not earned the right to know. So it says not found instead, and the honest cost of that design is that “your token cannot see this” and “you typed the name wrong” arrive as the same sentence.

Here is the part I actually want to write down, though, because it is not really about GitHub.

The token was stored as an Actions secret. And an Actions secret is write-only — once you put a value in, there is no reading it back, not through the UI, not through the API, not by anyone, which is the entire point of it being a secret. You can confirm that a secret exists. You cannot confirm that it is right.

So “the secret is set” had gone into my notes looking like a finished step, and it is not a step. It is half of one. The other half only happens the first time something tries to use it, which in this case was a release workflow on the main branch.

Set is not the same as works.

And the only reason that seven-second failure landed as an expectation rather than a nasty surprise is that it had been written down beforehand as a thing that had not been verified. Not “done”. Not “configured”. Untested, and here is why I can’t test it. That one bit of bookkeeping is the whole difference between a failure you nod at and a failure that eats an afternoon, and it cost about nine words.

The fix was access on the token. The retry took twenty-two seconds.

Look at the trigger column on that second run, because that is the other thing that paid for itself: workflow_dispatch. A manual run button, added to the workflow earlier for no better reason than a hunch that the first attempt at this would fail on credentials. Without it, retrying a release workflow means pushing another commit to the main branch to make something happen — an empty commit, or a whitespace change, or whatever indignity you can think of — and now your history has a lie in it that exists purely to poke a robot. With it, the retry was one command.

Build the retry path while you are still calm. You are not going to feel like adding it at the moment you need it.

There was a second untestable claim in the same batch, and it is the one I was most braced about.

I wanted the baseline release to be 0.0.0 — a tag that says this exists, it has shipped nothing yet, and this is the line we are going to measure from. That turns out to be a slightly unnatural thing to ask for. The tooling reads a version file seeded at 0.0.0 as meaning “never released”, and a project that has never released gets offered 0.1.0, because the overwhelmingly common case is that your first tag should be your first real version. There is a setting that overrides it. Whether the setting actually wins is not something the documentation can settle for you, and it is not something a dry run tells you either — you find out when the bot opens the pull request and you read the title.

It came up titled release 0.0.0. It held.

One more, and this one genuinely cannot be undone: how the work got merged. The feature branch carried nine commits written in the Conventional Commits style — feat:, docs:, ci: — which is the raw material the changelog is generated from. Squash-merging it would have collapsed all nine into a single commit, and the changelog would have come out one line long, describing nothing. So the work branch was rebase-merged to keep the nine, and the bot’s own release pull request was squash-merged, because that one should be a single commit. Two opposite strategies, twenty minutes apart, both correct.

Get that backwards and the tag still cuts, the release still publishes, and everything looks fine. You just permanently have a changelog that does not say what changed.

So: a baseline exists. What does not exist yet is a deployed site — this is a released version, not a live one, and those are very different claims to make about somebody’s business. I would rather say that plainly here than have it quietly rounded up later.

What I keep arriving at is that the goal is not to eliminate the claims you cannot check. You cannot; some of them are unreadable by design, and that design is protecting you. The goal is to know which ones they are and mark them as they go by. An unverified thing recorded as unverified is a plan. The identical unverified thing recorded as done is a trap you built for yourself, and you will walk into it at speed, three weeks later, with somebody watching.

Seven seconds to fail. Twenty-two to succeed.

Set is not the same as works.