Skip to content

fix(computer): compose again a build another composer recorded before deploying it - #502

Merged
earakely-scale merged 2 commits into
mainfrom
edgararakelyan/fd-5256-a-change-to-a-computers-composition-code-doesnt-recompose-an
Nov 5, 2026
Merged

earakely-scale merged 2 commits into
mainfrom
edgararakelyan/fd-5256-a-change-to-a-computers-composition-code-doesnt-recompose-an

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

A computer env's composed build was reused for as long as the env's own files didn't change. So after an agent-env upgrade that composes differently, deploys silently booted computers composed the old way. On the EC2 Macs, a prepare.sh fix never reached the VM bundles until each env was composed from a fresh state. Now each build's record names the code that composed it, and a deploy composes again a build that other code recorded.

What's in it

The composer's digest on every record (env/envs/computer/utils/composed.py)

  • composition() is a digest of the code that decides what a composed computer holds: env/envs/computer/utils, computers/ (the build files, not their docs), the Lume provider, and the protocol's computer package. It's computed once per process.
  • Record.started and Record.finished write it into each result as composer.
  • stale(result) is true for a result with another digest or none, which covers records from before this change.
  • _rank puts a stale result below everything, so any new result takes its place, even a build that fails.
  • Record.built() leaves stale builds out of the computer it writes.

Deploys, env build and puts compose stale builds again (composer.py, env.py)

  • unstarted and unstarted_or_building, which deploys use, treat a stale record as one no compose started. pending, which env build and puts use, treats it as left to compose. A disk's container is rebuilt with it when it's stale too.
  • deployable_builds never returns a stale build. Where a run's fence keeps a deploy from composing, it refuses for want of a ready build. build_statuses then shows each stale build as ready, by another composer.
  • The deploy says why it composes: "an agent-env that composes differently built it".

Docs: computers/README.md states the rule.

Why this shape

The alternatives were to recompute each build's key at deploy, or to refuse the deploy. Recomputing means staging the whole build context, layers and downloads included, on every deploy. Refusing stops every run after an upgrade until someone rebuilds by hand. A digest of the composing code is cheap at deploy and never boots a stale computer. Its one cost is a recompose after an edit that changes nothing composed.

Builds keep their keys, which already cover what composes them (the provision script, prepare/, the context, the lock), so a recompose reuses an image whose inputs didn't change.

Records from before this change name no composer, so each env composes once after the upgrade.

Tested

  • tst/unit/env/envs, tst/unit/bundle, tst/unit/cli, the Lume provider and serialization tests pass on an EC2 Mac: 2,269 passed. ruff is clean.
  • Two test_disk_recipe.py tests (KVM and the compressed disk's launcher) fail on a Mac host the same way on main.
  • New: a deploy composes again what another composer built, and boots that. Before it, the builds read by another composer and none is deployable.
  • The rank test now covers another composer's ready build, and one that names none, both giving way to a new result.

Linear: FD-5256.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; both previous findings are addressed.

Summary

This PR records which composing code built each computer and rebuilds stale records before deployment.

  • Computer builds from different composer code are refreshed before use.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Read build record] --> B{Current composer?}
  B -->|No| C[Compose again]
  B -->|Yes| D{Needs first-boot probe?}
  C --> D
  D -->|No| G[Boot ready build]
  D -->|Yes| E{Record still matches picked build?}
  E -->|Yes| F[Probe and save result]
  E -->|No| H[Probe picked build without saving result]
  F --> I{Probe passed?}
  H --> I
  I -->|Yes| G
  I -->|No| J[Refuse deploy]
Loading

Reviews (2) · Last reviewed commit: "fix(computer): a first boot probes only ..." · Reviewed by Greptile

…fore it's deployed

Each build's record names the digest of the code that composed it (the composer, the computers' build files, the Lume provider and the protocol's computer package). Deploy, env build and a put treat a build recorded under another digest, or none, as unstarted: it isn't deployable, a new result takes its place even when that one fails, and the deploy says why it composes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale requested a review from a team as a code owner November 5, 2026 16:13
…composer's digest takes executable bits

Greptile's review: a first-boot probe whose record another compose took over (another agent-env's, building) probed that record and stamped it; it now probes the build its deploy picked and records nothing. The digest hashes each file's executable bit, as a build's key does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit 13c6104 into main Nov 5, 2026
83 of 88 checks passed
@earakely-scale
earakely-scale deleted the edgararakelyan/fd-5256-a-change-to-a-computers-composition-code-doesnt-recompose-an branch November 5, 2026 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant