Skip to content

fix: verify ancestry for orphaned intermediate fork (closes #721) - #789

Merged
s2x merged 1 commit into
masterfrom
fix/issue-721-killorphanedintermediatefork-fingerprint
Aug 27, 2026
Merged

s2x merged 1 commit into
masterfrom
fix/issue-721-killorphanedintermediatefork-fingerprint

Conversation

@s2x

@s2x s2x commented Aug 27, 2026

Copy link
Copy Markdown
Member

Description

Closes #721

ProcessInspector::killOrphanedIntermediateFork() fingerprint branch required $parentPid === $fingerprint->pid, but in daemon mode the fingerprint is written by the master itself (MasterWorker::saveMasterPid()) so it names the master PID — never the intermediate's — and the branch never fired. The orphaned daemonize intermediate was only ever killed via the legacy /proc cmdline path, which is unreachable when a fingerprint exists, so daemon intermediates leaked.

Changes

  • src/ProcessInspector.php: keep direct identity check (matchesFingerprint(parentPid, fingerprint)) for the non-daemon/matching-PID case, add ancestry check getParentPid(fingerprint->pid) === parentPid plus a Workerman master title check (isWorkermanMasterTitle()) on the parent, so the hung intermediate is killed only when it really is the parent of the fingerprinted master and looks like a Workerman master (shell in non-daemon mode is not killed). Extract isWorkermanMasterTitle() helper.
  • tests/ProcessInspectorTest.php: add two Linux-only integration tests pinning the two ancestry branches via a real parent → child hierarchy built with a temp script exec'd with WorkerMan: master process title (exec -a) and marker-file synchronisation.
  • CHANGELOG.md: entry under [Unreleased] Fixed for [Bug] killOrphanedIntermediateFork() fingerprint path can never fire in daemon mode — intermediate PID is compared to the master fingerprint #721.

Changelog

Added entry for #721 under [Unreleased] Fixed.

Proof of Work

docs/proof_of_work/0721-killorphanedintermediatefork-ancestry/ — 2 review rounds (review-1.md, review-2.md + 2 code-decision files)

Code Review

  • Passed subagent code review (manual critical review, 2 rounds)
  • Every finding answered (R1 nit fixed, R2 low tracked)

The fingerprint branch in ProcessInspector::killOrphanedIntermediateFork()
required $parentPid === fingerprint->pid, but in daemon mode the
fingerprint is written by the master itself so it always names the
master PID, never the intermediate's — the branch was dead in the
production daemon flow. Add ancestry verification: getParentPid(
fingerprint->pid) === parentPid plus a Workerman master title check
on the parent, so the hung daemonize intermediate is killed only
when it really is the parent of the fingerprinted master and looks
like a Workerman master (shell in non-daemon mode is not killed).
Extract isWorkermanMasterTitle() helper and keep the legacy fallback
via the same helper. Add two Linux-only integration tests pinning
the ancestry branches (kill when title matches, no-kill when title
missing) via a real parent→child hierarchy.

Co-authored-by: OpenCode <opencode@anomalyco.dev>
@s2x s2x self-assigned this Aug 27, 2026
@s2x
s2x merged commit 4aed041 into master Aug 27, 2026
14 checks passed
@s2x
s2x deleted the fix/issue-721-killorphanedintermediatefork-fingerprint branch August 27, 2026 02:58
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.

[Bug] killOrphanedIntermediateFork() fingerprint path can never fire in daemon mode — intermediate PID is compared to the master fingerprint

1 participant