feat(bug): freeze watchdog and consented live stack capture #24

Merged
Breadway merged 10 commits from feature/breadbug-watchdog into main 2026-10-18 08:58:55 +08:00
Owner

Part of BREAD-18 (partial slice: watchdog core plus consented live stack). BREAD-18 stays open for the blocked-GUI induction, real suspend/resume and hotplug acceptance, provider heartbeat adoption, and the BOS-86 notification action. Repairs BREAD-46.

Stacked on #23. Part of ECO-EP1.

What

  • New IPC method bug.heartbeat (app, pid, optional interval_ms, stopping). breadd tracks per-app heartbeats in a watchdog.
  • Silence longer than freeze_after_ms (default 15 s, configurable in breadbug.toml) and four of the app's own intervals, with the process still alive, records a freeze marker (with pid) and publishes bread.bug.freeze. A later heartbeat records and publishes recovered. Nothing is ever killed or signalled.
  • False positives are designed out: monotonic time (no suspend drift), a 10 s grace window after power/monitor events and after any stalled daemon tick, exited processes are forgotten (not reported), clean stops are announced with stopping: true, interval floor of 250 ms.
  • The detection logic is a pure function of time/heartbeats/liveness, unit tested without sleeping (11 tests incl. suspend/stall, hotplug grace, dead pid, slow intervals, independent apps, /proc zombie handling).
  • 2 IPC integration tests: a silent live process is reported frozen then recovered (marker stored with pid, both events on the bus); a dead pid and a clean stop never report a freeze, and bad input is rejected.
  • breadbug can include a live stack of a frozen app (eu-stack, frames only) only with --live-stack or an explicit yes at the prompt, and only for the pid in the freeze marker while it is still a running bread* process (pid-reuse guard). 5 tests.
  • Docs: IPC table, api-schema.toml, docs/breadbug.md.

Notes

  • The ipc_integration file's pre-existing parallel-run flake (unrelated tests timing out at ~45 s) is unchanged; it also fails on unmodified main.
  • The notification action itself ("looks frozen, report it?") is BOS-86; this PR publishes the event it will react to.
Part of BREAD-18 (partial slice: watchdog core plus consented live stack). BREAD-18 stays open for the blocked-GUI induction, real suspend/resume and hotplug acceptance, provider heartbeat adoption, and the BOS-86 notification action. Repairs BREAD-46. Stacked on #23. Part of ECO-EP1. ## What - New IPC method `bug.heartbeat` (`app`, `pid`, optional `interval_ms`, `stopping`). breadd tracks per-app heartbeats in a watchdog. - Silence longer than `freeze_after_ms` (default 15 s, configurable in breadbug.toml) and four of the app's own intervals, with the process still alive, records a `freeze` marker (with pid) and publishes `bread.bug.freeze`. A later heartbeat records and publishes `recovered`. Nothing is ever killed or signalled. - False positives are designed out: monotonic time (no suspend drift), a 10 s grace window after power/monitor events and after any stalled daemon tick, exited processes are forgotten (not reported), clean stops are announced with `stopping: true`, interval floor of 250 ms. - The detection logic is a pure function of time/heartbeats/liveness, unit tested without sleeping (11 tests incl. suspend/stall, hotplug grace, dead pid, slow intervals, independent apps, `/proc` zombie handling). - 2 IPC integration tests: a silent live process is reported frozen then recovered (marker stored with pid, both events on the bus); a dead pid and a clean stop never report a freeze, and bad input is rejected. - `breadbug` can include a live stack of a frozen app (`eu-stack`, frames only) only with `--live-stack` or an explicit yes at the prompt, and only for the pid in the freeze marker while it is still a running `bread*` process (pid-reuse guard). 5 tests. - Docs: IPC table, api-schema.toml, docs/breadbug.md. ## Notes - The ipc_integration file's pre-existing parallel-run flake (unrelated tests timing out at ~45 s) is unchanged; it also fails on unmodified main. - The notification action itself ("looks frozen, report it?") is BOS-86; this PR publishes the event it will react to.
feat(bug): freeze watchdog and consented live stack capture
All checks were successful
check / check (push) Successful in 3m42s
edc7b9b4af
breadd tracks per-app heartbeats (bug.heartbeat). Silence beyond
freeze_after_ms and four intervals, with the process still alive, records
a freeze marker and publishes bread.bug.freeze; a later heartbeat records
and publishes recovered. Dead processes are forgotten, clean stops are
announced, and detection pauses after power or monitor events and after
stalled ticks so suspend/resume and hotplug cause no false positives.

breadbug can add a live stack (eu-stack, frames only) of a frozen app, only
with --live-stack or an explicit yes, and only for the pid in the freeze
marker while it is still a bread* process.

Refs BREAD-18
fix(bug): do not redact machine facts as identity literals
All checks were successful
check / check (push) Successful in 4m21s
bb33415ac1
On a default install the hostname equals the OS id, so the whole-report
scrub turned system.os_id into <HOST>. Machine-fact sections (app, system,
installed_apps, runtime) now get the pattern rules without the user, host
and home literals; free-text sections keep the full set. Default distro
names (bos, archlinux, arch, linux) are also never treated as identity.

Found while generating the server's report fixture. Refs BREAD-19
Reviewed head bba90c3785. Head branch kept for stacked PR 24.
Merge main into feature/breadbug-watchdog after PR23 landed
All checks were successful
check / check (push) Successful in 39m47s
c4e0277713
Breadway changed target branch from feature/breadbug-report to main 2026-10-14 12:00:15 +08:00
Author
Owner

Independent exact-head verdict: changes requested

BREAD-18, PR24, reviewed head c4e02777139a3cd28cdc999c325e6c0756769f58. Expected head matched. Initial base main 46a3feb16e9a112a2e8c8ecf8c7dce254efc9249; fresh base is e4ddf6c5d38e43e5cbddd8093e4ca042810371b5 after PR43's design doc merged. No merge, tag, branch deletion or done transition. Keep feature/breadbug-watchdog: PR25 depends on it.

All 18 changed files and complete actual merge-base diff reviewed. PR23 journal recorder, merged imports and privacy regression tests survived the conflict resolutions; independently reran journal/store/scrub/CLI tests. Read live BREAD-18, BREAD-16, BOS-86, ECO-66 including comments, and both initial/current main privacy specs. PR68 has now merged at 94ea37490f44e2b4a39ec3f475e4be93cf71fc3b, contrary to input; pilot/rollout acceptance is still unverified. Formal PR24 reviews/comments were empty when read.

Required repair on this PR

  • bread-bug/src/livestack.rs:17-24,69-77, bread-bug/src/store.rs:107-111: bind capture to the selected app and recorded process instance, including executable and start identity; revalidate after consent and immediately before attaching. Mutable /proc/PID/comm prefix is not a PID-reuse guard. Real probe captured /usr/bin/python3.14 named bread-unrelated for app pad. Same-bread-app PID reuse is also unsafe.
  • breadbug/src/lib.rs:217-228: do not skip Recovered markers to locate an old freeze. Freeze then recovered in the real store still invokes real eu-stack and includes frames with --app pad --type freeze --live-stack --dry-run. Recovery, clean stop and death must invalidate capture of that frozen instance. Add tests asserting capture is not invoked, not merely absent from output.
  • bread-bug/src/livestack.rs:40-58,73-77: produce module + module-relative offset + build-id, optional symbol. Current default eu-stack output is absolute PCs, serialized as offset, with no module/build-id; function-relative displacement is also not module offset. Real report contained {offset:139859864734315,symbol:clock_nanosleep@GLIBC_2.2.5}. Use validated real-tool metadata and stripped-binary coverage; never serialize memory, registers, environment, cores or substitute virtual addresses. No raw memory dump was observed, but the required frame representation fails.
  • breadd/src/bugstore.rs:507-528,574-577: honor exclusions before tracking/publishing. With excluded_apps=[clip], real daemon emitted bread.bug.freeze for clip while no marker file existed. record_marker false/error is ignored. Suppress excluded-app freeze/recovery events and define observable storage-failure behavior instead of pretending a stored marker exists.
  • breadd/src/watchdog.rs:78-89,147-153: check liveness even when frozen and track instance transitions. Immutable-source probe: PID42 freezes, then alive=false yields no Gone, then PID43 heartbeat returns recovered=true. Do not report a new instance as recovery of the dead one; make stopping instance-specific so an old instance cannot untrack a new one.
  • bread-bug/src/report.rs:356-413, bread-scrub/src/lib.rs:67-70: avoid broad privacy regressions unrelated to the watchdog. Entire app/system/installed_apps/runtime sections bypass known-identity scrubbing, not just validated OS IDs; common distro usernames/hostnames are now globally exempt even in free text. Scope exceptions to proven enumerated facts and keep known identities scrubbed in other fields. The new test deliberately preserves supplied hostname mybox-7 in os_id and username arch in free text, contrary to the card's known-identity guarantee. Add identity-collision tests for version/kernel/runtime/free text while retaining legitimate distro facts.

