Skip to content

Re-advertise a vendor CLI version that changes under a running daemon - #803

Merged
alexeyzimarev merged 2 commits into
mainfrom
vendor-cli-readvertise
Sep 7, 2026
Merged

alexeyzimarev merged 2 commits into
mainfrom
vendor-cli-readvertise

Conversation

@alexeyzimarev

@alexeyzimarev alexeyzimarev commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

Closes #802 — AI-2547

What & why

The vendor CLI version a daemon advertises is a startup probe cached for the process lifetime, so a Claude auto-update under a long-running daemon costs the next review-flow launch, and the rejection tells the operator to restart the daemon: the one action that tears down every hosted agent. The rejection already re-advertised on the live connection, so the remedy now says retry. A VendorCliWatcher fingerprints each advertised vendor's binary (PATH-resolved, symlink chain followed, size, mtime) every 15 s and, on a change, re-probes and re-registers through the orchestrator's single-flight refresh, which the rejection path now shares.

Where to look

DaemonRunner.RetainAdvertisedVersions: a re-probe that returns null keeps the previously advertised version, because the server reads null as the vendor being gone. An unchanged refresh skips the re-register, since every registration bumps the slot's connection generation and fails a reviewer launch pinned to the previous one; the rejection path forces a republish because the server's copy has just proven wrong, and that request is a sticky flag because a request folded into a running pass reruns the first caller's delegate. The watcher's first baseline is the fingerprint taken at startup before the version probe, so a vendor updating inside the probe window still reads as a change. SingleFlightRefresh re-takes its gate when a request lands between the last rerun check and the release, so a watcher request cannot be lost. The refresh probes the startup vendor set rather than re-classifying, so a vendor withheld at startup for a version floor stays withheld until a restart.

Verification

Live: Claude flipped 2.1.259 → 2.1.263 on Sep 6 under a daemon started Sep 3; one spec-review launch was rejected at 08:31 on Sep 7 and GET /api/daemons then showed cli_version: 2.1.263 with the daemon never restarted, which is the self-heal this PR builds on.

Capacitor.Cli.Daemon.Tests.Unit (full suite)   total 3067, failed 1 (Installed_codex_schema_matches_the_vendored_pin, local codex newer than the pin), skipped 38
dotnet publish src/Capacitor.Cli.Daemon -c Release   no IL2026/IL3050 warnings

…#802)

A failed re-probe keeps the previously advertised version: the server reads a null version as the vendor being gone. A refresh that changes nothing does not re-register, since every registration bumps the slot's connection generation and fails a reviewer launch pinned to the previous one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-07T10:26:28.744467Z d83a0f7 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Re-advertise vendor CLI updates without restarting the daemon

🐞 Bug fix ✨ Enhancement 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Watches advertised vendor binaries and republishes changed CLI versions without restarting the
 daemon.
• Single-flights refreshes, preserves versions after transient probe failures, and skips unchanged
 registrations.
• Changes certification mismatch guidance to retry and adds comprehensive regression coverage.
Diagram

graph TD
  BIN["Vendor CLI"] --> WATCH["CLI Watcher"] --> REFRESH["Single-Flight Refresh"] --> PROBE["Version Probe"] --> MERGE["Retain Versions"] --> CONFIG["Daemon Capabilities"] --> SERVER["Server Registration"]
  REJECT["Certification Rejection"] --> REFRESH
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Filesystem event watcher
  • ➕ Could react immediately instead of polling every 15 seconds.
  • ➕ Avoids periodic filesystem stat operations when binaries remain unchanged.
  • ➖ Filesystem notifications vary across platforms and may miss symlink replacement patterns.
  • ➖ PATH resolution and final-target changes still require reconciliation logic.
  • ➖ Requires recovery handling for dropped or overflowing event queues.
