Releasing FLH v1.0: a derived stage summary, a rehearsed rollback and a real-browser smoke

Sirui Liu Lv4

Language: English | 简体中文

FLH v1.0.0 is the first release I treat as finished for personal use: one Docker image with a Go server, SQLite and the React workbench, bound to 127.0.0.1. Most of the release work was not new features. It was making the daily path from question to Concept easy to follow, then checking that an upgrade can be undone and that the packaged app works in a real browser.

My engineering contribution: defining the release gaps, setting the rule that a release check must never touch the daily instance, and deciding which evidence counted before tagging v1.0.0.

Published: 2026-11-08

A stage summary that is derived, never stored

A learning record used to show analysis, feedback and extraction as separate panels. Nothing said which step was pending. Each record now shows Where this record stands: analysis → extraction → Concept decisions, with one Next: action.

The summary is computed on render from reads the page already makes, plus one GET per decided unit. Nothing is persisted, so it cannot disagree with the records. Links now connect a record, the Concept its units are filed under, their source records and AI suggestions, and ← Back returns to the view you left, which stays mounted.

No endpoint, DTO, migration or provider prompt changed. A disposable fixture drives the real server binary against a fake OpenAI-compatible provider and compares read-only SQLite snapshots of every authority table. It passed 43 checks, 0 failures, including a suggestion that goes stale after re-extraction and is refused with 409.

Rehearsing the upgrade against an isolated project

The rehearsal found a real problem before anything else ran. The daily wrapper hard-coded the Compose project name, and compose.yaml hard-coded the image tag. Running flh-daily.sh up with any settings file would have rebuilt the daily image and recreated the daily project.

The fix is an opt-in isolated mode. It needs both a project name and an override file. It refuses the daily project name and any french-learning-hub image, then re-checks the resolved configuration. Without those variables, the command line is byte-identical to before.

The rehearsal then ran with real Docker Compose, 43 PASS, 0 FAIL:

  1. start a pre-release baseline image and seed it with the fixture;
  2. back up, then keep the working image as :before-upgrade;
  3. upgrade to the release candidate; data is byte-identical to the baseline snapshot;
  4. induce a failed upgrade with an unknown server flag;
  5. recover: stop → retag :before-upgrade → restore. The running image is the baseline again, and the data is byte-identical.

This changed the documented rollback. The old guide rebuilt from the previous checkout, and restoring before rebuilding would let the newer image migrate the restored database again. The guide now keeps and retags the known-good image.

The daily container’s ID, state, start time and image were recorded before and after every run, and never changed. An early run that proved nothing (its snapshots were empty) is kept in the report with the fixes it caused.

A browser smoke that refuses to touch the wrong server

The NAS has no browser, so the first smoke script was only syntax-checked. The follow-up added a fail-closed ownership check: before seeding, it proves from live Docker state that 127.0.0.1:PORT belongs to the rehearsal project it created, with the expected compose files, data mount, fake provider and an empty database. Pointing it at :8080 or localhost exits before any request.

Chromium ran in a disposable container. The first five runs failed on harness defects: selectors, an /api prefix, and a race where returning to suggestions re-read the run while the stale phase began. No product defect was found. The final runs passed 36 checks, 0 failures, twice. A controlled-failure probe showed that a failing smoke exits non-zero, keeps its evidence and removes only its own resources. The same workflow later passed on a GitHub-hosted runner.

What v1.0 does not prove

  • The upgrade rehearsal did not migrate a database: both images had migrations 001–013.
  • The fake provider proves mechanics, not model judgment. Real-model suggestion quality is not measured.
  • The smoke ran in Chromium only, at one screen size.
  • There is no authentication; the service stays on loopback behind an SSH tunnel.

Implementation used Claude Code and Codex under my direction, task definitions and review.

Release notes · Daily workflow RC · Upgrade rehearsal · Browser smoke · About me

Release commit.

  • Title: Releasing FLH v1.0: a derived stage summary, a rehearsed rollback and a real-browser smoke
  • Author: Sirui Liu
  • Created at : 2026-11-08 12:00:00
  • Updated at : 2026-11-08 12:00:00
  • Link: https://vanquisher.world/2026/11/08/flh-v1-release/
  • License: This work is licensed under CC BY-NC-SA 4.0.