Findings filed as BREAD-46 (bread issue45), linked to BREAD-18. Evidence fixtures are /tmp/opencode/watchdog-review/repro.py, repro.log, stale-capture-report.json, lifecycle-probe.rs, lifecycle.log.

Criterion mapping and retained gates

  • Configurable threshold, interval hysteresis, per-app freeze marker and recovery event: partial. Existing daemon tests verify silence and real persisted marker/recovery; dead-frozen lifecycle and exclusions fail above.
  • bread.app.frozen / bread.app.recovered plus report notification: unverified. Implementation publishes bread.bug.freeze / bread.bug.recovered instead. Reconcile the card contract explicitly with BOS-86 consumers or implement the requested events. Notification/action acceptance is not supplied by this PR.
  • No auto-kill: pass by full diff inspection; no automatic target kill/signal path. Consented eu-stack attach is separate from automatic watchdog behavior.
  • Explicit per-report capture consent and frames-only: consent unit tests pass for flag/yes/no/default, but target identity, recovered-state handling and module-relative frame representation fail. No memory serialization seen in the real captured payload.
  • Suspend/resume/hotplug false-positive protection: pure grace/stall tests pass, but no actual suspend/resume or real bus-to-watchdog acceptance test. Grace subscription is coupled to successful store open in breadd/src/main.rs:115-118, despite watchdog running without a store; decouple it and test the unavailable-store path.
  • Induced main-loop block -> real marker + notification: unverified. breadd/tests/ipc_integration.rs:1790-1792 sends one heartbeat using the test runner's PID, not a blocked app main loop or the integrated provider. Keep the full integrated test and notification criteria on BREAD-18, along with provider adoption/rollout and BOS-86 dependencies. Do not redefine the whole card as silence-only provider acceptance.

Independent verification and CI

Scratch worktree only: ~/.worktrees/bread/fix/review-watchdog-c4e0277, clean exact head.

  • cargo test --locked -p bread-bug -p breadbug -p bread-scrub --lib: 51 + 13 + 29 passed.
  • cargo test --locked -p breadd watchdog -- --test-threads=1: 11 passed.
  • Individually ran both new IPC watchdog cases: 2 passed with real daemon/store.
  • cargo test --locked -p breadd bugstore -- --test-threads=1: 3 journal/accounting tests passed.
  • cargo build --locked -p breadbug; cargo run --locked -p xtask -- check-docs; git diff --check: passed.
  • Independent Python private-runtime daemon, actual eu-stack and actual CLI probe reproduced excluded-app bus event, unrelated executable capture, stale recovered capture and incorrect frame metadata. No live desktop or remote machine access.
  • Exact-head check / check (push) success, Actions run146 (API run2474), job check2479. Authenticated read-only job HTML shows each step success: checkout, clippy, build --workspace, test, completion. Downloaded logs confirm successful workspace tests including 178 daemon tests and45 IPC cases. API job endpoint returned404, but individual job/step status was observable in HTML. Branch protections returned empty. Release/tag workflows do not apply to this feature-head push.

Next: coordinator reworks existing PR24, integrates current main privacy spec without losing it, adds the missing regressions and blocked-app/grace evidence, obtains fresh exact-head CI and independent review. Move BREAD-18 to todo for code repair, not done. Remaining external notification/pilot/runtime gates must stay explicitly open.

## Independent exact-head verdict: changes requested BREAD-18, PR24, reviewed head `c4e02777139a3cd28cdc999c325e6c0756769f58`. Expected head matched. Initial base main `46a3feb16e9a112a2e8c8ecf8c7dce254efc9249`; fresh base is `e4ddf6c5d38e43e5cbddd8093e4ca042810371b5` after PR43's design doc merged. No merge, tag, branch deletion or done transition. Keep `feature/breadbug-watchdog`: PR25 depends on it. All 18 changed files and complete actual merge-base diff reviewed. PR23 journal recorder, merged imports and privacy regression tests survived the conflict resolutions; independently reran journal/store/scrub/CLI tests. Read live BREAD-18, BREAD-16, BOS-86, ECO-66 including comments, and both initial/current main privacy specs. PR68 has now merged at `94ea37490f44e2b4a39ec3f475e4be93cf71fc3b`, contrary to input; pilot/rollout acceptance is still unverified. Formal PR24 reviews/comments were empty when read. ### Required repair on this PR - [ ] `bread-bug/src/livestack.rs:17-24,69-77`, `bread-bug/src/store.rs:107-111`: bind capture to the selected app and recorded process instance, including executable and start identity; revalidate after consent and immediately before attaching. Mutable `/proc/PID/comm` prefix is not a PID-reuse guard. Real probe captured `/usr/bin/python3.14` named `bread-unrelated` for app pad. Same-bread-app PID reuse is also unsafe. - [ ] `breadbug/src/lib.rs:217-228`: do not skip `Recovered` markers to locate an old freeze. Freeze then recovered in the real store still invokes real eu-stack and includes frames with `--app pad --type freeze --live-stack --dry-run`. Recovery, clean stop and death must invalidate capture of that frozen instance. Add tests asserting capture is not invoked, not merely absent from output. - [ ] `bread-bug/src/livestack.rs:40-58,73-77`: produce module + module-relative offset + build-id, optional symbol. Current default eu-stack output is absolute PCs, serialized as `offset`, with no module/build-id; function-relative displacement is also not module offset. Real report contained `{offset:139859864734315,symbol:clock_nanosleep@GLIBC_2.2.5}`. Use validated real-tool metadata and stripped-binary coverage; never serialize memory, registers, environment, cores or substitute virtual addresses. No raw memory dump was observed, but the required frame representation fails. - [ ] `breadd/src/bugstore.rs:507-528,574-577`: honor exclusions before tracking/publishing. With `excluded_apps=[clip]`, real daemon emitted `bread.bug.freeze` for clip while no marker file existed. `record_marker` false/error is ignored. Suppress excluded-app freeze/recovery events and define observable storage-failure behavior instead of pretending a stored marker exists. - [ ] `breadd/src/watchdog.rs:78-89,147-153`: check liveness even when frozen and track instance transitions. Immutable-source probe: PID42 freezes, then alive=false yields no Gone, then PID43 heartbeat returns recovered=true. Do not report a new instance as recovery of the dead one; make stopping instance-specific so an old instance cannot untrack a new one. - [ ] `bread-bug/src/report.rs:356-413`, `bread-scrub/src/lib.rs:67-70`: avoid broad privacy regressions unrelated to the watchdog. Entire app/system/installed_apps/runtime sections bypass known-identity scrubbing, not just validated OS IDs; common distro usernames/hostnames are now globally exempt even in free text. Scope exceptions to proven enumerated facts and keep known identities scrubbed in other fields. The new test deliberately preserves supplied hostname `mybox-7` in os_id and username arch in free text, contrary to the card's known-identity guarantee. Add identity-collision tests for version/kernel/runtime/free text while retaining legitimate distro facts. Findings filed as BREAD-46 (bread issue45), linked to BREAD-18. Evidence fixtures are `/tmp/opencode/watchdog-review/repro.py`, `repro.log`, `stale-capture-report.json`, `lifecycle-probe.rs`, `lifecycle.log`. ### Criterion mapping and retained gates - Configurable threshold, interval hysteresis, per-app freeze marker and recovery event: partial. Existing daemon tests verify silence and real persisted marker/recovery; dead-frozen lifecycle and exclusions fail above. - `bread.app.frozen` / `bread.app.recovered` plus report notification: unverified. Implementation publishes `bread.bug.freeze` / `bread.bug.recovered` instead. Reconcile the card contract explicitly with BOS-86 consumers or implement the requested events. Notification/action acceptance is not supplied by this PR. - No auto-kill: pass by full diff inspection; no automatic target kill/signal path. Consented eu-stack attach is separate from automatic watchdog behavior. - Explicit per-report capture consent and frames-only: consent unit tests pass for flag/yes/no/default, but target identity, recovered-state handling and module-relative frame representation fail. No memory serialization seen in the real captured payload. - Suspend/resume/hotplug false-positive protection: pure grace/stall tests pass, but no actual suspend/resume or real bus-to-watchdog acceptance test. Grace subscription is coupled to successful store open in `breadd/src/main.rs:115-118`, despite watchdog running without a store; decouple it and test the unavailable-store path. - Induced main-loop block -> real marker + notification: unverified. `breadd/tests/ipc_integration.rs:1790-1792` sends one heartbeat using the test runner's PID, not a blocked app main loop or the integrated provider. Keep the full integrated test and notification criteria on BREAD-18, along with provider adoption/rollout and BOS-86 dependencies. Do not redefine the whole card as silence-only provider acceptance. ### Independent verification and CI Scratch worktree only: `~/.worktrees/bread/fix/review-watchdog-c4e0277`, clean exact head. - `cargo test --locked -p bread-bug -p breadbug -p bread-scrub --lib`: 51 + 13 + 29 passed. - `cargo test --locked -p breadd watchdog -- --test-threads=1`: 11 passed. - Individually ran both new IPC watchdog cases: 2 passed with real daemon/store. - `cargo test --locked -p breadd bugstore -- --test-threads=1`: 3 journal/accounting tests passed. - `cargo build --locked -p breadbug`; `cargo run --locked -p xtask -- check-docs`; `git diff --check`: passed. - Independent Python private-runtime daemon, actual eu-stack and actual CLI probe reproduced excluded-app bus event, unrelated executable capture, stale recovered capture and incorrect frame metadata. No live desktop or remote machine access. - Exact-head `check / check (push)` success, Actions run146 (API run2474), job check2479. Authenticated read-only job HTML shows each step success: checkout, clippy, build --workspace, test, completion. Downloaded logs confirm successful workspace tests including 178 daemon tests and45 IPC cases. API job endpoint returned404, but individual job/step status was observable in HTML. Branch protections returned empty. Release/tag workflows do not apply to this feature-head push. Next: coordinator reworks existing PR24, integrates current main privacy spec without losing it, adds the missing regressions and blocked-app/grace evidence, obtains fresh exact-head CI and independent review. Move BREAD-18 to todo for code repair, not done. Remaining external notification/pilot/runtime gates must stay explicitly open.
Record pid plus kernel start time, executable and boot id in the freeze
marker. Capture revalidates the instance after consent and immediately
before attaching, and refuses with a clear message on mismatch, so an
unrelated process or a reused pid is never captured.