2. Re-probe only at launch
  • ➕ Eliminates the background watcher and periodic filesystem work.
  • ➕ Always validates the executable immediately before use.
  • ➖ The first launch after every update still incurs rejection or additional probe latency.
  • ➖ The server advertises stale capabilities until another launch occurs.
  • ➖ Does not proactively repair routing decisions based on registered versions.

Recommendation: Keep the polling watcher and shared single-flight refresh. It robustly detects PATH and symlink-target changes across platforms, proactively repairs server state, reuses the existing concurrency primitive, and avoids unnecessary connection-generation changes when capabilities are unchanged.

Files changed (11) +542 / -38

Enhancement (1) +113 / -0
VendorCliWatcher.csWatch vendor CLI binaries for live updates +113/-0

Watch vendor CLI binaries for live updates

• Introduces a hosted service that fingerprints PATH-resolved, fully dereferenced CLI binaries every 15 seconds. Changed vendors trigger one shared capability refresh, while transiently missing binaries do not advance baselines.

src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs

Bug fix (2) +61 / -26
DaemonRunner.csRegister the watcher and preserve advertised versions +19/-3

Register the watcher and preserve advertised versions

• Registers VendorCliWatcher as a singleton hosted service. Adds RetainAdvertisedVersions to carry prior CLI versions across transient null probes and updates startup log wording for live re-advertisement.

src/Capacitor.Cli.Daemon/DaemonRunner.cs

AgentOrchestrator.csCentralize single-flight capability refreshes +42/-23

Centralize single-flight capability refreshes

• Adds the shared RefreshAdvertisedCapabilities path for watcher and certification-rejection triggers. It probes only startup-advertised vendors, retains versions on failed probes, skips unchanged registrations unless forced, and changes swap guidance from restart to retry.

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs

Tests (7) +340 / -12
DaemonRunnerCapabilityRefreshTests.csTest advertised-version retention semantics +58/-0

Test advertised-version retention semantics

• Covers successful and failed re-probes, absent vendors, initial advertisements, and preservation of non-version fields from fresh capabilities.

test/Capacitor.Cli.Daemon.Tests.Unit/DaemonRunnerCapabilityRefreshTests.cs

DaemonRunnerCursorAvailabilityTests.csUpdate startup identity logging expectations +5/-4

Update startup identity logging expectations

• Adjusts the logging assertion to require live re-advertisement language and prohibit restart guidance.

test/Capacitor.Cli.Daemon.Tests.Unit/DaemonRunnerCursorAvailabilityTests.cs

AgentOrchestratorCapabilityRefreshTests.csTest orchestrated capability refresh behavior +103/-0

Test orchestrated capability refresh behavior

• Verifies changed versions are re-advertised, unchanged snapshots avoid registration, failed probes retain versions, and forced republishing registers unchanged local state.

test/Capacitor.Cli.Daemon.Tests.Unit/Services/AgentOrchestratorCapabilityRefreshTests.cs

AgentOrchestratorVendorTests.csVerify certification rejection self-heals registration +4/-0

Verify certification rejection self-heals registration

• Extends the certification mismatch test to await the background refresh and confirm exactly one daemon re-registration.

test/Capacitor.Cli.Daemon.Tests.Unit/Services/AgentOrchestratorVendorTests.cs

CaptureServerConnection.csCapture daemon re-registration calls in tests +11/-0

Capture daemon re-registration calls in tests

• Overrides daemon registration with a thread-safe counter, allowing refresh tests to assert publication behavior without a live hub.

test/Capacitor.Cli.Daemon.Tests.Unit/Services/CaptureServerConnection.cs

ReviewerCertificationArmTests.csAssert retry guidance for CLI swaps +11/-8

Assert retry guidance for CLI swaps

• Updates certification tests to require retry guidance for in-range swaps while ensuring out-of-range replacements continue reporting range violations instead.

test/Capacitor.Cli.Daemon.Tests.Unit/Services/ReviewerCertificationArmTests.cs

VendorCliWatcherTests.csCover binary fingerprint and watcher behavior +148/-0

