Back to Ideas 5 min read

The First Real Run Said No

E
EkoHacks Team
·
The First Real Run Said No

Encoding the release, part 6 of 8.

The first time ekohacks release ran against a real repository, for real, it produced this:

ekohacks release 0.4.1
  FAIL changelog entry: no ## 0.4.1 heading in the changelog
  ok version is new
  ok on main
  ok clean working tree
  ok lockfile registry
  ok package smoke
stopped: preflight failed: changelog entry

We count this as the tool's first success, and we mean that without irony. Everything was in place — clean main, unpublished version, healthy lockfile, passing smoke — except the one input our process deliberately keeps human: the changelog entry, the piece of writing that becomes the PR body and the Release notes. The rail refused to start, named the missing piece, and touched nothing. A release tool earns trust by refusing well before it earns trust by shipping.

Then, while writing that entry, a question came up that sounded almost naive:

"So… do we deploy the local main, or origin/main?"

It is the sharpest question anyone had asked about the tool. The answer: what ships is always GitHub's main — the merge happens there, the Release is tagged there, the publish workflow runs there. But the rail builds on the local main: the release branch, the version bump and the PR all start from whatever commit it points at. The entire flow rests on an unstated promise that the two are the same commit.

And nothing checked that promise. Start from a stale local main — a teammate's merged work never pulled — and one of two things happens. The loud one: the release PR conflicts with origin's main, package.json being the classic battlefield, and the rail dies half-done. The quiet one is the frightening one: nothing textually conflicts, the PR merges green, and the published package silently omits work that was already on main. Users install a version that does not contain what everyone believes main contains, and no step of the process ever says a word.

Closing the gap followed the rule from part 1, in order. First the document: RELEASING.md gained a new first line in its "Before cutting" checklist — main matches origin/main, git pull before anything else — merged as its own PR. Then the tool mirrored it, red-first, in five commits: the nulled git learned to answer a configured sync state, an integration test pinned the real behaviour against a bare origin, and preflight grew its seventh check:

  ok on main
  ok in sync with origin
  ok clean working tree

The pattern to keep is not the specific check. It is that the checklist grew the way checklists should: one real question, one real near-miss, one line in the document, one test-first check in the tool. Preflight is not a list of clever ideas. It is a list of afternoons.

Next: What One Real Release Taught Us in an Afternoon.

E

Written by

EkoHacks Team

More from Ideas

·6 min read

What the Nullable Gave Back

One file, seven behaviours held fixed, the database swapped for a Nullable: about 180 times less time inside the tests, and coverage flat to two decimals.

E
EkoHacks Team
·6 min read

Twenty Six More Tests, Four Fewer Behaviours

Removing the mocks grew the suite from 44 tests to 70 and quietly deleted four behaviours, every one of them a failure path. Test count is not coverage.

E
EkoHacks Team
·6 min read

The Best Coverage Number in the Room

Same commit, same spec, same test count. The mocked suite ran 5.6 times faster, covered 3.5 fewer points of real code, and posted the best branch coverage.

E
EkoHacks Team