Claiming the whole project means what's stale, not everything built here

after_moving (Pull and Update's shared machinery) gated a post-pull build
on `pulled || is_stale(None)` and then, once open, `claim(&mut inner,
None)` -- which marks every component with a build command regardless of
whether it was the one that moved. `trigger_if_needed(None, ...)` had the
same shape one level up: check is_stale, then hand off to build_now, which
is unconditional by design. So any pull that fetched anything rebuilt
every sibling beside the one that actually changed -- "it tries to update
the compose apk even if nothing was done."

`claim` now takes `only_stale`: false for build_now (a person pressed a
specific button, and staleness has no business overruling that), true for
trigger_if_needed and for the build after_moving runs after a pull.
component_is_stale was already scoped correctly per component; the bug was
building past that answer once any one component tripped it.

MismatchedPairNote also had its own word for the same "behind" freshness
freshnessNote already calls "out of date" -- "older than this build" was a
second name for one measurement, which is what "pulling says something
weird about the compose apk" turned out to be. Reused the existing word.

Regression test: a_pull_touching_one_component_does_not_rebuild_its_sibling.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Sonnet 5 committed 2026-09-06 13:45:45 -04:00
1 parent 663626345a
commit c41c36f25d
3 files changed
+194 -19

No files matched your search

@@ -3146,8 +3146,13 @@ private fun MismatchedPairNote(self: ProjectComponent, others: List<ProjectCompo
if (behind.isEmpty()) return
val names = behind.joinToString(", ") { it.name }
Text(
if (behind.size == 1) "$names is older than this build, so the two would not match."
else "$names are older than this build, so they would not match.",
// "Out of date" rather than "older": that is already the word
// `freshnessNote` uses for this exact freshness ("behind"), and a
// second word for the same measurement reads as a second, weaker
// signal rather than the same one said twice -- worth avoiding
// since this note and that one are drawn from the same field.
if (behind.size == 1) "$names is out of date, so the two would not match."
else "$names are out of date, so they would not match.",
style = MaterialTheme.typography.bodySmall,
color = ActionTone.Caution.color,
)