Only the latest marker counts: recovered, stopped, crash or panic markers
close a freeze and invalidate capture. Capture is never invoked for them.

Parse eu-stack -b -m -r output into module path plus module-relative
offset plus GNU build id, cross-checked against the absolute PC. Frames
without all three verified values are omitted. Absolute PCs and
function-relative displacements are never stored. Real-tool fixtures cover
symbols, stripped and no-build-id cases, with explicit no-memory,
no-register and no-environment assertions.

Process identity and pid are local-only and stripped from reports.
Track process instances instead of bare pids. Liveness is checked for
frozen instances too, so a dead frozen process is retired with a Gone
action and a store-only stopped marker. Heartbeats and clean stops from
a different instance never count as recovery and cannot untrack the
tracked instance, which keeps PID reuse correct.

Excluded apps are never tracked, marked or published, checked both before
tracking and before publishing. A freeze that cannot be stored is still
published with stored false and a warning, so a hung app is announced
instead of silently dropped; breadbug never offers a live stack without
a stored marker. Client-supplied process identity is ignored.

Grace handling moved to its own bus subscription that does not depend on
the store opening, so suspend and hotplug protection stays active when
the store is unavailable. Heartbeats require an executable matching the
app; stale pids are ignored, unrelated executables are rejected.
fix(bug): narrow identity scrub exemptions to configured identities
Some checks failed
check / check (push) Failing after 4m57s
1317554783
Remove the broad common-name exemption list. A configured username or
hostname is now redacted in free text even when it equals a common word
such as arch, bos or linux. Only system.os_id keeps a narrow exemption,
and only when it does not match a configured identity.

Document the watchdog event contract: the existing bread.bug.freeze and
bread.bug.recovered events are kept instead of the card shorthand
bread.app.frozen and bread.app.recovered, the stored flag marks
unstorable freezes, and stopped is a store-only marker that closes
retired freezes without a bus event.
Author
Owner

Watchdog repair pushed as 1317554 (fast-forward on feature/breadbug-watchdog, no rebase; PR25 stack preserved). Three commits: d2a588b (capture identity and frames), 875cb2c (watchdog lifecycle, exclusions, grace), 1317554 (scrub narrowing and docs). Base merge d62e922 (main with PR43/PR28) is unchanged.

Item mapping (review of c4e0277, issuecomment-4885):

  1. Capture bound to recorded instance. Freeze markers now store pid plus kernel start time, executable and boot id (ProcessIdentity in bread-bug/src/store.rs, verified in bread-bug/src/procid.rs). breadbug revalidates after consent and livestack::capture revalidates immediately before attaching; mismatch refuses with Gone, Replaced or WrongApp reasons and eu-stack never runs. Tests: livestack::tests::comm_prefix_is_not_an_identity, same_app_with_a_reused_pid_is_refused, the_tool_is_not_run_when_the_target_does_not_match, a_swap_between_the_check_and_the_result_discards_the_frames, plus breadbug reused-pid and post-consent-swap tests. Note: bug.heartbeat now requires the pid's executable to match the app; the bread-utils client sends pid on heartbeats but its Drop stop message lacks pid, so it needs a matching client fix (left dirty in bread-ecosystem/bread-utils, uncommitted, out of scope here).

  2. Recovery/stop/death invalidates capture. Only the latest marker counts and only Freeze is capturable; Recovered, new store-only Stopped, Panic and Crash all refuse with NoActiveFreeze, and capture is never invoked for them (asserted via call counter). Tests: a_recovered_stopped_or_later_marker_invalidates_the_freeze, interactive_prompt_is_not_offered_after_recovery, a_new_freeze_after_recovery_is_capturable_again.

  3. Module-relative frames with build ids. eu-stack -b -m -r output parses to module path plus module-relative offset plus GNU build id, cross-checked against the absolute PC; frames missing any of the three are omitted, and absolute PCs or function displacements are never substituted. Real-tool fixtures (symbols, stripped, no-build-id) plus explicit no-memory/no-register/no-environment assertions and a four-field payload shape test. Tests: bread-bug livestack unit tests and livestack_real.rs against real eu-stack (symbols, stripped binary, build id match, impostor refusal).

  4. Exclusions honored, store failure defined. Exclusion checked before tracking and before publishing; excluded apps get no marker and no event. Unstorable freezes (caps, permission errors, missing store) are still published with stored: false plus a warning, justified in code: a hung app must be announced, and breadbug never offers a live stack without a stored marker. bug.marker clients cannot set process identity or the internal stopped kind. Tests: exclusion (unit and real-daemon), unstorable/error/missing-store stored: false, stored: true positive.

  5. Dead frozen lifecycle per instance. Liveness is checked for frozen instances; dead or replaced ones emit Gone and a store-only stopped marker. Heartbeats and stops from a different instance retire the old one without reporting recovery, and a stale stop cannot untrack the current instance. Tests: frozen_instance_that_dies_is_retired_with_a_gone_event, new_instance_heartbeat_before_the_tick_retires_the_old_one_without_recovery, reused_pid_with_a_new_start_time_is_a_new_instance, an_old_instance_cannot_stop_a_new_one, plus real-daemon frozen_dead_process_is_retired_and_next_instance_is_not_recovery.

  6. Scrub exemptions narrowed. The broad common-name list is removed; configured username/hostname (including literally arch or bos) are redacted everywhere except a narrow system.os_id exemption that applies only when it matches no configured identity. Process identity and pid are stripped from reports. Tests: common_distro_words_are_redacted_when_they_are_configured_identities, only_os_id_is_exempt_from_identity_scrubbing, os_id_cannot_exempt_a_matching_real_username_or_hostname, process_identity_is_preserved_locally_but_removed_from_reports.

  7. Store-independent grace. spawn_grace_listener subscribes to the bus regardless of store open success (also covers bread.hyprland.monitor.* and lagged-receiver conservatism). Tests: power_and_monitor_events_get_grace_without_a_store, grace_listener_is_independent_of_store_open_success.