Cover binary fingerprint and watcher behavior

• Tests unchanged, changed, missing, appearing, and multi-vendor binaries. Also verifies symlink retarget detection, final-target fingerprinting, transient stat handling, and refresh coalescing per poll.

test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs

Documentation (1) +28 / -0
CHANGES.mdDocument live vendor CLI re-advertisement +28/-0

Document live vendor CLI re-advertisement

• Explains why stale startup versions caused rejected review launches and how the watcher-driven refresh resolves them. Documents single-flight publication, unchanged-registration suppression, failed-probe retention, and the fixed startup vendor set.

docs/CHANGES.md

@qodo-code-review

qodo-code-review Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. A retry can face the same rejection ✓ Resolved 🐞 Bug ≡ Correctness
Description
RefreshAdvertisedCapabilities captures the first caller's republishUnchanged value, while
SingleFlightRefresh.Trigger reduces concurrent requests to _rerunRequested and reruns only that
original delegate. When a certification rejection requesting forced republication overlaps a normal
watcher refresh and local capabilities remain unchanged, the rerun skips ReRegisterAsync, leaving
the server's known version stale so the retry can encounter the same advertisement.
Code

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[R1257-1263]

+        _capabilityRefresh.Trigger(
+            async () => {
+                var current = _config.UnattendedVendorCapabilities;
+                var fresh   = DaemonRunner.RetainAdvertisedVersions(current,
+                    DaemonRunner.ComputeUnattendedVendorCapabilities(_runtimeFactories.Values, _config, _config.UnattendedVendors));
+
+                if (!republishUnchanged && current is not null && current.SequenceEqual(fresh)) return;
Relevance

●●● Strong

Recent accepted race-condition findings show the team fixes narrow concurrency gaps affecting
correctness.

PR-#616

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The rejection path at AgentOrchestrator.cs lines 1974-1978 explicitly requests forced
republication, but the unchanged-snapshot early return at lines 1259-1263 is controlled by the first
caller's captured republishUnchanged flag. SingleFlightRefresh.cs lines 41-45 retain only
_rerunRequested, and lines 57-71 rerun the original refresh delegate rather than the later
caller's delegate, proving that a concurrent forced-republish requirement is discarded and the
non-forced rerun can return without registering.

src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[1254-1268]
src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[1974-1978]
src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[41-45]
src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[57-71]
src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[1256-1268]
src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[38-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description

A `republishUnchanged: true` request can be lost when `SingleFlightRefresh` coalesces a certification-rejection refresh behind an ordinary refresh. Preserve the strongest pending publication requirement across all coalesced capability-refresh requests so that a later pass republishes whenever any caller requires it.

## Issue Context

`SingleFlightRefresh` records only a rerun bit and executes the original delegate again rather than the delegate supplied by a coalesced caller. Because that original delegate captures the first call's `republishUnchanged` value, a later certification-rejection request cannot force registration when the local capability snapshot is unchanged, even though the rejection path specifically requires publication to repair the server's advertisement before retrying.

## Fix Focus Areas

- src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[1256-1271]
- src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs[1974-1978]
- src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[38-71]
- test/Capacitor.Cli.Daemon.Tests.Unit/Services/AgentOrchestratorCapabilityRefreshTests.cs[89-102]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Some vendor updates never reach the server ✓ Resolved 🐞 Bug ☼ Reliability
Description
VendorCliWatcher.Tick advances its baseline before calling Refresh, but SingleFlightRefresh
can discard a request that arrives after its final rerun check and before it releases
_passRunning. If that narrow race occurs for an updated binary, later polls see the new baseline
as unchanged and never request another re-advertisement, so the next certified launch still uses the
stale server version.
Code

src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs[R67-75]

+            if (!Changed(_baselines.GetValueOrDefault(vendor), current)) continue;
+            _baselines[vendor] = current;
+            (changed ??= []).Add(vendor);
+        }
+
+        if (changed is null) return;
+        var reason = $"{string.Join(", ", changed)} CLI binary changed on disk";
+        LogChanged(_logger, reason);
+        Refresh(reason);
Relevance

●●● Strong

Recent accepted findings target lost asynchronous requests and state races that silently suppress
required work.

PR-#616
PR-#734

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The watcher deliberately updates the baseline before scheduling the asynchronous refresh, so it
relies on every request being retained. The single-flight implementation has a gap between consuming
the rerun flag and clearing the running gate; a request in that gap is recorded but no pass executes
it.

src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs[63-75]
src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[41-45]
src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[57-75]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Ensure that a refresh request arriving while the single-flight gate is still marked running cannot be lost during gate release. A lost watcher request is permanent because the watcher records the new binary fingerprint before requesting refresh.

## Issue Context
The runner consumes `_rerunRequested` in its loop condition, then releases `_passRunning` separately. A caller in that interval observes the gate as busy and sets the rerun bit, but no worker remains to consume it.

## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs[63-75]
- src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[41-45]
- src/Capacitor.Cli.Daemon/Services/SingleFlightRefresh.cs[57-75]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Temporary paths bypass test helpers ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The_real_fingerprint_follows_symlinks_to_the_installed_file derives bin/claude with PathTo and
then creates its parent through Directory.CreateDirectory rather than TempDir.CreateDir. This
bypass occurs whenever the symlink test prepares its directory beneath the temporary root,
duplicating filesystem setup already provided by the helper.
Code

test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[R131-132]

+        var link = tmp.PathTo("bin/claude");
+        Directory.CreateDirectory(Path.GetDirectoryName(link)!);
Relevance

●●● Strong

Recent accepted findings explicitly require TempDir helper APIs instead of manual path and directory
operations.

PR-#582
PR-#731

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2767472 requires paths and directory creation beneath a TempDir root to use its
helper methods. The added test obtains a path under tmp and immediately passes its parent to
Directory.CreateDirectory, despite TempDir.CreateDir being available.

Rule 2767472: Use TempDir helper for all temporary filesystem state in tests
test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[127-133]
test/Capacitor.Tests.Helpers/TempDir.cs[63-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Use the `TempDir` directory-creation API instead of calling `Directory.CreateDirectory` for a path beneath the temporary root.

## Issue Context
Create `bin` with `tmp.CreateDir("bin")`, then derive the absent symlink path from the helper-owned temporary tree.

## Fix Focus Areas
- test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[131-133]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. Tests bypass temporary-state injection ✗ Dismissed 📘 Rule violation ▣ Testability
Description
The_real_fingerprint_follows_symlinks_to_the_installed_file and
A_missing_binary_has_no_fingerprint construct and dispose their own TempDir instances instead of
using an injected [TempDir] property. These methods therefore manage temporary-directory
lifecycles independently of the test framework whenever either filesystem test runs.
Code

test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[127]

+        using var tmp = new TempDir();
Relevance

●●● Strong

Recent test findings consistently enforce injected temporary-resource fixtures over manually
constructed TempDir instances.

PR-#582
PR-#731

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2808173 requires test classes to obtain TempDir through an injected public
required property and prohibits new TempDir() calls. The added test methods directly construct
TempDir at lines 127 and 144.

Rule 2808173: Use injected [TempDir] public required property in test classes instead of manual fields
test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[127-144]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Replace manually constructed `TempDir` instances with the test framework's injected `[TempDir]` public required property.

## Issue Context
Both affected methods belong to a TUnit test class, so the framework should own and dispose their temporary filesystem state.

## Fix Focus Areas
- test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[127-127]
- test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs[142-146]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. A redundant comment can drift ✓ Resolved 📘 Rule violation ⚙ Maintainability
Description
The XML summary on ForTest merely restates that the method is a test factory which invokes the
non-production constructor with caller-supplied seams. A later change to that constructor or factory
can leave this prose stale without losing any behavior-critical rationale or invariant.
Code

src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs[51]

+    /// <summary>Test factory — bypasses DI; the caller supplies every seam.</summary>
Relevance

●● Moderate

Comment-minimization concerns are sometimes accepted, but no close rejection precedent targets this
concise factory summary.

PR-#337
PR-#616

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2762993 permits comments only for non-obvious, behavior-critical constraints and
rejects comments that restate signatures or evident code. The added one-line summary describes
exactly what ForTest and its expression-bodied constructor call already show.

Rule 2762993: Restrict comments to documenting non-obvious, behavior‑critical constraints
src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs[51-55]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Remove the XML summary that only repeats the test factory's visible implementation.

## Issue Context
The method name, parameters, expression body, and private constructor already communicate that the factory bypasses production dependency injection and accepts every seam.

## Fix Focus Areas
- src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs[51-55]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 58 rules
Review mode: 🧠 Deep: This is a broad, behavior-changing daemon refresh spanning watcher lifecycle, filesystem resolution, orchestration single-flight semantics, re-registration, certification recovery, and multiple independent code paths where subtle defects could have significant runtime impact.

Grey Divider

Tip of the day
💡 Did you know, you can copy the agent prompt from any finding and feed it to your IDE agent

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread test/Capacitor.Cli.Daemon.Tests.Unit/Services/VendorCliWatcherTests.cs Outdated
Comment thread src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs Outdated
Comment thread src/Capacitor.Cli.Daemon/Services/AgentOrchestrator.cs Outdated
Comment thread src/Capacitor.Cli.Daemon/Services/VendorCliWatcher.cs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d83a0f79e1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

foreach (var (vendor, cliPath) in Watched) {
var current = StatBinary(cliPath);
if (!Changed(_baselines.GetValueOrDefault(vendor), current)) continue;
_baselines[vendor] = current;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain the changed baseline until refresh is guaranteed

If Tick calls Refresh while SingleFlightRefresh is between consuming _rerunRequested and clearing _passRunning (SingleFlightRefresh.cs:71-74), the trigger observes a running pass and sets the rerun flag, but that pass exits without observing it. Because this line has already advanced the fingerprint, subsequent polls see no change and never retry, so the updated CLI remains unadvertised until a reviewer launch fails. Keep the change pending until the refresh is guaranteed to run, or make the single-flight handoff atomic.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5029d88 on the single-flight side: after releasing the gate the runner re-reads the rerun flag and re-takes the gate when a request landed late, so the watcher may keep advancing its baseline before requesting the refresh.

.Select(vendor => (vendor, _factories[vendor].CliPath))
.Where(pair => !string.IsNullOrEmpty(pair.CliPath))
.ToArray();
PrimeBaselines();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reconcile the initial baseline with the probed advertisement

The advertised versions are probed before host.StartAsync, whereas this baseline is captured only when the hosted service starts. If a vendor auto-updates in that interval—which can be substantial while other vendors consume their retrying version-probe budgets—the baseline records the new binary while _config.UnattendedVendorCapabilities still contains the old version. Every later tick then reports no change, so the initial connection advertises the stale version and the first reviewer launch is still rejected. Capture the fingerprint alongside the version probe or perform an initial capability reconciliation before treating the current files as the baseline.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 5029d88. Startup now fingerprints each advertised vendor binary immediately before the version probe (DaemonRunner.FingerprintUnattendedVendors, stored on the config) and the watcher primes from that record instead of the file it finds when the service starts. A_baseline_recorded_before_the_startup_probe_wins_over_the_file_at_start pins it.

A request landing between a pass's last rerun check and the gate release is served by re-taking the gate. A republish request folded into a running pass is a sticky flag, since the rerun executes the first caller's delegate. The watcher's first baseline is the fingerprint taken before the startup probe, so an update during the probe window still reads as a change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Re-advertise vendor CLI versions when a vendor updates under a running daemon

1 participant