Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec by jrob5756 · Pull Request #445 · microsoft/conductor · GitHub
Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec by jrob5756 · Pull Request #445 · microsoft/conductor · GitHub
Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec by jrob5756 · Pull Request #445 · microsoft/conductor · GitHub
Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec by jrob5756 · Pull Request #445 · microsoft/conductor · GitHub
Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec by jrob5756 · Pull Request #445 · microsoft/conductor · GitHub
Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec by jrob5756 · Pull Request #445 · microsoft/conductor · GitHub
Skip to content

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec - #445

Merged
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict
Aug 16, 2026
Merged

fix(cli): stop --web-bg false-flagging port conflicts on trampoline re-exec#445
Jason Robert (jrob5756) merged 2 commits into
mainfrom
fix/444-web-bg-false-port-conflict

Conversation

@jrob5756

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where --web-bg could fail with a false "Port already in
use" and terminate a healthy background run.

The launch gate's two identity checks both compared against the
spawned process's pid (subprocess.Popen.pid), which is not always
the pid of the process that ends up running the workflow: on a
trampoline sys.executable (e.g. a uv tool install on Windows, the
documented install path) the spawned process re-execs into a different
one. That made the run-record poll never see its own child's record —
surfacing as "did not report a run record within 15 seconds, but is
still running" — and then made the /api/info probe report every port
as held by a foreign process, terminating the healthy child.

The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real
pid forward as the confirmed identity for the port-conflict check. A
PORT_CONFLICT is now only raised when that identity was confirmed;
an unconfirmed mismatch degrades to the existing non-fatal "still
initializing" note. The foreign pid is also captured before the child
is terminated instead of probed after, when it can no longer answer.

Closes#444

Testing

  • tests/test_cli/test_bg_runner.py updated/extended to cover the
    trampoline re-exec identity scenario.

Jason Robertand others added 2 commits August 15, 2026 20:48
…e-exec
The launch gate's identity checks compared against the spawned process's
pid (subprocess.Popen.pid), which isn't always the pid of the process
that ends up running the workflow when sys.executable re-execs into a
different one (e.g. a uv tool install trampoline on Windows). That made
the run-record poll never see its own child's record and made the
/api/info probe report every port as held by a foreign process,
terminating a healthy child with a false "Port already in use".
The run-record poll now also accepts a record whose pid differs from
Popen.pid when the record is fresh, and carries the record's real pid
forward as the confirmed identity for stage two. A PORT_CONFLICT is now
only raised when that identity was confirmed; an unconfirmed mismatch
degrades to the existing "still initializing" note. The foreign pid is
also captured before the child is terminated instead of probed after.
Closes#444
Addresses PR #444 review findings:
- _classify_dashboard_identity no longer falls back to comparing run_id
when the payload reports a usable int pid but this launch's own
child_pid is unconfirmed. That fallback misjudged a resumed run's own
healthy dashboard as FOREIGN (run_id legitimately differs on resume),
suppressing a real workflow_started and stalling conductor resume
--web-bg for the full 30s timeout.
- Added direct unit coverage for all five _classify_dashboard_identity
branches, plus a regression test pinning the deliberate
`elif "started_at" in info` skip for an unconfirmed-FOREIGN payload.
- Added boundary/contract tests for _record_is_fresh at the realistic
near-equal-instant margin (the actual boundary a real writer produces),
including a producer/consumer test using a real RunRecord round-tripped
through write_run_record/read_run_record, and updated the trampoline
freshness e2e test to stamp started_at at the real spawn instant
instead of an artificial +1h offset.
Also applied several review recommendations:
- CHILD_EXITED cleanup no longer deletes a run record without confirming
the owning pid is actually dead, and the previous truthy-or fallback
(`confirmed_child_pid or proc.pid`) is now an explicit `is not None`
check.
- Renamed _run_record_matches_launch to _confirmed_pid_from_record,
returning the confirmed pid (int | None) instead of a bool, removing
both `# type: ignore[union-attr]` comments.
- Removed an unreachable `except TypeError` arm in _record_is_fresh.
- Hardened the real two-process regression test: bounded the handshake
read with a timeout so a hung nested interpreter can't block the
suite, and killed the reparented inner process in `finally` so it no
longer leaks.
- Distinguished proc.pid from the confirmed/record pid in several tests
that previously used equal values for both, so they can no longer pass
merely by coincidence.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jrob5756
Jason Robert (jrob5756) marked this pull request as ready for review August 16, 2026 01:21
@jrob5756
Jason Robert (jrob5756) merged commit c436ab9 into mainAug 16, 2026
11 checks passed
@jrob5756
Jason Robert (jrob5756) deleted the fix/444-web-bg-false-port-conflict branch August 31, 2026 13:35
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant

@jrob5756