Follow-up from the #665 review. Non-blocking; #665 was gated and merged on its own merits.
What happens
profile.rs::generated_about_update decides whether to regenerate the kind-0 about from live config:
match (existing_about, existing_generated) {
(None, _) | (Some(_), Some(true)) => Some((live_about, true)),
(Some(_), Some(false) | None) => None,
}
For a seat whose about is stamped about_generated = Some(true) — i.e. every seat we generated the text for — the (Some(_), Some(true)) arm returns Some unconditionally, including when live_about is byte-identical to the text already stored. publish_seller_discoverability_async then calls home::save_config, so every seller boot rewrites config.toml even when nothing changed.
Why it is worth closing
- It is a write with no effect, on a path that runs on every boot. The provenance design is otherwise carefully conservative (unknown provenance is protected, operator text is stamped
Some(false)), and this is the one place it does work it does not need to.
config.toml is shared home state. A buyer daemon and a seller daemon can run against the same home, so a needless read-modify-write on seller boot is a needless opportunity for a lost update. This is not a reported bug — no interleaving is known to lose data today — but the write buys nothing, so the cheapest fix is to not make it.
Suggested fix
Return None when the regenerated text equals what is already stored, so the generated case is a true no-op:
(Some(current), Some(true)) if current == live_about => None,
(None, _) | (Some(_), Some(true)) => Some((live_about, true)),
(Some(_), Some(false) | None) => None,
Note the guard arm must come first, and it should compare against live_about after any clamping (default_seller_about clamps to PROFILE_ABOUT_MAX), otherwise a clamped value will never compare equal to the stored clamped text and the no-op never triggers.
Acceptance
A test that boots the discoverability publish twice against an unchanged config with about_generated = true, and asserts config.toml is not rewritten the second time — mtime is the wrong instrument for this (coarse resolution, and it answers a question next to the one asked); assert on the file's bytes, or on a save-callback count.
Follow-up from the #665 review. Non-blocking; #665 was gated and merged on its own merits.
What happens
profile.rs::generated_about_updatedecides whether to regenerate the kind-0aboutfrom live config:For a seat whose
aboutis stampedabout_generated = Some(true)— i.e. every seat we generated the text for — the(Some(_), Some(true))arm returnsSomeunconditionally, including whenlive_aboutis byte-identical to the text already stored.publish_seller_discoverability_asyncthen callshome::save_config, so every seller boot rewritesconfig.tomleven when nothing changed.Why it is worth closing
Some(false)), and this is the one place it does work it does not need to.config.tomlis shared home state. A buyer daemon and a seller daemon can run against the same home, so a needless read-modify-write on seller boot is a needless opportunity for a lost update. This is not a reported bug — no interleaving is known to lose data today — but the write buys nothing, so the cheapest fix is to not make it.Suggested fix
Return
Nonewhen the regenerated text equals what is already stored, so the generated case is a true no-op:Note the guard arm must come first, and it should compare against
live_aboutafter any clamping (default_seller_aboutclamps toPROFILE_ABOUT_MAX), otherwise a clamped value will never compare equal to the stored clamped text and the no-op never triggers.Acceptance
A test that boots the discoverability publish twice against an unchanged config with
about_generated = true, and assertsconfig.tomlis not rewritten the second time — mtime is the wrong instrument for this (coarse resolution, and it answers a question next to the one asked); assert on the file's bytes, or on a save-callback count.