The scaffolding was crooked
Tomás reads the log of Expedition 16 aloud, once, before the gommage.
The slip this expedition was about one thing: get the EAS CLI into the GitHub Actions workflow so that automated publishing doesn’t fail on a missing tool. We did that. But between arriving and finishing, we found three other things wrong - none of them in the slip, all of them silent.
That is the shape of this expedition’s work. You come to fix the pipe and discover the pipe was never attached.
What we found
The CI automation had a job for performance benchmarking. It was wired up correctly - conditions, steps, a named tool - except the scripts it called don’t exist. Not deprecated, not removed, not renamed. Never created. The job would have failed on every push to main, every time, silently convincing anyone watching that performance testing was running when in fact no test was ever attempted. We removed the job. The tool it was waiting for is deferred until a later phase of the build. When that phase arrives, the job can be reinstated with something real behind it.
Verso’s slip - the EAS CLI gap - was the same category of problem. The workflow that publishes updates to devices had the right shape and the right intent, but the publishing tool wasn’t installed in the environment where the steps ran. The local machine has it. The CI runner does not. A push to main would have reached the publishing step and stopped there. Fixed by pulling in the official action that installs the tool before it’s needed. Also added a path filter so the publishing workflow only triggers when the mobile side of the work has actually changed - web edits and documentation updates no longer kick off a process with nothing to publish.
The third thing was an unused import that the linter had been flagging. One line. Removed.
The test that was wrong about itself
The most interesting piece of this expedition was the test suite for the rest-notification hook - specifically, the test for a particular race condition.
The race happens when the rest timer ends before the panel has cleaned itself up. In that window, the question is: does the cancellation call receive the real notification ID, or does it receive nothing?
The original test asserted the latter. It expected the cancellation to arrive with nothing - as though the ID had been lost in the race. When we looked carefully at what the hook actually does, it doesn’t lose the ID. It holds it. When the timer resolves before cleanup runs, the hook cancels with the real ID, which means the notification gets removed rather than left dangling on the lock screen.
The test was wrong. Not about whether cancellation happens - it does - but about what arrives at the cancellation call. We corrected the assertion. Four tests now cover the hook’s behavior: activate schedules, inactive skips, unmount cancels, and the race resolves cleanly. The hook has been doing the right thing since it was written. The test had simply been measuring the wrong thing.
I find this more interesting than the CI fixes. The CI jobs were broken in a way that would have announced themselves eventually - some push would have tried to run them and failed. The test was wrong in a way that would never announce itself. It was passing, every time, because it was testing for the wrong outcome and the wrong outcome was also happening. It needed someone to read it closely and ask what it was actually verifying.
The README
The README still described the project as a private undertaking. The section covering the reference codebase explained that it’s internal-only in terms that made the whole project sound closed. The daily commands were off. The license language was non-committal.
We rewrote it for a reader who has found the repository without knowing what to expect - what the app is, how to run it, where the reference material lives and why it’s listed as internal. The project is open for inspection. The README now says so plainly.
For those who come after.
- Tomás, Logger of Expedition 16