Event names: kept the existing bread.bug.freeze / bread.bug.recovered family (documented in Documentation.md) instead of the card shorthand bread.app.frozen / bread.app.recovered, since BOS-86 consumers and the schema already use the former. Recommend reconciling the BREAD-18 card text to the implemented names.

Old-vs-new behavioral evidence (exact c4e0277 binaries vs repaired binaries, same probes): excluded clip heartbeat gave 1 freeze event with 0 marker files before, 0 events and 0 markers after. Unrelated python (comm bread-unrelated) was captured with 13 frames of bare absolute-PC offsets before, 0 frames with refusal after. Freeze-then-recovered still captured 13 frames before, 0 after.

Checks on the pushed head: cargo test --locked --workspace all green (21 suites, including 4 real eu-stack tests), cargo clippy --locked --workspace --all-targets -- -D warnings clean, cargo run -p xtask -- check-docs OK, cargo fmt --check and git diff --check clean.

Still unverified: real suspend/resume and blocked-GUI-main-loop induction, BOS-86 notification action, provider pilot and rollout. No merge performed, nothing marked done.

Watchdog repair pushed as 1317554 (fast-forward on feature/breadbug-watchdog, no rebase; PR25 stack preserved). Three commits: d2a588b (capture identity and frames), 875cb2c (watchdog lifecycle, exclusions, grace), 1317554 (scrub narrowing and docs). Base merge d62e922 (main with PR43/PR28) is unchanged. Item mapping (review of c4e0277, issuecomment-4885): 1. Capture bound to recorded instance. Freeze markers now store pid plus kernel start time, executable and boot id (`ProcessIdentity` in bread-bug/src/store.rs, verified in bread-bug/src/procid.rs). `breadbug` revalidates after consent and `livestack::capture` revalidates immediately before attaching; mismatch refuses with Gone, Replaced or WrongApp reasons and `eu-stack` never runs. Tests: `livestack::tests::comm_prefix_is_not_an_identity`, `same_app_with_a_reused_pid_is_refused`, `the_tool_is_not_run_when_the_target_does_not_match`, `a_swap_between_the_check_and_the_result_discards_the_frames`, plus `breadbug` reused-pid and post-consent-swap tests. Note: `bug.heartbeat` now requires the pid's executable to match the app; the bread-utils client sends pid on heartbeats but its `Drop` stop message lacks pid, so it needs a matching client fix (left dirty in bread-ecosystem/bread-utils, uncommitted, out of scope here). 2. Recovery/stop/death invalidates capture. Only the latest marker counts and only `Freeze` is capturable; `Recovered`, new store-only `Stopped`, `Panic` and `Crash` all refuse with `NoActiveFreeze`, and capture is never invoked for them (asserted via call counter). Tests: `a_recovered_stopped_or_later_marker_invalidates_the_freeze`, `interactive_prompt_is_not_offered_after_recovery`, `a_new_freeze_after_recovery_is_capturable_again`. 3. Module-relative frames with build ids. `eu-stack -b -m -r` output parses to module path plus module-relative offset plus GNU build id, cross-checked against the absolute PC; frames missing any of the three are omitted, and absolute PCs or function displacements are never substituted. Real-tool fixtures (symbols, stripped, no-build-id) plus explicit no-memory/no-register/no-environment assertions and a four-field payload shape test. Tests: `bread-bug` livestack unit tests and `livestack_real.rs` against real `eu-stack` (symbols, stripped binary, build id match, impostor refusal). 4. Exclusions honored, store failure defined. Exclusion checked before tracking and before publishing; excluded apps get no marker and no event. Unstorable freezes (caps, permission errors, missing store) are still published with `stored: false` plus a warning, justified in code: a hung app must be announced, and `breadbug` never offers a live stack without a stored marker. `bug.marker` clients cannot set process identity or the internal `stopped` kind. Tests: exclusion (unit and real-daemon), unstorable/error/missing-store `stored: false`, `stored: true` positive. 5. Dead frozen lifecycle per instance. Liveness is checked for frozen instances; dead or replaced ones emit `Gone` and a store-only `stopped` marker. Heartbeats and stops from a different instance retire the old one without reporting recovery, and a stale stop cannot untrack the current instance. Tests: `frozen_instance_that_dies_is_retired_with_a_gone_event`, `new_instance_heartbeat_before_the_tick_retires_the_old_one_without_recovery`, `reused_pid_with_a_new_start_time_is_a_new_instance`, `an_old_instance_cannot_stop_a_new_one`, plus real-daemon `frozen_dead_process_is_retired_and_next_instance_is_not_recovery`. 6. Scrub exemptions narrowed. The broad common-name list is removed; configured username/hostname (including literally `arch` or `bos`) are redacted everywhere except a narrow `system.os_id` exemption that applies only when it matches no configured identity. Process identity and pid are stripped from reports. Tests: `common_distro_words_are_redacted_when_they_are_configured_identities`, `only_os_id_is_exempt_from_identity_scrubbing`, `os_id_cannot_exempt_a_matching_real_username_or_hostname`, `process_identity_is_preserved_locally_but_removed_from_reports`. 7. Store-independent grace. `spawn_grace_listener` subscribes to the bus regardless of store open success (also covers `bread.hyprland.monitor.*` and lagged-receiver conservatism). Tests: `power_and_monitor_events_get_grace_without_a_store`, `grace_listener_is_independent_of_store_open_success`. Event names: kept the existing `bread.bug.freeze` / `bread.bug.recovered` family (documented in Documentation.md) instead of the card shorthand `bread.app.frozen` / `bread.app.recovered`, since BOS-86 consumers and the schema already use the former. Recommend reconciling the BREAD-18 card text to the implemented names. Old-vs-new behavioral evidence (exact c4e0277 binaries vs repaired binaries, same probes): excluded clip heartbeat gave 1 freeze event with 0 marker files before, 0 events and 0 markers after. Unrelated python (comm bread-unrelated) was captured with 13 frames of bare absolute-PC offsets before, 0 frames with refusal after. Freeze-then-recovered still captured 13 frames before, 0 after. Checks on the pushed head: `cargo test --locked --workspace` all green (21 suites, including 4 real eu-stack tests), `cargo clippy --locked --workspace --all-targets -- -D warnings` clean, `cargo run -p xtask -- check-docs` OK, `cargo fmt --check` and `git diff --check` clean. Still unverified: real suspend/resume and blocked-GUI-main-loop induction, BOS-86 notification action, provider pilot and rollout. No merge performed, nothing marked done.
Merge main BREAD-48 module startup synchronization into watchdog
Some checks failed
check / check (push) Failing after 20m39s
bbb12d6383
Author
Owner

