Skip to content

feat(cli): show native update progress and drop the rollback point - #1375

Merged
frahlg merged 1 commit into
masterfrom
feat/native-update-progress
Sep 24, 2026
Merged

frahlg merged 1 commit into
masterfrom
feat/native-update-progress

Conversation

@frahlg

@frahlg frahlg commented Sep 24, 2026

Copy link
Copy Markdown
Member

Summary

Fredrik tested ftw update on the home box (v0.132.0-beta.1 → v0.133.0-beta.1). Of its 2 min 33 s, about two minutes went to "Saving rollback point", with no progress shown for the first 1.5 minutes. The settings database there is 410 MB. The request was clearer progress: a bar, MB/s, time left, disk space and paths.

  • The native rollback point goes, as ADR 0007 decision 3 (docs: the owner runs updates; native has no update UI #1373) already says. A native update is three steps: download, check, start. It keeps data in place. Nothing on native could restore the point. The 503 message pointed at ftw-backup, which cannot read it.
  • Core records every finished step in the update status. Each record has Core's own start, end and bytes. The new Core closes the start step when it commits. Without the record, a 24 MB download on a fast network finishes between two polls, and nothing shows it.
  • Disk:
    • Before a download, Core refuses when the install root has less than three times the current release free. That covers the archive, the unpacked release and margin. State and history usually share this disk.
    • /api/version/check reports install_root, install_free_bytes and install_need_bytes.
    • /api/backups reports free_bytes.
  • ftw progress:
    • On a terminal each step has two lines: its name, and a bar with size, rate, time left and elapsed time. When the step ends, both become one ✓ line with duration and average rate, for example ✓ 1/3 Downloading verified Core release 24.0 MB in 0.4s (60.0 MB/s). The bar width follows the terminal, and non-UTF-8 locales get ASCII.
    • In logs and scripts there is one line per step.
    • While following: polling is every 0.5 s. A history migration in the starting Core gets its own bar. After the run, the previous release's directory is named.
    • Disk shortage: ftw update stops before asking Core when there is not enough space.
  • ftw status adds free space for releases and backups. It lists rollback points an older Core left, with size and directory. Core deletes nothing; the owner decides. On the home box they are 906 MB in five points.
  • Why no progress-bar library: I looked at schollz/progressbar, cheggaaa/pb and mpb. None was added, because a plain-line mode for wrappers is needed anyway and the rendering is about 150 lines. golang.org/x/sys was already a dependency and gives the terminal width.

minor changeset, because it removes the rollback point. Owner approval needed.

Tests

  • Go:
    • nativeupdate: space needed equals three times the release; a sparse 8 TiB release is refused.
    • selfupdate: three native steps with recorded phases.
    • cmd/ftw: the new Core records its start step at commit.
    • api: a native update takes no rollback point, manual points are refused, and backups report free space.
    • ftwcli:
      • terminal rendering with bar, rate and ETA on a controlled clock, the ASCII variant, and a quiet phase
      • an update whose phases only Core's record knows
      • a history migration during start
      • a disk-short stop, and status with disk and old points
  • make test, go vet ./..., go build ./..., the release-workflow script tests, and a cross build of ftw-cli for darwin and windows all pass.
  • Web: LANG=C npm test, 654 pass.
  • Local native site on a pty (branch release as v0.132.3-beta.1, sim-sungrow):
    • ftw status shows the new lines.
    • ftw rollback from the published v0.133.0 shows ✓ 1/2 Starting the previous Core once in 2.5s, taken from the branch Core's record.
    • ftw update to the published v0.133.0 shows download and restart. That older target drops the record when it rewrites status, so the CLI falls back to what it saw.
    • ftw backup --output-dir shows the copy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

The rollback point took about two of the two and a half minutes of a
native update on the home box (a 410 MB settings database), and nothing
on native could restore it. ADR 0007 already removes it: a native update
now has three steps (download, check, start) and keeps data in place.
Manual rollback points are refused on native, and the rollback refusal
names ftw rollback and a full backup instead of a tool that could not
read the point.

Core records each finished step with its own timing and bytes in the
update status, and the new Core closes the start step when it commits.
A download that ends between two reads still shows. Before downloading,
Core refuses when the install root has less than three times the
current release free, since state and history usually share that disk.
/api/version/check reports the install root, its free space and that
need; /api/backups reports free space beside the archives.

ftw draws each step on a terminal as its name and a bar with size,
rate, time left and elapsed time, and closes it with one line giving
its duration and average rate. Logs and scripts get one line per step.
It polls every half second, shows a history migration while the new
Core starts, names the previous release's directory, and stops before
asking Core when the disk is short. ftw status adds free space for
releases and backups and lists rollback points an older Core left.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-24T07:35:05.920758Z da73e46 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da73e46caa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
return err
})
return 3 * size, err

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Size the guard from the target release

SpaceNeeded assumes both the next archive and extracted tree are no larger than the current installation, but nothing enforces that assumption: archives may be up to 1 GiB and extraction up to 2 GiB. If a release grows substantially or is accidentally bloated, this check can pass with only 3 * currentSize free and the subsequent extraction can exhaust the filesystem shared with state/history—the exact failure this guard claims to prevent. Base the requirement on target asset/package metadata or a conservative enforced maximum instead.

AGENTS.md reference: AGENTS.md:L66-L68

Useful? React with 👍 / 👎.

Comment on lines +1013 to +1014
if err := manager.CheckSpace(slots.Current); err != nil {
return err

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Let retries reuse an already-installed target

When a restart or trial fails after InstallArchive succeeds, CancelPrepared/Select records the target as LastFailed and deliberately retains its release directory. On a host that initially had only slightly more than the new three-times-current requirement, that retained target consumes roughly one current release's space, so this unconditional check rejects every retry before InstallArchive can take its idempotent existing-target path. Account for an already-installed target, or remove/reuse it before applying the full fresh-install threshold, so recovery from a transient restart failure remains possible.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

@frahlg
frahlg merged commit 3981f1f into master Sep 24, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant