{
  "issue": 285,
  "commit": "88d5cb9ede43a0364b33f9676b20ed91c617dbd7",
  "branch": "fix/285-zombie-identity",
  "worktree": ".worktrees/285-zombie",
  "implementation": [
    "HostedSession captures OS process creation time immediately after PTY spawn, before starting the exit waiter; the AlreadyLive gate carries that remembered stamp.",
    "Zombie reaping now freshly probes death and identity. Provably dead roots proceed to existing bounded cleanup without any numeric tree-kill. Live roots require matching creation time.",
    "Missing PID, unreadable/missing identity, or a changed creation time emits SPAWN_ZOMBIE_REAP_DECLINE and returns an error before forced de-tabling. No fallback session.kill, teardown dispatch, or HostedSession removal occurs after refusal.",
    "Added REQ-BROKER-ZOMBIE-IDENTITY to daemon-process-lifecycle before implementation, evidence-proximate tags, ADR-0041 explanation, relevant hazard note, and Unreleased changelog entry. No exported symbols or shared identity helpers changed."
  ],
  "regression_cells": [
    "broker::tests::zombie_reap_declines_recycled_pid: old zombie predicate accepts the candidate, but injected different birth at the same PID produces identity-mismatch and zero kill calls.",
    "broker::tests::zombie_reap_requires_positive_identity_but_dead_root_needs_no_kill: matching identity permits kill; unknown identity/PID declines; absent root permits cleanup without signaling."
  ],
  "identity_provenance": "The PID comes from the newly spawned PtySession. The creation-time query runs before any waiter can reap that child: Windows retains its process handle; Unix keeps the unreaped child's PID reserved. Expected identity is never reconstructed at reap time. Creation time avoids false mismatch when a launcher execs another image.",
  "design_decision": "Identity refusal retains the old session row for its normal exit waiter rather than forcibly dropping session/PTY resources. This intentionally favors safety over automatic recovery of an unverifiable remembered live-number row. Fresh-dead cleanup and the existing snapshot-less Unix liveness fallback remain available.",
  "verification": "Not run: assignment explicitly forbids builds, cargo, tests, linters, formatters, and other validation. Commit hooks were disabled for the local commit to honor that restriction. No live processes were mutated, no pushes or PRs made. Main must validate before shipping.",
  "focused_verification_commands": [
    "cargo test -p spt-daemon --lib broker::tests::zombie_reap_",
    "cargo test -p spt-daemon --lib broker::tests::zombie_verdict_table -- --exact",
    "cargo test -p spt-daemon --test spawn_truth zombie_client_tree_is_reaped_and_run_succeeds_honestly -- --exact --test-threads=1",
    "cargo test -p spt-daemon --test spawn_truth windows_run_never_refuses_over_a_dead_root_the_broker_holds_a_handle_to -- --exact --test-threads=1",
    "traceable-reqs trace REQ-BROKER-ZOMBIE-IDENTITY",
    "traceable-reqs check --json"
  ],
  "risks": [
    "Numeric kill_pid_tree remains non-atomic with identity verification; root reuse between query and signal and descendant enumeration/kill races remain.",
    "Linux birth stamps have clock-tick resolution, so same-tick PID reuse cannot be distinguished by this guard; Windows uses creation FILETIME.",
    "The existing successful-kill cleanup path remains best-effort and unchanged; this lane specifically blocks cleanup after identity refusal.",
    "CHANGELOG.md adds an Unreleased section; integrate its bullet into the release section Main chooses. Worktree retained for integration."
  ]
}