Skip to content

I1992 — A rebuild that fails consumes no change: the next request retries it

When a long-lived server's rebuild of its repository picture fails, keep the change it noticed unconsumed, so that a later request retries the load (bounded, not on every request) instead of serving the previous generation until git happens to move again.

DONE wave 0 · p2 · implementation profile · parallel safe

Part of development-runtime — The runtime has a development surface.

Objective

When a long-lived server's rebuild of its repository picture fails, keep the change it noticed unconsumed, so that a later request retries the load (bounded, not on every request) instead of serving the previous generation until git happens to move again.

Why

Found while closing the case 545 flake (fix/ci-flakes-545-and-multicast 79ecdbb944, batch B3 #788): Live::reload (apps/majordomus-cli/src/live.rs, the Err arm of `match built`) records `state.stamp = taken` when App::load fails, so the stamp the failed load was taken under now reads as current. A transient failure — a git process caught mid-write, an index.lock, a manifest saved half-way — therefore makes the server miss the commit that triggered it, and every answer (HTTP, MCP, Cockpit) keeps the old head with a fresh-looking observed_at until some unrelated move. The comment there gives the reason (not to retry a failing load on every request); the cost of that choice is a commit silently not seen. Case 545 now polls for the new head and prints the server's 'would not load' line when it fails, so an occurrence names this path.

Current state

A failed App::load sets the generation's stamp to the stamp it was taken under: the change is consumed, and no request retries the load until the git control files move again.

Desired state

A failed load leaves the generation's stamp as it was and records the failure (stamp and moment) beside it; a request whose stamp equals the failed one retries the load once a bounded interval has passed since that failure, and is served the previous generation (with the failure said) inside it. A stamp that moves again retries at once. The warning names the retry.

Scope

  • apps/majordomus-cli/src/live.rs
  • apps/majordomus-cli/tests
  • test/cases

Out of scope

  • The stamp's watched files (WORKTREE_FILES, COMMON_FILES)
  • The mid-rebuild rule: a request arriving during a rebuild is still served the existing generation

Dependencies

None. This issue is a root of the graph.

Acceptance criteria

  • A load that fails and then would succeed, with no further repository move, is retried after the interval and the next answer carries the new head
  • A load that keeps failing is attempted at most once per interval, not once per request
  • Case 545 still passes; with the retry removed, the new test fails

Validation

  • bin/majordomus plan validate
  • cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib live::
  • MJ_TEST_JOBS=4 bash test/run.sh 545_every_answer_says_when_it_was_observed

Evidence required

  • failed_load_is_retried_test

Evidence

coverstypecommandresultat commit
failed_load_is_retried_testtestcargo test --locked --manifest-path apps/majordomus-cli/Cargo.toml --lib live::test result: ok. 15 passed; 0 failed (run 2026-10-14 between 07:40Z and 07:58Z on master ce5959db59)ce5959d

Timeline

started
2026-10-14T07:59:03Z
verified
—
completed
2026-10-14T07:59:09Z

Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.

Canonical record: .ai/repo/project/issues/I1992.yaml. Read it back with majordomus plan show I1992.

Searches the titles and descriptions of every page this site publishes.