Both halves of the #869 version-coupling gate budget 2.0s for an out-of-process launch of the mosaic CLI (mosaic __lease-capability):
enforcement: PROBE_TIMEOUT_SECONDS = 2.0 in framework/tools/lease-broker/activation_version_gate.py
activation: timeout: 2000 in defaultCapabilityProbe() in src/commands/lease-activation-probe.ts
The CLI is a Node program whose cold start alone measures 2.2–2.3s on a mid-range workstation (sb-it-1-dt, measured 2026-08-13: 2.29s / 2.26s / 2.21s over three runs). On such hosts every probe times out, is treated as NO capability (fail-closed by design), and every mosaic <runtime> launch dies with the misleading "framework/CLI version skew; see #869" message — even though the capability matches exactly ({"name":"lease-runtime-activation","version":1}, rc 0).
Fix
Raise both budgets to 10s (named constant LEASE_CAPABILITY_PROBE_TIMEOUT_MS on the TS side, mirroring comment on both). The timeout only bounds the pathological hang case — the happy path returns as soon as the probe exits — so the larger budget costs nothing on healthy hosts.
Latent test-hermeticity bug exposed by the new budget
_resolve_probe_command() ignored the provided environ and resolved mosaic against the ambientos.environ PATH. So test_returns_none_when_mosaic_is_not_resolvable_on_path (which passes a hermetic environ with a nonexistent PATH) actually spawned the host's real CLI — despite the test class docstring promising it never does — and only passed on hosts where that real probe happened to exceed the old 2s timeout, i.e. it was green because of the bug this PR fixes. Resolution now honors the provided environment's PATH (shutil.which("mosaic", path=environ.get("PATH", "")), fail-closed when absent).
Verification
version_coupling_unittest.py: 15/15, and suite duration drops ~2.1s → ~0.004s, confirming no real process is spawned anymore
lease-activation-probe.spec.ts: 15/15
lease-doctor-check.spec.ts + mutator-gate specs: identical results to clean next (4 acceptance failures in mutator-gate.acceptance.spec.ts pre-exist on 216cd722, STALE_GENERATION vs MUTATOR_UNVERIFIED — unrelated seam)
eslint + prettier clean on changed files; tsc --noEmit emits the identical pre-existing error set as clean next (58 lines, all in tui/)
End-to-end on the affected host: with the patched gate, the real probe passes in 2.19s and mosaic yolo claude -p launches successfully; before the patch, launch failed 100% of the time
## Problem
Both halves of the #869 version-coupling gate budget **2.0s** for an out-of-process launch of the mosaic CLI (`mosaic __lease-capability`):
- enforcement: `PROBE_TIMEOUT_SECONDS = 2.0` in `framework/tools/lease-broker/activation_version_gate.py`
- activation: `timeout: 2000` in `defaultCapabilityProbe()` in `src/commands/lease-activation-probe.ts`
The CLI is a Node program whose **cold start alone measures 2.2–2.3s** on a mid-range workstation (sb-it-1-dt, measured 2026-08-13: 2.29s / 2.26s / 2.21s over three runs). On such hosts every probe times out, is treated as NO capability (fail-closed by design), and **every `mosaic <runtime>` launch dies** with the misleading "framework/CLI version skew; see #869" message — even though the capability matches exactly (`{"name":"lease-runtime-activation","version":1}`, rc 0).
## Fix
Raise both budgets to **10s** (named constant `LEASE_CAPABILITY_PROBE_TIMEOUT_MS` on the TS side, mirroring comment on both). The timeout only bounds the pathological hang case — the happy path returns as soon as the probe exits — so the larger budget costs nothing on healthy hosts.
## Latent test-hermeticity bug exposed by the new budget
`_resolve_probe_command()` ignored the provided `environ` and resolved `mosaic` against the **ambient** `os.environ` PATH. So `test_returns_none_when_mosaic_is_not_resolvable_on_path` (which passes a hermetic environ with a nonexistent PATH) actually **spawned the host's real CLI** — despite the test class docstring promising it never does — and only passed on hosts where that real probe happened to exceed the old 2s timeout, i.e. it was green *because of* the bug this PR fixes. Resolution now honors the provided environment's PATH (`shutil.which("mosaic", path=environ.get("PATH", ""))`, fail-closed when absent).
## Verification
- `version_coupling_unittest.py`: **15/15**, and suite duration drops ~2.1s → ~0.004s, confirming no real process is spawned anymore
- `lease-activation-probe.spec.ts`: **15/15**
- `lease-doctor-check.spec.ts` + mutator-gate specs: identical results to clean `next` (4 acceptance failures in `mutator-gate.acceptance.spec.ts` pre-exist on `216cd722`, `STALE_GENERATION` vs `MUTATOR_UNVERIFIED` — unrelated seam)
- eslint + prettier clean on changed files; `tsc --noEmit` emits the identical pre-existing error set as clean `next` (58 lines, all in `tui/`)
- **End-to-end on the affected host**: with the patched gate, the real probe passes in 2.19s and `mosaic yolo claude -p` launches successfully; before the patch, launch failed 100% of the time
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Dtdjx4Gxude9fwyLezCrhh
The activation/enforcement capability probes (#869 C1/C4) budget 2.0s for
an out-of-process launch of the mosaic CLI, but the CLI's Node cold start
alone measures 2.2-2.3s on a mid-range workstation (sb-it-1-dt,
2026-08-13). Result: every probe timed out, was treated as NO capability
(fail-closed), and every `mosaic <runtime>` launch on such hosts died
with the misleading version-skew message even though the capability
matched exactly. 10s costs nothing on healthy hosts — the happy path
returns as soon as the probe exits; the timeout only bounds hangs.
Also fixes a latent test-hermeticity bug the new budget exposed:
_resolve_probe_command() ignored the provided environ and resolved
`mosaic` against the ambient os.environ PATH, so the "not resolvable on
PATH" unittest actually spawned the host's real CLI — and only passed on
hosts where that real probe happened to exceed the old 2s timeout.
Resolution now honors the provided environment's PATH (fail-closed when
absent); the unittest suite drops from ~2.1s to ~0.004s, confirming no
real process is spawned.
Verified: version_coupling_unittest.py 15/15; lease-activation-probe
spec 15/15; lease-doctor + mutator-gate specs unchanged vs clean next
(4 acceptance failures pre-exist on 216cd722, unrelated seam); eslint +
prettier clean; tsc --noEmit emits the identical pre-existing error set
as clean next. End-to-end on the affected host: patched gate passes the
real probe in 2.19s and `mosaic yolo claude -p` launches successfully.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dtdjx4Gxude9fwyLezCrhh
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Both halves of the #869 version-coupling gate budget 2.0s for an out-of-process launch of the mosaic CLI (
mosaic __lease-capability):PROBE_TIMEOUT_SECONDS = 2.0inframework/tools/lease-broker/activation_version_gate.pytimeout: 2000indefaultCapabilityProbe()insrc/commands/lease-activation-probe.tsThe CLI is a Node program whose cold start alone measures 2.2–2.3s on a mid-range workstation (sb-it-1-dt, measured 2026-08-13: 2.29s / 2.26s / 2.21s over three runs). On such hosts every probe times out, is treated as NO capability (fail-closed by design), and every
mosaic <runtime>launch dies with the misleading "framework/CLI version skew; see #869" message — even though the capability matches exactly ({"name":"lease-runtime-activation","version":1}, rc 0).Fix
Raise both budgets to 10s (named constant
LEASE_CAPABILITY_PROBE_TIMEOUT_MSon the TS side, mirroring comment on both). The timeout only bounds the pathological hang case — the happy path returns as soon as the probe exits — so the larger budget costs nothing on healthy hosts.Latent test-hermeticity bug exposed by the new budget
_resolve_probe_command()ignored the providedenvironand resolvedmosaicagainst the ambientos.environPATH. Sotest_returns_none_when_mosaic_is_not_resolvable_on_path(which passes a hermetic environ with a nonexistent PATH) actually spawned the host's real CLI — despite the test class docstring promising it never does — and only passed on hosts where that real probe happened to exceed the old 2s timeout, i.e. it was green because of the bug this PR fixes. Resolution now honors the provided environment's PATH (shutil.which("mosaic", path=environ.get("PATH", "")), fail-closed when absent).Verification
version_coupling_unittest.py: 15/15, and suite duration drops ~2.1s → ~0.004s, confirming no real process is spawned anymorelease-activation-probe.spec.ts: 15/15lease-doctor-check.spec.ts+ mutator-gate specs: identical results to cleannext(4 acceptance failures inmutator-gate.acceptance.spec.tspre-exist on216cd722,STALE_GENERATIONvsMUTATOR_UNVERIFIED— unrelated seam)tsc --noEmitemits the identical pre-existing error set as cleannext(58 lines, all intui/)mosaic yolo claude -plaunches successfully; before the patch, launch failed 100% of the time🤖 Generated with Claude Code
https://claude.ai/code/session_01Dtdjx4Gxude9fwyLezCrhh