Skip to content

fix(tools): identify a wake source by process identity, not pid alone (#437) - #847

Merged
thomasluizon merged 5 commits into
redesign/mainfrom
fix/ticket-437-wake-identity
Sep 7, 2026
Merged

thomasluizon merged 5 commits into
redesign/mainfrom
fix/ticket-437-wake-identity

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

Closes thomasluizon/orbit-tickets#437

Ticket: orbit-tickets #437

Wake registrations persist the OS process start identity. The final sleep decision now compares that same identity with a fresh OS observation, so a pid recycled after reader validation cannot allow an unattended run to stop. An unreadable final identity blocks sleep while work remains.

Writes still fail soft, legacy registrations still provide no wake evidence, and the Stop exit contract, run record schema, and readiness ledger are unchanged.

Review round 3

Closed P1 thread PRRT_kwDOR5Siws6fwdya in commit 568de8eda81a457c708484a24c41b5ca2807a9b0. The Linux identity probe rejects the complete documented dead-state set, Z, X, and historical x, using a named set and a comment explaining the historical spelling. A dead observation now supplies no identity at either probe.

The regression wake identity: Linux dead states block the real Stop adapter at either probe runs six scenarios through the actual isolated Stop adapter: each of X, x, and Z at the reader, and each after a live reader observation. Only the OS stat boundary and platform selection are replaced. The pid existence probe, registration reader, identity predicate, and Stop decision remain real. It checks the observed states, probe count, exit 2, and missing-wake explanation.

I saw this test red before the fix. With production code unchanged, the four X and x scenarios exited 0, including observations [X, X] and [x, x]; the two existing Z behaviors were controls and already blocked.

The requested three observations were also completed:

  1. A temporary characterization expecting the defective behavior passed against the original guard.
  2. The same characterization failed after the dead-state fix because X and x now blocked.
  3. The final blocking regression passed after restoring its intended expectations. All six scenarios block; a dead reader observation ends after one probe, and a live-to-dead transition ends after two.

Round 3 validation

  • Both changed JavaScript files passed node --check.
  • node .claude/hooks/test-hooks.mjs: all 369 assertions passed.
  • node tools/test-tools.mjs: completed with 1,401 passing checks and two failures, the same CPU-progress and log-progress launcher timing cases recorded in round 2. Both expected the hard-ceiling outcome. The full suite remains failed; this round changes only the Linux dead-state set and its regression.
  • Commit hooks passed. No route, endpoint, or module structure changed, so architecture regeneration does not apply.

Round 3 Linux interface evidence

The proc_pid_stat(5) state table lists Z as zombie, X as dead, and x as dead on Linux 2.6.33 through 3.13. The complete documented character set is R S D Z T t W X x K P I; W has two historical meanings. No other listed value denotes a dead process. The kill(2) contract confirms that signal 0 performs existence and permission checks.

Re-derived the stat layout and boot-id format with these real commands on this host:

wsl.exe -d docker-desktop -- cat /proc/self/stat
wsl.exe -d docker-desktop -- cat /proc/sys/kernel/random/boot_id

Both exited 0. Stat stdout was one record with all 52 fields, followed by a newline. This is the complete positional shape with values replaced and decimal integer types preserved; stat has no JSON keys:

<pid:int> (<comm:string>) <state:char> <ppid:int> <pgrp:int> <session:int> <tty_nr:int> <tpgid:int> <flags:uint> <minflt:uint> <cminflt:uint> <majflt:uint> <cmajflt:uint> <utime:uint> <stime:uint> <cutime:int> <cstime:int> <priority:int> <nice:int> <num_threads:int> <itrealvalue:int> <starttime:uint> <vsize:uint> <rss:int> <rsslim:uint> <startcode:uint> <endcode:uint> <startstack:uint> <kstkesp:uint> <kstkeip:uint> <signal:uint> <blocked:uint> <sigignore:uint> <sigcatch:uint> <wchan:uint> <nswap:uint> <cnswap:uint> <exit_signal:int> <processor:int> <rt_priority:uint> <policy:uint> <delayacct_blkio_ticks:uint> <guest_time:uint> <cguest_time:int> <start_data:uint> <end_data:uint> <start_brk:uint> <arg_start:uint> <arg_end:uint> <env_start:uint> <env_end:uint> <exit_code:int>

State was R; it is field 3, or index 0 after the closing command parenthesis. Starttime is field 22, or index 19 in that same slice. Boot-id stdout was a lowercase hexadecimal UUID plus newline, with this redacted literal format:

00000000-0000-0000-0000-000000000000

The regression retains the captured stat record and mutates only its pid and state; its boot-id fixture was captured by the second command. The documented dead-state values are injected deliberately so the case is deterministic on Windows as well as Linux.

Review round 2

Closed P1 thread PRRT_kwDOR5Siws6fvY3n in commit 41c6c95df00d37972625be314a2f1d3808fcf903: the final liveness decision was pid-only. checkSleepStop now passes the complete registration to isWakeSourceAlive, shared with the reader. The adapter and every rule caller use the new predicate contract.

The regression cases run the actual isolated Stop adapter with a preloaded OS probe seam. The first observation uses the real registered identity. Only the second observation changes its start identity or throws an unreadable-identity error. Each case requires two observations, a matching reader identity, a changed final observation, exit 2, and the missing-wake explanation.

  • wake identity: replaced identity after reader validation blocks the real Stop adapter: I saw this test red before the fix. The unfixed adapter exited 0 after one matching observation; the fixed adapter exits 2 after two observations with different identities.
  • wake identity: unreadable identity after reader validation blocks the real Stop adapter: I saw this test red before the fix. The unfixed adapter exited 0 after one matching observation; the fixed adapter exits 2 after the second observation becomes unreadable.

The three observations were: the existing hook suite passed with the defect present, the new regression assertions failed against unchanged production code, and the hook suite including both regressions passed after the fix.

Validation from round 2

  • node --check passed for all four changed JavaScript modules.
  • node .claude/hooks/test-hooks.mjs passed, including both regressions and the existing identity, legacy, cleanup, and Stop-contract cases.
  • node tools/test-tools.mjs completed with 1,376 passing assertions and two failures: the existing CPU-progress and log-progress launcher timing cases expected the hard-ceiling outcome.
  • Isolated reruns of those same CPU/log workers, configurations, and clocks produced the expected hard-ceiling outcome for both the current code and the pre-fix fed1fdb6 run-state module. This points to timing sensitivity, but the full suite result remains recorded as failed. The isolated comparison was staged outside the repository and changed no test or production code.
  • The tools suite passed the real launcher lifecycle checks: its running registration contained an OS start identity, and its observed wake record was gone after exit. The previous PR body's cleanup verification debt is now covered.
  • node tools/arch-map.mjs regenerated both artifacts with no diff.
  • The commit hooks passed.

External interface evidence

The Windows start-time expression was executed on this machine. It returned a decimal string; its .NET type was System.String. The final predicate reuses this existing OS probe without introducing another OS field.

Reproduce the complete observed Node response with this command, which uses the probe process's own pid and contains no credentials:

node -e 'const {spawnSync}=require("node:child_process"); const r=spawnSync("powershell.exe",["-NoProfile","-NonInteractive","-Command",`(Get-Process -Id ${process.pid} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks.ToString()`],{encoding:"utf8",windowsHide:true,timeout:3000}); process.stdout.write(JSON.stringify(r,null,2))'

Complete observed key set, with values replaced and types retained:

{
  status: number = 0,
  signal: null,
  output: [null, string = "<decimal UTC .NET ticks>\r\n", string = ""],
  pid: number = <child pid>,
  stdout: string = "<decimal UTC .NET ticks>\r\n",
  stderr: string = ""
}

The probe accepts only status 0 and trimmed stdout matching ^\d+$; any other status or malformed output supplies no identity. Identity comparison requires exact string equality. A thrown probe also supplies no identity. The test modifies the real returned stdout, preserving the remaining response keys, rather than inventing a response object.

The Linux source was also read through wsl -d docker-desktop -- sh -c 'cat /proc/self/stat; cat /proc/sys/kernel/random/boot_id'. Both interfaces return scalar text, with no object keys. The stat response contains the pid, parenthesized command, state, and numeric fields; field 22 is the decimal start tick count. The boot id has UUID format. The production probe and Linux test seam keep the existing field positions; the seam changes only field 22. The state check rejects Z; other states retain the existing handling.

Assumptions

  • The work order's explicit request to update hook callers and add regression cases takes precedence over its generic prohibition on changing the test infrastructure; no runner behavior or gate baseline was changed.
  • For round 3, the pass/fail/pass sequence uses a temporary characterization of the defect. The final regression is also run red against unfixed production code before the fix, rather than treating the characterization as regression coverage.
  • The seam is preloaded at the OS boundary instead of adding production injection parameters, so the test also verifies the real adapter's predicate wiring.

Independent verification of both OS start-identity interfaces

Pullfrog asked that the Linux interface evidence be complete and preserved before merge. The
orchestrator re-ran both probes itself rather than relying on the implementing worker's report, and
this is the raw output.

Linux, through WSL

Command, run twice against separate short-lived processes:

wsl.exe -d docker-desktop -- sh -c 'cat /proc/self/stat'

Run A, first 90 characters:

10 (cat) R 9 9 9 34816 9 4194304 50 0 0 0 0 0 0 0 20 0 1 0 136 1736704 210 18446744073709

Run B, first 90 characters:

9 (cat) R 8 9 9 34816 9 4194560 213 0 1 0 0 0 0 0 20 0 1 0 2794 1736704 190 18446744073709

Applying exactly the parsing in tools/lib/run-state.mjs,
stat.slice(stat.lastIndexOf(") ") + 2).trim().split(/\s+/):

index /proc field name run A run B
fields[0] 3 state R R
fields[17] 20 num_threads 1 1
fields[18] 21 itrealvalue 0 0
fields[19] 22 starttime 136 2794
fields[20] 23 vsize 1736704 1736704
fields[21] 24 rss 210 190

Why this confirms the index rather than merely being consistent with it. The two runs are
different processes started at different times. starttime is the only column that moves as a start
time should (136 then 2794), while vsize is byte-identical at 1736704 across both, which is what a
constant per-binary field looks like for the same cat, and num_threads stays 1. A wrong index
would have to land on a field that happens to vary the same way and leave vsize where it is; it
does not. /^\d+$/.test(fields[19]) is true in both runs.

The slice-after-") " approach is also the right one for this file, because the second field is the
parenthesized command and can itself contain spaces and parentheses. Splitting the whole line on
whitespace would shift every index for such a process.

Boot id, same host:

9d47a387-d487-457a-91ef-472ccc9486f0

36 characters, matching the /^[0-9a-f-]{36}$/ guard in the implementation.

Windows

powershell.exe -NoProfile -NonInteractive -Command "(Get-Process -Id 4276).StartTime.ToUniversalTime().Ticks.ToString()"
639243321953634446

A bare decimal digit string, matching the /^\d+$/ guard.

One behaviour worth recording, because the implementation depends on it: the same command against a
pid that does not exist does not return an empty string, it throws. Observed verbatim, on a
Portuguese-locale host:

Nao e possivel chamar um metodo em uma expressao de valor nulo.

Get-Process -ErrorAction Stop fails, .StartTime is then called on null, and PowerShell raises. So
the probe's result.status === 0 test is what rejects a dead pid, and the regex is a second guard
rather than the first. The error text is localized, so nothing may ever parse it.

What this does and does not establish

  • It establishes the field index, the parsing strategy, the boot-id shape and the Windows tick
    format against real output from both platforms.
  • It does NOT establish behaviour across a reboot, which is what pairing starttime with boot_id
    is there to cover, and which no single-session run can show.

@vercel

vercel Bot commented Sep 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
orbit-ui-mobile-web Ignored Ignored Sep 7, 2026 1:17am UTC

Request Review

@pullfrog

pullfrog Bot commented Sep 6, 2026 •

Copy link
Copy Markdown

Pullfrog stalled — likely cause: provider usage limit reached

The agent stopped emitting events for 125s and was killed by the activity-timeout watchdog. 100 events were processed before the failure.

Recent agent stderr
timestamp=2026-09-06T21:09:44.306Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:09:46.738Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:09:51.302Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:09:59.741Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:10:16.425Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:10:49.479Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:11:54.064Z level=ERROR run=65516c10 message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f8771cd93ffeFV3BdFtmLq4Lae small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using GPT Sol | 𝕏

@pullfrog

pullfrog Bot commented Sep 6, 2026

Copy link
Copy Markdown

Pullfrog stalled — likely cause: provider usage limit reached

The agent stopped emitting events for 120s and was killed by the activity-timeout watchdog. 100 events were processed before the failure.

Recent agent stderr
timestamp=2026-09-06T21:33:48.282Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:33:50.944Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:33:55.299Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:34:04.023Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:34:20.437Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:34:52.930Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"
timestamp=2026-09-06T21:35:57.443Z level=ERROR run=8b47fa2c message="stream error" providerID=openai modelID=gpt-5.6-sol session.id=ses_f875bc457ffeH4s3thKg485gs4 small=false agent=build mode=primary error.error="AI_APICallError: The usage limit has been reached"

Pullfrog  | Rerun failed job ➔ | View workflow run | via Pullfrog | Using GPT Sol | 𝕏

@pullfrog pullfrog 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.

Important

The wake-source decision still has a PID-reuse race, and the new OS interfaces need durable evidence before this can merge.

Reviewed changes I reviewed the full six-file PR delta because no prior Pullfrog review exists; the synchronization merged redesign/main without changing that delta.

  • Persisted OS start identities. Wake-source records now bind launcher PIDs to Windows start-time ticks or Linux boot-and-start-time values.
  • Filtered stale registrations. The reader now rejects mismatched, legacy, malformed, inaccessible, and proven-dead wake-source records.
  • Exercised wake-source lifecycle paths. The tool and hook harnesses now cover registration, identity mismatch, legacy records, dead-record sweeping, and launcher cleanup.
  • Merged the current base. The synchronized merge commit brought in redesign/main without modifying the PR's six changed files.

⚠️ External interface evidence is not durable

The implementation parses new PowerShell and Linux process-metadata outputs, but the PR body contains neither the real invocations nor their complete observed shapes. The source comment that both were read cannot preserve or re-derive that evidence for review.

Technical details
# Preserve evidence for the process-identity interfaces

## Affected sites
- tools/lib/run-state.mjs:123-136 — reads PowerShell process output and Linux `/proc` fields using newly introduced formats
- PR #847 body — contains no command, complete observed output, installed-source reference, or prior-PR citation for those formats

## Required outcome
- Add independently reproducible evidence for every newly parsed external value to the PR body, including exact redacted commands and complete outputs with literal timestamp/tick formats preserved, or cite the prior PR that established each shape.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Sol | 𝕏

Comment thread tools/lib/run-state.mjs Outdated

@pullfrog pullfrog 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.

Important

The final PID-reuse race is fixed, but the Linux interface evidence is still incomplete and must be preserved before merge.

Reviewed changes I reviewed the substantive commit added after the prior Pullfrog review at fed1fdb6:

  • Rechecked final process identity. Passed each complete wake registration through isWakeSourceAlive so the sleep decision compares the stored identity with a fresh OS observation.
  • Added deterministic final-probe regressions. Exercised the actual isolated Stop adapter with a matching reader observation followed by either a replaced or unreadable identity.
  • Expanded external-interface and validation evidence. Recorded the complete Windows spawnSync response, Linux reproduction command, regression behavior, and current harness results in the PR body.

⚠️ Linux process response is not preserved

The PR body now gives the exact WSL command, but it summarizes the two scalar responses instead of pasting the complete observed /proc/self/stat and boot_id stdout. Without that response, the field-22 layout remains an assertion rather than durable evidence of the interface the parser consumes.

Technical details
# Preserve the complete Linux process-identity response

## Affected sites
- PR #847 body, `External interface evidence` — gives a prose description of the Linux response but no complete observed output

## Required outcome
- Paste the complete two-line observed stdout with values replaced while preserving every `/proc/self/stat` field in order and the literal boot-ID format.
- Keep the existing credential-free reproduction command beside that response.

Pullfrog  | Fix it ➔ | View workflow run | Using GPT Sol | 𝕏

@thomasluizon

Copy link
Copy Markdown
Owner Author

Independent verification of both OS start-identity interfaces

Pullfrog asked that the Linux interface evidence be complete and preserved before merge. The
orchestrator re-ran both probes itself rather than relying on the implementing worker's report, and
this is the raw output.

Linux, through WSL

Command, run twice against separate short-lived processes:

wsl.exe -d docker-desktop -- sh -c 'cat /proc/self/stat'

Run A, first 90 characters:

10 (cat) R 9 9 9 34816 9 4194304 50 0 0 0 0 0 0 0 20 0 1 0 136 1736704 210 18446744073709

Run B, first 90 characters:

9 (cat) R 8 9 9 34816 9 4194560 213 0 1 0 0 0 0 0 20 0 1 0 2794 1736704 190 18446744073709

Applying exactly the parsing in tools/lib/run-state.mjs,
stat.slice(stat.lastIndexOf(") ") + 2).trim().split(/\s+/):

index /proc field name run A run B
fields[0] 3 state R R
fields[17] 20 num_threads 1 1
fields[18] 21 itrealvalue 0 0
fields[19] 22 starttime 136 2794
fields[20] 23 vsize 1736704 1736704
fields[21] 24 rss 210 190

Why this confirms the index rather than merely being consistent with it. The two runs are
different processes started at different times. starttime is the only column that moves as a start
time should (136 then 2794), while vsize is byte-identical at 1736704 across both, which is what a
constant per-binary field looks like for the same cat, and num_threads stays 1. A wrong index
would have to land on a field that happens to vary the same way and leave vsize where it is; it
does not. /^\d+$/.test(fields[19]) is true in both runs.

The slice-after-") " approach is also the right one for this file, because the second field is the
parenthesized command and can itself contain spaces and parentheses. Splitting the whole line on
whitespace would shift every index for such a process.

Boot id, same host:

9d47a387-d487-457a-91ef-472ccc9486f0

36 characters, matching the /^[0-9a-f-]{36}$/ guard in the implementation.

Windows

powershell.exe -NoProfile -NonInteractive -Command "(Get-Process -Id 4276).StartTime.ToUniversalTime().Ticks.ToString()"
639243321953634446

A bare decimal digit string, matching the /^\d+$/ guard.

One behaviour worth recording, because the implementation depends on it: the same command against a
pid that does not exist does not return an empty string, it throws. Observed verbatim, on a
Portuguese-locale host:

Nao e possivel chamar um metodo em uma expressao de valor nulo.

Get-Process -ErrorAction Stop fails, .StartTime is then called on null, and PowerShell raises. So
the probe's result.status === 0 test is what rejects a dead pid, and the regex is a second guard
rather than the first. The error text is localized, so nothing may ever parse it.

What this does and does not establish

  • It establishes the field index, the parsing strategy, the boot-id shape and the Windows tick
    format against real output from both platforms.
  • It does NOT establish behaviour across a reboot, which is what pairing starttime with boot_id
    is there to cover, and which no single-session run can show.

@thomasluizon

Copy link
Copy Markdown
Owner Author

@pullfrog review

@pullfrog pullfrog 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.

Important

The independent follow-up confirms the parsed Linux columns, but the required interface evidence is still incomplete and is not preserved in the PR body.

Reviewed changes I reviewed the full current six-file delta at bbc12545, the synchronized base commit, and the independent OS-probe evidence posted since the prior Pullfrog review.

  • Bound wake registrations to OS identities. Wake records now persist Windows start-time ticks or Linux boot-and-start-time values and reject mismatched, legacy, malformed, inaccessible, or proven-dead records.
  • Revalidated the final Stop decision. The rule now passes each complete registration through isWakeSourceAlive, closing the PID-reuse race between reader validation and the decision to sleep.
  • Covered adapter and lifecycle paths. The hook regressions exercise changed and unreadable final observations, while the tool cases observe registration identity and cleanup around a real launcher.
  • Rechecked external evidence. The Windows response shape is preserved in the PR body, and the follow-up comment independently samples the Linux fields the implementation reads.

⚠️ Linux response remains incomplete and outside the PR body

The follow-up comment labels both /proc/self/stat samples as only their “first 90 characters,” so the remainder of this positional response is still omitted; the PR body itself still contains only a prose summary. Because production indexes field 22 of this external interface, an excerpt cannot establish the complete response shape or preserve the required evidence with the implementation.

Technical details
# Preserve the complete Linux process response in the PR body

## Affected sites
- `tools/lib/run-state.mjs:132-136` — parses process state and start time from positional `/proc/<pid>/stat` fields and combines them with `boot_id`
- PR #847 body, `External interface evidence` — gives the reproduction command but no observed Linux stdout
- PR comment `#issuecomment-5562770172` — independently verifies relevant columns but explicitly truncates each stat line after 90 characters

## Required outcome
- Add an untruncated observed `/proc/self/stat` line and the complete boot-ID line to the PR body, replacing values as needed while preserving every positional field and each literal format.
- Keep the credential-free reproduction command beside that complete response.

Pullfrog  | Fix it ➔ | View workflow run | Using GPT Sol | 𝕏

@thomasluizon

Copy link
Copy Markdown
Owner Author

@pullfrog review

@pullfrog pullfrog 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.

Important

Linux dead-process states can still satisfy the new identity predicate, and the complete Linux interface response remains unpreserved.

Reviewed changes I reviewed the current six-file delta at bbc12545, the resolution of the prior final-probe race, all wake-source callers, the regression harness, and the latest PR-body evidence.

  • Persisted process identities. Wake registrations now bind launcher PIDs to Windows start ticks or Linux boot-and-start-time values and filter malformed, inaccessible, legacy, and mismatched records.
  • Revalidated the Stop decision. checkSleepStop now passes complete registrations through isWakeSourceAlive, closing the prior PID-only decision path.
  • Expanded lifecycle coverage. The hook and tool harnesses exercise identity registration, changed and unreadable final observations, dead-record sweeping, and launcher cleanup.
  • Preserved follow-up evidence. The PR body now includes the independently rerun Windows and Linux probe notes, including the positional Linux samples currently available.

⚠️ Linux process response is still incomplete

The independent follow-up is now preserved in the PR body, but both /proc/self/stat samples explicitly stop after their first 90 characters. Because production parses this positional external interface, omitting the remaining fields still leaves the complete response shape unverified.

Technical details
# Preserve the complete Linux process response

## Affected sites
- `tools/lib/run-state.mjs:132-136` — parses state and start time by position from `/proc/<pid>/stat`
- PR #847 body, `Independent verification of both OS start-identity interfaces` — labels both observed stat lines as only their first 90 characters

## Required outcome
- Put an untruncated observed `/proc/self/stat` line and the complete boot-ID line in the PR body, preserving every positional field and literal format.
- Keep the credential-free reproduction command beside the complete response.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GPT Sol | 𝕏

Comment thread tools/lib/run-state.mjs Outdated
@sonarqubecloud

sonarqubecloud Bot commented Sep 7, 2026

Copy link
Copy Markdown

@thomasluizon

Copy link
Copy Markdown
Owner Author

@pullfrog review

@pullfrog

pullfrog Bot commented Sep 7, 2026 •

Copy link
Copy Markdown
  • Check out PR 847 and read every authoritative diff range
  • Trace changed behavior, callers, tests, and prior review context
  • Validate any disposition-changing concerns and submit one review

Pullfrog  | View workflow run | via Pullfrog | Using GPT Sol | 𝕏

@thomasluizon
thomasluizon merged commit ff975ad into redesign/main Sep 7, 2026
36 checks passed
@thomasluizon
thomasluizon deleted the fix/ticket-437-wake-identity branch September 7, 2026 02:17
thomasluizon added a commit that referenced this pull request Sep 30, 2026
Co-Authored-By: Claude Opus 5.5 <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.

1 participant