From 455e9e5b624acdf6cfb9089ae8bef5dcf92dcfdf Mon Sep 17 00:00:00 2001 From: Martin Vogel Date: Thu, 6 Aug 2026 16:49:50 +0200 Subject: [PATCH] diag(daemon): name the cohort path that admits a mismatched build A forced client/daemon build mismatch raises a cohort conflict locally but is ADMITTED on every CI leg, which made the #1388 conflict regression untestable there. Reading the code explains how that is possible: identity comparison happens ONLY in the BUSY branch, i.e. when another process already holds the cohort lifetime lock. When the EX acquire succeeds - no live holder - the participant claims the cohort and NO comparison runs at all, so a mismatched build joins. That is correct behaviour when nothing is running. What is missing is the ability to tell the two apart after the fact: "was the lifetime lock held?" is exactly the question that separates the local run from the CI run, and no log line answered it. This is deliberately observability only - no admission behaviour changes. The next CI run that exercises the path will say which branch it took, and that decides whether the CI daemon simply is not holding the lease (an environment fact) or the lease is being released early (a real bug). Signed-off-by: Martin Vogel --- src/daemon/version_cohort.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/daemon/version_cohort.c b/src/daemon/version_cohort.c index aaa521ff1..f642001db 100644 --- a/src/daemon/version_cohort.c +++ b/src/daemon/version_cohort.c @@ -457,6 +457,14 @@ cbm_version_cohort_status_t cbm_version_cohort_acquire(cbm_version_cohort_manage CBM_PRIVATE_FILE_LOCK_EX, &lease->lifetime); cbm_version_cohort_status_t status = version_cohort_status_from_lock(lock_status); if (status == CBM_VERSION_COHORT_OK) { + /* No live holder: this participant CLAIMS the cohort and NO identity + * comparison happens — a mismatched build is admitted, not refused. + * That is correct when nothing is running, and it is the only path by + * which a mismatched client can join. Name it: "was the lifetime lock + * held?" is exactly what separates a local run (conflict raised) from + * a CI run (client admitted), and it was not observable in any log. */ + cbm_log_info("version_cohort.claimed_unheld", "build", + identity->build_fingerprint ? identity->build_fingerprint : ""); status = version_cohort_claim_new(lease, identity, deadline_ms); } else if (status == CBM_VERSION_COHORT_BUSY) { lock_status =