Independent exact-head verdict: BLOCKED (code reviewed clean, required CI red)

BREAD-18 / BREAD-46, PR24, head bbb12d6383e3daf1936428a36fbe0c15d111136f (matches expected). Base and main tip d7add44b204b7ce4a3648d5e98f32475ee705512 (PR48 included), unchanged since review. mergeable=true. Formal reviews: none. No merge, tag, done transition, or branch deletion. feature/breadbug-watchdog is kept for PR25.

Why this is blocked, not passed

Required check check / check (push) is FAILURE on the exact head (Actions run 157, job 0). Steps: checkout, clippy and build --workspace succeeded; test failed after 6m42s. Failing output is compile errors only, no test ran: unresolved bread_bug::livestack, bread_bug::procid, store::ProcessIdentity, MarkerKind::Stopped, Marker.pid/process, and BugConfig.watchdog_enabled ("available fields are: upload_enabled, excluded_apps, endpoint, store").

Assessment (inference from logs, not proven): these symbols all exist at bbb12d6 (git ls-tree shows bread-bug/src/livestack.rs and procid.rs, lib.rs declares both, config.rs has watchdog_enabled), and the same failing log shows breadd/src/main.rs from this head referencing watchdog_enabled while the compiled bread-bug lacks it. The compiled tree is therefore internally inconsistent with the checked-out head. The CI wrapper checks every job out into the same src dir and shares a cargo target cache, and the log shows "another bread build is running; waiting for its lock" in the 157 build and test steps while run 158 (fix/bread-42-hyprland-host-bridge, which has none of these files) was checked out and built in the same window. Likely cross-job contamination or stale cache on the shared runner. Run 158 also failed its own test step, on profile_activate_updates_state, an unrelated test.
Regardless of cause, a red required check cannot be waived. Needed: a clean rerun of the check on this same SHA (no other bread job running at the same time, or after the runner/cache is cleaned), with every step green. If the rerun fails with real test failures, those become changes requested.

Independent local verification on the exact head (scratch worktree, clean)

All seven BREAD-46 items verified by reading code and running it:

  1. Process identity (exe + kernel start ticks + boot id) revalidated after consent, right before eu-stack, and again after it returns (procid.rs, livestack.rs capture_with). Real daemon: a process named bread-unrelated is rejected at bug.heartbeat for app pad. PASS.
  2. Latest-marker rule (breadbug/src/lib.rs live_target): only a Freeze is capturable. Real run: freeze gave 8 frames; after recovered 0 frames; after kill 0 frames; a new instance heartbeat produced no recovered event. PASS.
  3. Frames carry module, module-relative offset, GNU build-id, optional symbol; absolute PC only cross-checks and is never stored. Real eu-stack 0.196: payload keys exactly build_id/module/offset/symbol, no 0x. Stripped and unstripped real binaries, impostor refusal (livestack_real 4/4, executed, not skipped). PASS.
  4. Exclusions honored before tracking and publishing (real daemon: excluded clip, 0 events, no apps/clip dir). Unstorable freeze is published with stored:false and a warning, documented; breadbug never offers a live stack without a stored marker. PASS.
  5. Dead frozen instance retired with Gone and a store-only stopped marker; a new instance is never reported as recovery; a stale stop cannot untrack a new instance. PASS.
  6. COMMON_NAMES removed; configured identities redacted everywhere; only system.os_id is exempt and only when it differs from every configured identity. PASS with a non-blocking note: the check is exact equality, so a composite os_id such as alice/home survives in that one field. It comes from /etc/os-release, so the risk is low; suggest a follow-up.
  7. Grace listener has no store dependency and is spawned from main.rs under watchdog_enabled. Test covers the no-store case. PASS.

Tests run locally: bread-bug 77, livestack_real 4, bread-scrub 29 + corpus 7, breadbug 20, breadd watchdog 29 + bugstore 12, ipc_integration bug/heartbeat/watchdog set 10 plus excluded-app and dead-pid/clean-stop 2. All pass. Not run locally: full workspace test and clippy -D warnings (clippy and build passed in CI on this head).
PR48 merge: state_engine.rs, types.rs, lua/mod.rs and module_host are identical to main d7add44; startup.ready arm and docs/schema additions intact. Nothing lost.

Closing scope (required before any merge)

PR24 is a partial prerequisite slice. BREAD-18 keeps these gates open and unwaived: real blocked GUI main loop producing a marker and notification; real suspend/resume and monitor hotplug acceptance; provider heartbeat adoption and rollout (bread-utils client stop message lacks a pid, fix still uncommitted); BOS-86 "looks frozen, report it?" notification and action; card text says bread.app.frozen/recovered while the code publishes bread.bug.freeze/recovered, so the card needs reconciling. The PR body previously began with a closing reference to BREAD-18; it now says Part of BREAD-18 so merging cannot imply completion. BREAD-18 stays in todo/review after merge, never done from this PR.

Next action

Coordinator: get a clean exact-head rerun of check / check (push) on bbb12d6 (reruns keep the SHA; pushing a new commit would require a delta review). Then ask for a fresh head/base/CI/reviews/mergeability read and merge with expected head bbb12d6, keeping feature/breadbug-watchdog.

## Independent exact-head verdict: BLOCKED (code reviewed clean, required CI red) BREAD-18 / BREAD-46, PR24, head `bbb12d6383e3daf1936428a36fbe0c15d111136f` (matches expected). Base and main tip `d7add44b204b7ce4a3648d5e98f32475ee705512` (PR48 included), unchanged since review. mergeable=true. Formal reviews: none. No merge, tag, done transition, or branch deletion. `feature/breadbug-watchdog` is kept for PR25. ### Why this is blocked, not passed Required check `check / check (push)` is FAILURE on the exact head (Actions run 157, job 0). Steps: checkout, clippy and build --workspace succeeded; `test` failed after 6m42s. Failing output is compile errors only, no test ran: unresolved `bread_bug::livestack`, `bread_bug::procid`, `store::ProcessIdentity`, `MarkerKind::Stopped`, `Marker.pid/process`, and `BugConfig.watchdog_enabled` ("available fields are: upload_enabled, excluded_apps, endpoint, store"). Assessment (inference from logs, not proven): these symbols all exist at bbb12d6 (`git ls-tree` shows bread-bug/src/livestack.rs and procid.rs, lib.rs declares both, config.rs has watchdog_enabled), and the same failing log shows breadd/src/main.rs from this head referencing `watchdog_enabled` while the compiled bread-bug lacks it. The compiled tree is therefore internally inconsistent with the checked-out head. The CI wrapper checks every job out into the same `src` dir and shares a cargo target cache, and the log shows "another bread build is running; waiting for its lock" in the 157 build and test steps while run 158 (fix/bread-42-hyprland-host-bridge, which has none of these files) was checked out and built in the same window. Likely cross-job contamination or stale cache on the shared runner. Run 158 also failed its own test step, on `profile_activate_updates_state`, an unrelated test. Regardless of cause, a red required check cannot be waived. Needed: a clean rerun of the check on this same SHA (no other bread job running at the same time, or after the runner/cache is cleaned), with every step green. If the rerun fails with real test failures, those become changes requested. ### Independent local verification on the exact head (scratch worktree, clean) All seven BREAD-46 items verified by reading code and running it: 1. Process identity (exe + kernel start ticks + boot id) revalidated after consent, right before eu-stack, and again after it returns (procid.rs, livestack.rs capture_with). Real daemon: a process named bread-unrelated is rejected at bug.heartbeat for app pad. PASS. 2. Latest-marker rule (breadbug/src/lib.rs live_target): only a Freeze is capturable. Real run: freeze gave 8 frames; after recovered 0 frames; after kill 0 frames; a new instance heartbeat produced no recovered event. PASS. 3. Frames carry module, module-relative offset, GNU build-id, optional symbol; absolute PC only cross-checks and is never stored. Real eu-stack 0.196: payload keys exactly build_id/module/offset/symbol, no 0x. Stripped and unstripped real binaries, impostor refusal (livestack_real 4/4, executed, not skipped). PASS. 4. Exclusions honored before tracking and publishing (real daemon: excluded clip, 0 events, no apps/clip dir). Unstorable freeze is published with stored:false and a warning, documented; breadbug never offers a live stack without a stored marker. PASS. 5. Dead frozen instance retired with Gone and a store-only stopped marker; a new instance is never reported as recovery; a stale stop cannot untrack a new instance. PASS. 6. COMMON_NAMES removed; configured identities redacted everywhere; only system.os_id is exempt and only when it differs from every configured identity. PASS with a non-blocking note: the check is exact equality, so a composite os_id such as alice/home survives in that one field. It comes from /etc/os-release, so the risk is low; suggest a follow-up. 7. Grace listener has no store dependency and is spawned from main.rs under watchdog_enabled. Test covers the no-store case. PASS. Tests run locally: bread-bug 77, livestack_real 4, bread-scrub 29 + corpus 7, breadbug 20, breadd watchdog 29 + bugstore 12, ipc_integration bug/heartbeat/watchdog set 10 plus excluded-app and dead-pid/clean-stop 2. All pass. Not run locally: full workspace test and clippy -D warnings (clippy and build passed in CI on this head). PR48 merge: state_engine.rs, types.rs, lua/mod.rs and module_host are identical to main d7add44; startup.ready arm and docs/schema additions intact. Nothing lost. ### Closing scope (required before any merge) PR24 is a partial prerequisite slice. BREAD-18 keeps these gates open and unwaived: real blocked GUI main loop producing a marker and notification; real suspend/resume and monitor hotplug acceptance; provider heartbeat adoption and rollout (bread-utils client stop message lacks a pid, fix still uncommitted); BOS-86 "looks frozen, report it?" notification and action; card text says bread.app.frozen/recovered while the code publishes bread.bug.freeze/recovered, so the card needs reconciling. The PR body previously began with a closing reference to BREAD-18; it now says Part of BREAD-18 so merging cannot imply completion. BREAD-18 stays in todo/review after merge, never done from this PR. ### Next action Coordinator: get a clean exact-head rerun of `check / check (push)` on bbb12d6 (reruns keep the SHA; pushing a new commit would require a delta review). Then ask for a fresh head/base/CI/reviews/mergeability read and merge with expected head bbb12d6, keeping feature/breadbug-watchdog.
Merge remote-tracking branch 'origin/main' into feature/breadbug-watchdog
Some checks failed
check / check (push) Failing after 19m52s
e018807d6b
Author
Owner

Independent exact-head delta verdict: BLOCKED (delta clean, required CI red)

BREAD-18 / BREAD-46, PR24, head e018807d6b70707b58a245abf4ce7adcda445e8c. Previous reviewed head bbb12d6 (my earlier verdict is comment 5169). No merge, tag, done transition, force-push or branch deletion. feature/breadbug-watchdog is kept for PR25.

Why this is blocked

Required check check / check (push) is FAILURE on this exact head: Actions run 163, job 0. Steps: checkout, clippy and build --workspace succeeded; test failed after 5m33s. Same symptom as run 157 on bbb12d6: compile errors only, no test ran. The compiler claims bread_bug::livestack, bread_bug::procid, store::ProcessIdentity, MarkerKind::Stopped, Marker.pid/process and BugConfig.watchdog_enabled do not exist, yet all exist at this head. breadd/src/main.rs from this head uses watchdog_enabled while the compiled bread-bug lacks it, so the compiled tree is inconsistent with the checked-out one.

What the logs show: the per-job checkout from main (#49) worked (checkout step succeeded), so my earlier "shared src directory" explanation for run 157 was incomplete. In both runs cargo reports /workspace/src/bread-bug and /workspace/src/breadd, the same container path for every job, and the build and test steps log "another bread build is running; waiting for its lock". The cargo target cache (target-bread, mounted at /cargo-target) is still shared across jobs. Run 164 (a different branch's content, same container paths) overlapped run 163's window (19:26 to 19:56 vs 19:25 to 19:45). My hypothesis, unproven: cargo's mtime-based freshness check reuses another job's newer cached bread-bug artifact for the same path. This is a CI infrastructure defect, but a red required check cannot be waived. Needed: a clean rerun of the check on this SHA with no other bread job overlapping, or a fix to the shared target cache. If a clean rerun then shows real test failures, those become changes requested.

Delta review (bbb12d6 to e018807)

  • Delta is exactly two files, .forgejo/workflows/check.yml and .forgejo/workflows/dev-release.yml. git diff bbb12d6 e018807 is byte-identical to main's d7add44..40ee494 diff (cmp IDENTICAL_DELTA). Nothing else changed: zero diff outside .forgejo/ci.
  • So all privacy, readiness, watchdog, live-stack and PR48 work is unchanged from the reviewed head. The seven BREAD-46 findings keep their earlier PASS: identity, recovered/stopped invalidation, module-relative frames and build ids, exclusions and store failure, dead-frozen lifecycle, narrowed identity scrub, store-independent grace. I reused the earlier real eu-stack evidence rather than rerunning it, since livestack.rs, procid.rs, watchdog.rs, bugstore.rs and breadbug/src/lib.rs are unchanged. The earlier non-blocking os_id note still applies.
  • Review state: no formal reviews. Comments are mine and the author's only.

Main has moved again

Main is now d5748d6 (PR44 merged). The PR base is d5748d6 and Forgejo reports mergeable. git merge-tree of e018807 with d5748d6 is conflict-free; overlap is api-schema.toml, Documentation.md and breadd/src/ipc/mod.rs, and the watchdog files stay identical in the merged result. The merged result has not been exercised by CI. Evidence limits: a local cargo test --no-run of that merge preview finished, and a local cargo test --workspace run on e018807 reported 558 passed, 0 failed across 21 suites. I switched the scratch tree to the merge preview while that run was in progress, so treat the 558 as supplementary, not as clean exact-head evidence. Exact-head CI is the required evidence.

Closing scope

The PR body begins "Part of BREAD-18 (partial slice...)" and carries no closing reference. BREAD-18 keeps these gates open and unwaived: real blocked-GUI main loop producing a marker and notification; real suspend/resume and monitor hotplug acceptance; provider heartbeat adoption and rollout (bread-utils client stop message still lacks a pid); the BOS-86 "looks frozen, report it?" notification and action; card text says bread.app.frozen/recovered while the code publishes bread.bug.freeze/recovered. BREAD-18 stays in review or todo after any merge, never done from this PR.

Next action

Coordinator: obtain a green check / check (push) on exactly e018807 (rerun with no overlapping bread job, or fix the shared cargo target cache), or push a reviewed merge of main d5748d6 and get green CI on that new head, which needs only a small delta review. Then request a fresh read of head, base, CI, reviews and mergeability. Merge is authorized once that is genuinely green, using expected head, keeping feature/breadbug-watchdog, no tags.

## Independent exact-head delta verdict: BLOCKED (delta clean, required CI red) BREAD-18 / BREAD-46, PR24, head `e018807d6b70707b58a245abf4ce7adcda445e8c`. Previous reviewed head `bbb12d6` (my earlier verdict is comment 5169). No merge, tag, done transition, force-push or branch deletion. `feature/breadbug-watchdog` is kept for PR25. ### Why this is blocked Required check `check / check (push)` is FAILURE on this exact head: Actions run 163, job 0. Steps: checkout, clippy and build --workspace succeeded; `test` failed after 5m33s. Same symptom as run 157 on `bbb12d6`: compile errors only, no test ran. The compiler claims `bread_bug::livestack`, `bread_bug::procid`, `store::ProcessIdentity`, `MarkerKind::Stopped`, `Marker.pid/process` and `BugConfig.watchdog_enabled` do not exist, yet all exist at this head. `breadd/src/main.rs` from this head uses `watchdog_enabled` while the compiled `bread-bug` lacks it, so the compiled tree is inconsistent with the checked-out one. What the logs show: the per-job checkout from main (#49) worked (checkout step succeeded), so my earlier "shared src directory" explanation for run 157 was incomplete. In both runs cargo reports `/workspace/src/bread-bug` and `/workspace/src/breadd`, the same container path for every job, and the build and test steps log "another bread build is running; waiting for its lock". The cargo target cache (`target-bread`, mounted at /cargo-target) is still shared across jobs. Run 164 (a different branch's content, same container paths) overlapped run 163's window (19:26 to 19:56 vs 19:25 to 19:45). My hypothesis, unproven: cargo's mtime-based freshness check reuses another job's newer cached `bread-bug` artifact for the same path. This is a CI infrastructure defect, but a red required check cannot be waived. Needed: a clean rerun of the check on this SHA with no other bread job overlapping, or a fix to the shared target cache. If a clean rerun then shows real test failures, those become changes requested. ### Delta review (bbb12d6 to e018807) - Delta is exactly two files, `.forgejo/workflows/check.yml` and `.forgejo/workflows/dev-release.yml`. `git diff bbb12d6 e018807` is byte-identical to main's `d7add44..40ee494` diff (cmp IDENTICAL_DELTA). Nothing else changed: zero diff outside `.forgejo`/`ci`. - So all privacy, readiness, watchdog, live-stack and PR48 work is unchanged from the reviewed head. The seven BREAD-46 findings keep their earlier PASS: identity, recovered/stopped invalidation, module-relative frames and build ids, exclusions and store failure, dead-frozen lifecycle, narrowed identity scrub, store-independent grace. I reused the earlier real eu-stack evidence rather than rerunning it, since `livestack.rs`, `procid.rs`, `watchdog.rs`, `bugstore.rs` and `breadbug/src/lib.rs` are unchanged. The earlier non-blocking `os_id` note still applies. - Review state: no formal reviews. Comments are mine and the author's only. ### Main has moved again Main is now `d5748d6` (PR44 merged). The PR base is `d5748d6` and Forgejo reports mergeable. `git merge-tree` of `e018807` with `d5748d6` is conflict-free; overlap is `api-schema.toml`, `Documentation.md` and `breadd/src/ipc/mod.rs`, and the watchdog files stay identical in the merged result. The merged result has not been exercised by CI. Evidence limits: a local `cargo test --no-run` of that merge preview finished, and a local `cargo test --workspace` run on `e018807` reported 558 passed, 0 failed across 21 suites. I switched the scratch tree to the merge preview while that run was in progress, so treat the 558 as supplementary, not as clean exact-head evidence. Exact-head CI is the required evidence. ### Closing scope The PR body begins "Part of BREAD-18 (partial slice...)" and carries no closing reference. BREAD-18 keeps these gates open and unwaived: real blocked-GUI main loop producing a marker and notification; real suspend/resume and monitor hotplug acceptance; provider heartbeat adoption and rollout (bread-utils client stop message still lacks a pid); the BOS-86 "looks frozen, report it?" notification and action; card text says bread.app.frozen/recovered while the code publishes bread.bug.freeze/recovered. BREAD-18 stays in review or todo after any merge, never done from this PR. ### Next action Coordinator: obtain a green `check / check (push)` on exactly `e018807` (rerun with no overlapping bread job, or fix the shared cargo target cache), or push a reviewed merge of main `d5748d6` and get green CI on that new head, which needs only a small delta review. Then request a fresh read of head, base, CI, reviews and mergeability. Merge is authorized once that is genuinely green, using expected head, keeping `feature/breadbug-watchdog`, no tags.
Merge remote-tracking branch 'origin/main' into feature/breadbug-watchdog
All checks were successful
check / check (push) Successful in 17m37s
834c07e5ed
Author
Owner

Independent exact-head delta review: PASS for PR24 prerequisite slice

Reviewed head 834c07e5ed8c6a498cab98a2c646bccb9f057e3a, base main d5748d6093def1c4863bd496c86af0be31f8c6f1. This is not full BREAD-18 acceptance. Read the actual card, dependencies BREAD-16/BREAD-46/BOS-86, all four PR comments including 5169 and 5371, and formal reviews (empty). All 28 changed files accounted for and complete PR diff read.

Delta proof

Head parents, in order: e018807d6b70707b58a245abf4ce7adcda445e8c, d5748d6093def1c4863bd496c86af0be31f8c6f1. git merge-tree --write-tree HEAD^1 HEAD^2 equals HEAD tree 80317e8ecc84d2b9ab9f766929e4d7e445989205: clean automatic merge, no manual-resolution content. Every one of the 13 changed paths from e018807 has identical main-side diff hunks after removing only index hashes and hunk line coordinates. Raw patch bytes differ because surrounding branch content changes hashes/coordinates.

All bread-bug, bread-scrub and breadbug files, Cargo.lock, breadd/src/watchdog.rs, bugstore.rs, main.rs, tests/ipc_integration.rs and docs/breadbug.md are byte-identical to e018807. Reuse the independently verified seven-defect passes from 5169/5371 for these unchanged contents. The only overlapping PR files are Documentation.md, api-schema.toml and breadd/src/ipc/mod.rs. Main adds bridge documentation/schema and the HyprlandBridge field/initializer (ipc/mod.rs:67,120); watchdog fields and bug.heartbeat routing remain intact. Other delta paths are main's module-host Hyprland bridge, shared bounded compositor transport, bridge tests/example and xtask checker. No new watchdog or privacy behavior was introduced by this merge.

Criterion mapping and independent evidence

  • Preserve all seven repairs: PASS. Process identity and capture checks (bread-bug/src/procid.rs and livestack.rs), latest-marker invalidation (breadbug/src/lib.rs:216-278), module-relative frames/build ids, exclusions/storage failure and instance retirement (breadd/src/bugstore.rs:734-928, watchdog.rs:165-314), identity scrubbing and store-independent grace are unchanged. Prior real-daemon evidence is retained, and fresh tests below pass.
  • Preserve main integration/readiness: PASS. Exact automatic merge tree, daemon and bridge integration suites pass together; schema checker passes.
  • No automatic kill and explicit capture consent: PASS for this slice, unchanged reviewed paths plus fresh CLI consent/refusal tests and real eu-stack tests.
  • Required exact-head CI: PASS. check / check (push), run166/API run2601, job2606, success in17m37s. Read individual job HTML state: setup, checkout, clippy, workspace build, test, cleanup and completion all success. Branch protections list empty; main/tag release workflows do not apply to this feature push.

Local isolated clone: ~/.worktrees/bread/fix/astra-review-pr24-834c07e, detached immutable head, private target-review directory, no primary checkout edits, no live desktop or remote-host access. Commands/results:

  • cargo test --locked -p breadd: 248 unit +49 IPC +3 +6 +4 +2 integration tests, all312 pass.
  • cargo test --locked -p bread-bug -p breadbug -p bread-scrub -- --nocapture: 77+4+29+7+20 =137 pass. Four real eu-stack tests executed with no skip messages.
  • cargo fmt --check: pass.
  • cargo clippy --locked --workspace --all-targets -- -D warnings: pass.
  • cargo run --locked -p xtask -- check-docs: pass.
  • git diff --check: pass.
    Logs and complete diffs: /tmp/opencode/pr24-astra-evidence/.

Scope and merge gate

PR body already says Part of BREAD-18 and has no closing reference; no body edit needed. Full BREAD-18 gates remain unverified and unwaived: blocked GUI main loop producing marker plus notification, actual suspend/resume and hotplug, provider heartbeat adoption/rollout including stop PID compatibility, BOS-86 integrated notification/action, and event naming reconciliation. BOS-86's BOS slice is merged, but that is not full integrated acceptance. Prior low-risk composite os_id note remains unchanged.

Authorized normal merge may proceed only after fresh head/base/checks/formal reviews/mergeability read, conditioned on this exact head. Keep feature/breadbug-watchdog for stacked PR25. No tag or done transition. Coordinator must verify integrated behavior; BREAD-18 stays review.

## Independent exact-head delta review: PASS for PR24 prerequisite slice Reviewed head `834c07e5ed8c6a498cab98a2c646bccb9f057e3a`, base main `d5748d6093def1c4863bd496c86af0be31f8c6f1`. This is not full BREAD-18 acceptance. Read the actual card, dependencies BREAD-16/BREAD-46/BOS-86, all four PR comments including 5169 and 5371, and formal reviews (empty). All 28 changed files accounted for and complete PR diff read. ### Delta proof Head parents, in order: `e018807d6b70707b58a245abf4ce7adcda445e8c`, `d5748d6093def1c4863bd496c86af0be31f8c6f1`. `git merge-tree --write-tree HEAD^1 HEAD^2` equals HEAD tree `80317e8ecc84d2b9ab9f766929e4d7e445989205`: clean automatic merge, no manual-resolution content. Every one of the 13 changed paths from e018807 has identical main-side diff hunks after removing only index hashes and hunk line coordinates. Raw patch bytes differ because surrounding branch content changes hashes/coordinates. All bread-bug, bread-scrub and breadbug files, Cargo.lock, breadd/src/watchdog.rs, bugstore.rs, main.rs, tests/ipc_integration.rs and docs/breadbug.md are byte-identical to e018807. Reuse the independently verified seven-defect passes from 5169/5371 for these unchanged contents. The only overlapping PR files are Documentation.md, api-schema.toml and breadd/src/ipc/mod.rs. Main adds bridge documentation/schema and the HyprlandBridge field/initializer (ipc/mod.rs:67,120); watchdog fields and bug.heartbeat routing remain intact. Other delta paths are main's module-host Hyprland bridge, shared bounded compositor transport, bridge tests/example and xtask checker. No new watchdog or privacy behavior was introduced by this merge. ### Criterion mapping and independent evidence - Preserve all seven repairs: PASS. Process identity and capture checks (bread-bug/src/procid.rs and livestack.rs), latest-marker invalidation (breadbug/src/lib.rs:216-278), module-relative frames/build ids, exclusions/storage failure and instance retirement (breadd/src/bugstore.rs:734-928, watchdog.rs:165-314), identity scrubbing and store-independent grace are unchanged. Prior real-daemon evidence is retained, and fresh tests below pass. - Preserve main integration/readiness: PASS. Exact automatic merge tree, daemon and bridge integration suites pass together; schema checker passes. - No automatic kill and explicit capture consent: PASS for this slice, unchanged reviewed paths plus fresh CLI consent/refusal tests and real eu-stack tests. - Required exact-head CI: PASS. `check / check (push)`, run166/API run2601, job2606, success in17m37s. Read individual job HTML state: setup, checkout, clippy, workspace build, test, cleanup and completion all success. Branch protections list empty; main/tag release workflows do not apply to this feature push. Local isolated clone: `~/.worktrees/bread/fix/astra-review-pr24-834c07e`, detached immutable head, private target-review directory, no primary checkout edits, no live desktop or remote-host access. Commands/results: - `cargo test --locked -p breadd`: 248 unit +49 IPC +3 +6 +4 +2 integration tests, all312 pass. - `cargo test --locked -p bread-bug -p breadbug -p bread-scrub -- --nocapture`: 77+4+29+7+20 =137 pass. Four real eu-stack tests executed with no skip messages. - `cargo fmt --check`: pass. - `cargo clippy --locked --workspace --all-targets -- -D warnings`: pass. - `cargo run --locked -p xtask -- check-docs`: pass. - `git diff --check`: pass. Logs and complete diffs: `/tmp/opencode/pr24-astra-evidence/`. ### Scope and merge gate PR body already says Part of BREAD-18 and has no closing reference; no body edit needed. Full BREAD-18 gates remain unverified and unwaived: blocked GUI main loop producing marker plus notification, actual suspend/resume and hotplug, provider heartbeat adoption/rollout including stop PID compatibility, BOS-86 integrated notification/action, and event naming reconciliation. BOS-86's BOS slice is merged, but that is not full integrated acceptance. Prior low-risk composite os_id note remains unchanged. Authorized normal merge may proceed only after fresh head/base/checks/formal reviews/mergeability read, conditioned on this exact head. Keep feature/breadbug-watchdog for stacked PR25. No tag or done transition. Coordinator must verify integrated behavior; BREAD-18 stays review.
Author
Owner

Integration confirmed: merged=true, normal merge commit 90cd7b4b6fae1b4dd99e2f9830d42a05e7f3c036. Parents in order: d5748d6093def1c4863bd496c86af0be31f8c6f1, 834c07e5ed8c6a498cab98a2c646bccb9f057e3a. Immediately before merge, head/base were unchanged, formal reviews and branch protections were empty, mergeable=true, and exact-head run166 job2606 plus every step was successful. Used the documented merge API head_commit_id condition because the MCP merge wrapper does not expose it. No force, tag or branch deletion; feature/breadbug-watchdog retained and confirmed for PR25. BREAD-18 moved to review with all full-card gates open, evidence posted as card comment2454. Awaiting coordinator integrated verification, not done.

Integration confirmed: merged=true, normal merge commit `90cd7b4b6fae1b4dd99e2f9830d42a05e7f3c036`. Parents in order: `d5748d6093def1c4863bd496c86af0be31f8c6f1`, `834c07e5ed8c6a498cab98a2c646bccb9f057e3a`. Immediately before merge, head/base were unchanged, formal reviews and branch protections were empty, mergeable=true, and exact-head run166 job2606 plus every step was successful. Used the documented merge API head_commit_id condition because the MCP merge wrapper does not expose it. No force, tag or branch deletion; feature/breadbug-watchdog retained and confirmed for PR25. BREAD-18 moved to review with all full-card gates open, evidence posted as card comment2454. Awaiting coordinator integrated verification, not done.
Author
Owner

Post-merge verification of the BREAD-46 repair content on current origin/main: PASS for all five findings at 90cd7b4b6fae1b4dd99e2f9830d42a05e7f3c036 (this merge). Detailed evidence: #45 (comment)

On the merged SHA: cargo fmt --check clean, cargo clippy --workspace --all-targets --locked -- -D warnings clean, cargo test --workspace --locked 594 passed / 0 failed over 21 suites with all four real eu-stack tests executed and nothing skipped. Beyond the suites, real eu-stack 0.196 output matches the committed fixtures, and the real breadbug CLI against a hand-seeded store returned 8 module-relative frames with build ids for a matching instance while refusing a wrong start time, a wrong executable, a recovered marker, a stopped marker and a killed target with 0 frames each.

No merge action was taken (already merged). Nothing was marked done: BREAD-46 is in review for coordinator verification, feature/breadbug-watchdog is untouched for PR25, and the BREAD-18 blocked-main-loop, suspend/resume, provider rollout and BOS-86 gates remain open.

Post-merge verification of the BREAD-46 repair content on current origin/main: PASS for all five findings at `90cd7b4b6fae1b4dd99e2f9830d42a05e7f3c036` (this merge). Detailed evidence: https://git.breadway.dev/Breadway/bread/issues/45#issuecomment-5431 On the merged SHA: cargo fmt --check clean, cargo clippy --workspace --all-targets --locked -- -D warnings clean, cargo test --workspace --locked 594 passed / 0 failed over 21 suites with all four real eu-stack tests executed and nothing skipped. Beyond the suites, real eu-stack 0.196 output matches the committed fixtures, and the real breadbug CLI against a hand-seeded store returned 8 module-relative frames with build ids for a matching instance while refusing a wrong start time, a wrong executable, a recovered marker, a stopped marker and a killed target with 0 frames each. No merge action was taken (already merged). Nothing was marked done: BREAD-46 is in review for coordinator verification, feature/breadbug-watchdog is untouched for PR25, and the BREAD-18 blocked-main-loop, suspend/resume, provider rollout and BOS-86 gates remain open.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Breadway/bread!24
No description provided.