fix(module-host): bridge bread.hyprland to out-of-process modules #44

Merged
Breadway merged 8 commits from fix/bread-42-hyprland-host-bridge into main 2026-10-16 21:12:59 +08:00
Owner

Closes BREAD-42

Expose bread.hyprland to manifest modules granted the hyprland permission. The daemon authenticates each method against the host's granted permissions, forwards dispatch, keyword and eval through the shared checked compatibility layer, and serves the existing Hyprland queries. Unchecked/refused dispatch and keyword replies surface as Lua errors.

The bug was that module-host Lua environments exposed no Hyprland namespace or module_host.hyprland* RPC despite advertising the manifest permission as granted.

Validation: the dedicated subprocess fixture runs a real breadd and bread-module-host against a private fake Hyprland Unix socket; it covers granted access, denied permission, and a refused reply surfaced as an error. No host compositor is contacted. cargo test --locked --workspace, clippy, and xtask check-docs results are recorded in the implementation session.

Closes BREAD-42 Expose `bread.hyprland` to manifest modules granted the `hyprland` permission. The daemon authenticates each method against the host's granted permissions, forwards dispatch, keyword and eval through the shared checked compatibility layer, and serves the existing Hyprland queries. Unchecked/refused dispatch and keyword replies surface as Lua errors. The bug was that module-host Lua environments exposed no Hyprland namespace or `module_host.hyprland*` RPC despite advertising the manifest permission as granted. Validation: the dedicated subprocess fixture runs a real breadd and bread-module-host against a private fake Hyprland Unix socket; it covers granted access, denied permission, and a refused reply surfaced as an error. No host compositor is contacted. `cargo test --locked --workspace`, clippy, and `xtask check-docs` results are recorded in the implementation session.
fix(module-host): bridge bread.hyprland to out-of-process modules (BREAD-42)
All checks were successful
check / check (push) Successful in 21m41s
44a5a0b740
A manifest module granted `hyprland` runs in bread-module-host, which
authenticated with the permission listed but never installed
bread.hyprland, because the daemon bridge had no module_host.hyprland_*
methods. The grant did nothing and the first call hit a nil field.

Add module_host.hyprland_dispatch, _keyword, _eval and _query. breadd
makes the compositor request itself through the same hyprland_compat
helpers as the in-process binding, so checked-reply semantics (refused
dispatch/keyword is an error, bind/monitor read-back) are identical in
and out of process. The hyprland grant is checked daemon-side, per
authenticated host, before the method name is matched, so an ungranted
host cannot reach it by inventing a method name. The host installs
bread.hyprland only when granted. on_raw is not bridged.

The Hyprland socket helper moves from lua/mod.rs into hyprland_compat so
both paths share it. New test target module_host_hyprland spawns a real
breadd and bread-module-host against a fake Hyprland socket.
Author
Owner

Independent exact-head review: changes requested

Issue: BREAD-42. Reviewed head: 44a5a0b7407a4c4b8052a75134e3a478dcc64503. Actual base: main at e4ddf6c5d38e43e5cbddd8093e4ca042810371b5. Expected head matches. Read live card/comments, actual PR body, all six changed files and complete diff, applicable instructions, workflows, branch protections and formal reviews. PR/file pagination exhausted. PR44 is the unique linked match. Formal reviews were empty. No merge performed.

Interpretation: "checked variants" means the existing checked dispatch/keyword behavior, not new dispatch_checked/keyword_checked functions, which do not exist in the in-process API. eval intentionally returns raw reply text. on_raw is explicitly documented as unbridged.

Acceptance and evidence

  • Granted manifest host API: PASS for exercised dispatch, keyword legacy-to-eval fallback, eval raw error, monitors and active_window. bread-module-host/src/lua_env.rs:404-497; independent cargo test --locked -p breadd --test module_host_hyprland: 3 passed. workspaces/clients are implemented but not exercised by this fixture.
  • Same checked-reply semantics: PASS for exercised paths. Both in-process and bridge use the same dispatch/keyword helpers. Refused dispatch propagates both legacy and eval errors. cargo test --locked -p breadd hyprland --bin breadd: 45 passed, including read-back and IO error tests.
  • Daemon identity/permission/socket selection: code correctly binds permissions to the consumed one-time token (module_host_bridge.rs:93-105,148-153), not client names/ids, and gates all hyprland-prefix methods before matching (522-526). Socket selection reads only daemon environment (hyprland_compat.rs:29-60). However authenticated adversarial denial, spoof/replay and two-host error isolation are UNVERIFIED by wire tests. Existing denied subprocess test only checks Lua nil and an ordinary unauthenticated connection (module_host_hyprland.rs:385-418); helper unit tests do not exercise connection routing.
  • Bounded input, transport and operation lifetime: FAIL. See R1 below and reproduced BREAD-47.
  • Documentation/schema/check-docs: FAIL as a combined criterion. Documentation updates exist and local cargo run --locked -p xtask -- check-docs passes. api-schema.toml is unchanged and contains none of the four new IPC methods. xtask reads only ipc/mod.rs (xtask/src/main.rs:60-61,245-286), so the green checker does not verify this bridge surface.

Required CI

Exact-head run 149, job 2509 check: success. Independently read the job page's structured initial state, bound to commit 44a5a0b740. checkout, clippy, build --workspace, test and job completion all success. Exact-SHA status context check / check (push) is success. Branch protections list is empty. check.yml is the branch workflow; dev-release is main-only and tag workflows do not apply. CI evidence saved at /tmp/opencode/review-pr44/job-evidence.json. The known unrelated IPC status/store race in run147 and the earlier malformed-rules test failure are not grounds for rejection here because exact-head CI is green.

Rework checklist

  • R1, high: breadd/src/ipc/module_host_bridge.rs:529-545,587-590 and breadd/src/lua/hyprland_compat.rs:63-71. The outer timeout drops the JoinHandle but does not stop spawn_blocking. Socket connect/write/read have no transport deadline, and read_to_string is unbounded. A private real-daemon/real-host probe sent dispatch at 1.6s, returned a timeout to the module, then sent the eval fallback at 11.1s after the compositor delayed its rejection for 9.5s. Late commands can execute after reported failure and retry; repeated stalls retain workers/connections and can block shutdown. Repair on this PR, tracked as BREAD-47. Apply an actual whole-operation deadline across connect/write/read/fallback/read-back, stop subsequent requests after expiry, bound in-flight work, request/reply bytes, and strictly validate provided argument types (args currently silently accepts non-string as empty). Reject oversized/malformed input before compositor access. Add stalled, late reply, oversized request/reply and shutdown regressions. Never choose a socket from module input.
  • R2: breadd/tests/module_host_hyprland.rs:385-418 and module_host_bridge.rs:93-105,148-153,742-793. Add authenticated ungranted-host wire tests for all four methods and invented prefix names. Include forged module names/request ids/permission fields, invalid or replayed token, and granted plus denied hosts using the same request ids. Assert actual daemon denial, no compositor request for denied calls, and no result/error delivered to the other host. Cover workspaces/clients through the host too. Current nil/unauthenticated checks are useful but do not verify the required boundary.
  • R3: api-schema.toml IPC registry and xtask/src/main.rs:60-61,245-286. Register the four new module_host.hyprland_* IPC methods and extend check-docs extraction to the bridge, including prefix-dispatched suffixes, so missing/stale entries and documentation drift fail. Add a checker regression proving removal of a bridge entry fails, then rerun check-docs. The existing checker blind spot is pre-existing, but it cannot stand in for the explicitly requested schema update.

Local evidence: /tmp/opencode/review-pr44/{subprocess.log,unit.log,docs.log,timeout-probe.py,timeout-probe.log,job-evidence.json,diff}. All tests and probes used an isolated exact-head worktree and private fake compositor, never the live desktop. The real-daemon timeout reproduction is high-confidence observable behavior, not just a diff inference.

Next action: coordinator repairs R1-R3 on the existing branch/PR, integrates current main without force-push if needed, runs checks, and requests fresh exact-head review. Preserve PR/branch. BREAD-42 returns to todo for rework under review-gate rules, never done. Merge authorization remains conditional on a fresh pass and green exact-head checks.

## Independent exact-head review: changes requested Issue: BREAD-42. Reviewed head: `44a5a0b7407a4c4b8052a75134e3a478dcc64503`. Actual base: `main` at `e4ddf6c5d38e43e5cbddd8093e4ca042810371b5`. Expected head matches. Read live card/comments, actual PR body, all six changed files and complete diff, applicable instructions, workflows, branch protections and formal reviews. PR/file pagination exhausted. PR44 is the unique linked match. Formal reviews were empty. No merge performed. Interpretation: "checked variants" means the existing checked dispatch/keyword behavior, not new dispatch_checked/keyword_checked functions, which do not exist in the in-process API. eval intentionally returns raw reply text. on_raw is explicitly documented as unbridged. ### Acceptance and evidence - Granted manifest host API: PASS for exercised dispatch, keyword legacy-to-eval fallback, eval raw error, monitors and active_window. `bread-module-host/src/lua_env.rs:404-497`; independent `cargo test --locked -p breadd --test module_host_hyprland`: 3 passed. workspaces/clients are implemented but not exercised by this fixture. - Same checked-reply semantics: PASS for exercised paths. Both in-process and bridge use the same dispatch/keyword helpers. Refused dispatch propagates both legacy and eval errors. `cargo test --locked -p breadd hyprland --bin breadd`: 45 passed, including read-back and IO error tests. - Daemon identity/permission/socket selection: code correctly binds permissions to the consumed one-time token (`module_host_bridge.rs:93-105,148-153`), not client names/ids, and gates all hyprland-prefix methods before matching (`522-526`). Socket selection reads only daemon environment (`hyprland_compat.rs:29-60`). However authenticated adversarial denial, spoof/replay and two-host error isolation are UNVERIFIED by wire tests. Existing denied subprocess test only checks Lua nil and an ordinary unauthenticated connection (`module_host_hyprland.rs:385-418`); helper unit tests do not exercise connection routing. - Bounded input, transport and operation lifetime: FAIL. See R1 below and reproduced BREAD-47. - Documentation/schema/check-docs: FAIL as a combined criterion. Documentation updates exist and local `cargo run --locked -p xtask -- check-docs` passes. `api-schema.toml` is unchanged and contains none of the four new IPC methods. xtask reads only ipc/mod.rs (`xtask/src/main.rs:60-61,245-286`), so the green checker does not verify this bridge surface. ### Required CI Exact-head run 149, job 2509 `check`: success. Independently read the job page's structured initial state, bound to commit 44a5a0b7407a4c4b8052a75134e3a478dcc64503. checkout, clippy, build --workspace, test and job completion all success. Exact-SHA status context `check / check (push)` is success. Branch protections list is empty. check.yml is the branch workflow; dev-release is main-only and tag workflows do not apply. CI evidence saved at `/tmp/opencode/review-pr44/job-evidence.json`. The known unrelated IPC status/store race in run147 and the earlier malformed-rules test failure are not grounds for rejection here because exact-head CI is green. ### Rework checklist - [ ] R1, high: `breadd/src/ipc/module_host_bridge.rs:529-545,587-590` and `breadd/src/lua/hyprland_compat.rs:63-71`. The outer timeout drops the JoinHandle but does not stop spawn_blocking. Socket connect/write/read have no transport deadline, and read_to_string is unbounded. A private real-daemon/real-host probe sent dispatch at 1.6s, returned a timeout to the module, then sent the eval fallback at 11.1s after the compositor delayed its rejection for 9.5s. Late commands can execute after reported failure and retry; repeated stalls retain workers/connections and can block shutdown. Repair on this PR, tracked as BREAD-47. Apply an actual whole-operation deadline across connect/write/read/fallback/read-back, stop subsequent requests after expiry, bound in-flight work, request/reply bytes, and strictly validate provided argument types (args currently silently accepts non-string as empty). Reject oversized/malformed input before compositor access. Add stalled, late reply, oversized request/reply and shutdown regressions. Never choose a socket from module input. - [ ] R2: `breadd/tests/module_host_hyprland.rs:385-418` and `module_host_bridge.rs:93-105,148-153,742-793`. Add authenticated ungranted-host wire tests for all four methods and invented prefix names. Include forged module names/request ids/permission fields, invalid or replayed token, and granted plus denied hosts using the same request ids. Assert actual daemon denial, no compositor request for denied calls, and no result/error delivered to the other host. Cover workspaces/clients through the host too. Current nil/unauthenticated checks are useful but do not verify the required boundary. - [ ] R3: `api-schema.toml` IPC registry and `xtask/src/main.rs:60-61,245-286`. Register the four new module_host.hyprland_* IPC methods and extend check-docs extraction to the bridge, including prefix-dispatched suffixes, so missing/stale entries and documentation drift fail. Add a checker regression proving removal of a bridge entry fails, then rerun check-docs. The existing checker blind spot is pre-existing, but it cannot stand in for the explicitly requested schema update. Local evidence: `/tmp/opencode/review-pr44/{subprocess.log,unit.log,docs.log,timeout-probe.py,timeout-probe.log,job-evidence.json,diff}`. All tests and probes used an isolated exact-head worktree and private fake compositor, never the live desktop. The real-daemon timeout reproduction is high-confidence observable behavior, not just a diff inference. Next action: coordinator repairs R1-R3 on the existing branch/PR, integrates current main without force-push if needed, runs checks, and requests fresh exact-head review. Preserve PR/branch. BREAD-42 returns to todo for rework under review-gate rules, never done. Merge authorization remains conditional on a fresh pass and green exact-head checks.
The bridge wrapped spawn_blocking in a timeout, which stops waiting but not
the work: the blocking thread kept going and could send the eval fallback
after the module had already been told the call timed out, so a retry could
run the command twice. The socket itself had no connect/read/write deadline
and no reply cap.

- hyprland_compat: request_until() takes an operation Deadline. connect,
  write and read each stop at it, the deadline is checked before anything is
  sent, requests are capped at 32 KiB and replies at 1 MiB.
- One Deadline now spans a dispatch, its eval fallback and any read-back, and
  the socket is resolved once per operation.
- module_host_bridge: the compositor I/O runs on its own thread that owns its
  in-flight permits until it has stopped. One call per host and 8 across the
  daemon; excess calls are refused before touching the compositor. The
  deadline is cancelled when the host connection closes, and the thread is
  detached so it cannot hold up daemon shutdown.
- Parameters are validated strictly before any compositor access: a
  non-string args is now an error instead of being treated as empty, and
  string fields are capped at 16 KiB.
- In-process bread.hyprland.* shares the socket deadline and size caps.
Adds two test targets (ipc_integration.rs is untouched) that drive a real
breadd with a test-only module host (examples/fake_module_host.rs). The host
authenticates over the real one-time token handshake inside the normal
sandbox and then sends exactly the request lines a test scripts, against a
fake compositor socket that records everything it receives.

module_host_hyprland_wire (BREAD-42 R2):
- an authenticated host without the hyprland grant is denied all four
  methods, with forged module/permission fields and invented names, and
  nothing reaches the compositor
- a denied host with a forged hello cannot act as the granted host; replayed
  and invented tokens and unauthenticated connections get nothing; a replayed
  request id is answered on its own
- two granted hosts and a denied host calling concurrently with the same
  request ids never receive each other's responses

module_host_hyprland_deadlines (BREAD-47):
- stall past the deadline: the caller times out and no later request arrives
- late reply: timeout, no read-back
- oversized reply and request are refused
- a socket that never accepts times out and SIGTERM still exits promptly
- many stalled hosts cannot exceed the in-flight bound
feat(xtask): check-docs covers the module_host bridge methods (BREAD-42)
Some checks failed
check / check (push) Failing after 1h0m1s
5ed063907a
check-docs only read ipc/mod.rs, so the module_host.* methods handled in
module_host_bridge.rs were invisible to it, including the four new
module_host.hyprland_* ones.

- extract plain arms (including or-patterns), the module_host.hello special
  case, and prefix-dispatched families (module_host.hyprland_ + suffix)
- a method present in code but missing from api-schema.toml, stale in the
  schema, or missing from the Documentation.md IPC table now fails the check
- register all 21 module_host.* methods in api-schema.toml
- Documentation.md: one row name per method so the table is checkable, and
  document the bridge deadline, size caps and concurrency bounds
- regressions: removing a bridge entry from the schema or the docs fails
Author
Owner

Rework for review 4900 (R1-R3): head 5ed063907adae3e44e0799a18586efb3298a9624

Pushed on top of 44a5a0b as a fast-forward (3 commits, no rebase, no force). main is still e4ddf6c, so no merge was needed. BREAD-47 is fixed here, not in a separate PR.

R1 (high, BREAD-47): operation lifetime

Root cause: tokio::time::timeout around a spawn_blocking JoinHandle only stops waiting. The blocking thread kept running, so the eval fallback could still be sent after the module had been told the call timed out.

Fix (breadd/src/lua/hyprland_compat.rs, breadd/src/ipc/module_host_bridge.rs):

  • request_until() takes one operation Deadline. Connect (SO_SNDTIMEO slices), write and read each stop at it. The deadline is checked before anything is sent, so nothing goes out after expiry.
  • The same Deadline spans a dispatch, its eval fallback and any bind/unbind/monitor read-back. The socket is resolved once per operation, from the daemon environment only.
  • Caps: 32 KiB per request, 1 MiB per reply, 16 KiB per string parameter. Oversized input is refused before compositor access.
  • Parameters are strictly typed: a non-string args is now an error instead of silently becoming empty.
  • The compositor I/O runs on its own thread that holds its in-flight permits until it has actually stopped (no JoinHandle timeout). Bounds: 1 per host connection, 8 daemon-wide. Excess calls are refused before touching the compositor.
  • The deadline is also cancelled when the host connection closes or the handler is dropped. The thread is detached, so it cannot hold up daemon shutdown.
  • In-process bread.hyprland.* shares the socket deadline and caps (5s per call).

Regressions, all in breadd/tests/module_host_hyprland_deadlines.rs (real breadd, authenticated host, fake compositor socket):

scenario test 44a5a0b now
(a) stalls past the deadline, rejects at 9.5s stalled_compositor_times_out_and_no_later_request_ever_arrives FAIL: compositor received dispatch ... and then the eval hl.dispatch(...) fallback pass: only dispatch workspace 9 ever arrives, checked 7s past the old 11.1s
(b) replies late late_reply_is_a_timeout_and_triggers_no_read_back FAIL: j/binds read-back sent after the caller timed out pass
(c) oversized reply and request oversized_reply_and_request_are_refused FAIL: the oversized reply was returned to the module pass: byte-limit errors, oversized request never sent
(d) never accepts compositor_that_never_accepts_times_out_and_does_not_hold_up_shutdown FAIL: daemon did not exit within 5s of SIGTERM pass: times out at the deadline, SIGTERM exits promptly
stall x 12 hosts stalled_compositor_cannot_accumulate_unbounded_workers FAIL: no call refused pass: at most 8 in flight, the rest refused

Old-fails proof: I checked out 44a5a0b in a temporary worktree, copied in only the new test files and ran them. 5 of 5 failed, as in the table. The worktree and its target dir were removed afterwards. Faster unit-level versions (lua::hyprland_compat::deadline_tests, ipc::module_host_bridge::tests) cover the same cases, plus one deadline spanning dispatch and fallback, and cancel-on-close. They use the new APIs, so they cannot compile on the old head.

R2: authenticated wire tests

New separate target breadd/tests/module_host_hyprland_wire.rs (ipc_integration.rs untouched). Hosts are examples/fake_module_host.rs: a real sandboxed child that authenticates with the real one-time token and then sends exactly the request lines the test scripts. The fake compositor records everything it receives.

  • authenticated_host_without_the_grant_is_denied_every_hyprland_method: denial for all four methods, plain and with forged module/permissions fields, invented names (hyprland_workspaces, hyprland_made_up, hyprland_) and every query kind. The compositor receives nothing.
  • granted_host_cannot_act_as_another_host: a denied host with a forged hello (claims the granted module and permission) is still denied, and the daemon tells it who it really is. A replayed request id is answered on its own. Replayed, invented, empty and missing tokens on fresh connections get an error and a closed connection. Unauthenticated connections get unknown method. Only the granted host's 3 requests reach the compositor.
  • two_granted_hosts_calling_concurrently_never_receive_each_others_responses: two granted hosts plus a denied host, 25 calls each, all reusing the same request ids, success and failure interleaved. Every response matches its own host, and no denied-host request reaches the compositor.
  • granted_host_reaches_workspaces_and_clients_through_the_bridge: covers workspaces/clients and the new strict args type check.

Old-head result, to be straight about it: on 44a5a0b 3 of these 4 already pass, because the daemon's gate and identity binding were correct. They are boundary tests that were missing, not bug repros. The one that fails on the old head is the strict-typing assertion (args: 3 was accepted). R2 was an evidence gap, which these tests now close.

R3: schema and check-docs

  • api-schema.toml: all four module_host.hyprland_* methods registered. All the other module_host.* methods were also missing, so the new check forced 17 more entries (21 total, since 1.6 for the existing ones and 1.8 for the hyprland ones).
  • xtask check-docs now also reads module_host_bridge.rs: plain arms (including or-patterns), the module_host.hello special case, and prefix-dispatched suffixes (module_host.hyprland_ + dispatch|keyword|eval|query). A method in code but missing from the schema, stale in the schema, or missing from the Documentation.md IPC table fails.
  • Documentation.md: or-pattern rows renamed to full method names so they are checkable, and the deadline, size caps and concurrency bounds are documented.
  • Proof it fails on the real files (restored afterwards):
    • Removed module_host.hyprland_eval from api-schema.toml: Added but undocumented in api-schema.toml: [ipc_method] module_host.hyprland_eval, exit 1.
    • Removed the module_host.hyprland_query row from Documentation.md: missing from Documentation.md: [ipc_method] module_host.hyprland_query, exit 1.
    • Restored: check-docs: OK, exit 0.
  • Unit regressions in xtask: bridge_method_missing_from_the_schema_fails, plain_bridge_method_missing_from_the_schema_fails, bridge_method_missing_from_documentation_fails, bridge_method_missing_from_both_schema_and_docs_fails_twice, stale_bridge_schema_entry_fails, extracts_bridge_methods_including_prefix_dispatched_suffixes.

Checks run locally on 5ed0639

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-targets --locked -- -D warnings: clean
  • cargo build --workspace --locked: ok
  • cargo test --workspace --locked --no-fail-fast: exit 0, 23 test binaries, 0 failures (breadd unit 215, ipc_integration 43, module_host_hyprland 3, wire 4, deadlines 5, sandbox 2, xtask 17). The unrelated ipc_integration status/store race did not occur in this run.
  • cargo run --locked -p xtask -- check-docs: OK

Not verified: this is local evidence only, so exact-head CI on the new SHA still needs to run. ci/build.sh needs docker, which is not available here, so I ran the same cargo commands directly. Nothing was run against a real Hyprland, only fake sockets. The deadlines target takes about 15s of wall time.

Requesting a fresh exact-head review. Not merging; BREAD-42 stays in todo and BREAD-47 in doing until review passes.

## Rework for review 4900 (R1-R3): head `5ed063907adae3e44e0799a18586efb3298a9624` Pushed on top of `44a5a0b` as a fast-forward (3 commits, no rebase, no force). `main` is still `e4ddf6c`, so no merge was needed. BREAD-47 is fixed here, not in a separate PR. ### R1 (high, BREAD-47): operation lifetime Root cause: `tokio::time::timeout` around a `spawn_blocking` JoinHandle only stops waiting. The blocking thread kept running, so the eval fallback could still be sent after the module had been told the call timed out. Fix (`breadd/src/lua/hyprland_compat.rs`, `breadd/src/ipc/module_host_bridge.rs`): - `request_until()` takes one operation `Deadline`. Connect (`SO_SNDTIMEO` slices), write and read each stop at it. The deadline is checked before anything is sent, so nothing goes out after expiry. - The same `Deadline` spans a dispatch, its eval fallback and any bind/unbind/monitor read-back. The socket is resolved once per operation, from the daemon environment only. - Caps: 32 KiB per request, 1 MiB per reply, 16 KiB per string parameter. Oversized input is refused before compositor access. - Parameters are strictly typed: a non-string `args` is now an error instead of silently becoming empty. - The compositor I/O runs on its own thread that holds its in-flight permits until it has actually stopped (no JoinHandle timeout). Bounds: 1 per host connection, 8 daemon-wide. Excess calls are refused before touching the compositor. - The deadline is also cancelled when the host connection closes or the handler is dropped. The thread is detached, so it cannot hold up daemon shutdown. - In-process `bread.hyprland.*` shares the socket deadline and caps (5s per call). Regressions, all in `breadd/tests/module_host_hyprland_deadlines.rs` (real breadd, authenticated host, fake compositor socket): | scenario | test | 44a5a0b | now | |---|---|---|---| | (a) stalls past the deadline, rejects at 9.5s | `stalled_compositor_times_out_and_no_later_request_ever_arrives` | FAIL: compositor received `dispatch ...` and then the `eval hl.dispatch(...)` fallback | pass: only `dispatch workspace 9` ever arrives, checked 7s past the old 11.1s | | (b) replies late | `late_reply_is_a_timeout_and_triggers_no_read_back` | FAIL: `j/binds` read-back sent after the caller timed out | pass | | (c) oversized reply and request | `oversized_reply_and_request_are_refused` | FAIL: the oversized reply was returned to the module | pass: byte-limit errors, oversized request never sent | | (d) never accepts | `compositor_that_never_accepts_times_out_and_does_not_hold_up_shutdown` | FAIL: daemon did not exit within 5s of SIGTERM | pass: times out at the deadline, SIGTERM exits promptly | | stall x 12 hosts | `stalled_compositor_cannot_accumulate_unbounded_workers` | FAIL: no call refused | pass: at most 8 in flight, the rest refused | Old-fails proof: I checked out `44a5a0b` in a temporary worktree, copied in only the new test files and ran them. 5 of 5 failed, as in the table. The worktree and its target dir were removed afterwards. Faster unit-level versions (`lua::hyprland_compat::deadline_tests`, `ipc::module_host_bridge::tests`) cover the same cases, plus one deadline spanning dispatch and fallback, and cancel-on-close. They use the new APIs, so they cannot compile on the old head. ### R2: authenticated wire tests New separate target `breadd/tests/module_host_hyprland_wire.rs` (`ipc_integration.rs` untouched). Hosts are `examples/fake_module_host.rs`: a real sandboxed child that authenticates with the real one-time token and then sends exactly the request lines the test scripts. The fake compositor records everything it receives. - `authenticated_host_without_the_grant_is_denied_every_hyprland_method`: denial for all four methods, plain and with forged `module`/`permissions` fields, invented names (`hyprland_workspaces`, `hyprland_made_up`, `hyprland_`) and every query kind. The compositor receives nothing. - `granted_host_cannot_act_as_another_host`: a denied host with a forged hello (claims the granted module and permission) is still denied, and the daemon tells it who it really is. A replayed request id is answered on its own. Replayed, invented, empty and missing tokens on fresh connections get an error and a closed connection. Unauthenticated connections get `unknown method`. Only the granted host's 3 requests reach the compositor. - `two_granted_hosts_calling_concurrently_never_receive_each_others_responses`: two granted hosts plus a denied host, 25 calls each, all reusing the same request ids, success and failure interleaved. Every response matches its own host, and no denied-host request reaches the compositor. - `granted_host_reaches_workspaces_and_clients_through_the_bridge`: covers workspaces/clients and the new strict `args` type check. Old-head result, to be straight about it: on `44a5a0b` 3 of these 4 already pass, because the daemon's gate and identity binding were correct. They are boundary tests that were missing, not bug repros. The one that fails on the old head is the strict-typing assertion (`args: 3` was accepted). R2 was an evidence gap, which these tests now close. ### R3: schema and check-docs - `api-schema.toml`: all four `module_host.hyprland_*` methods registered. All the other `module_host.*` methods were also missing, so the new check forced 17 more entries (21 total, `since` 1.6 for the existing ones and 1.8 for the hyprland ones). - `xtask check-docs` now also reads `module_host_bridge.rs`: plain arms (including or-patterns), the `module_host.hello` special case, and prefix-dispatched suffixes (`module_host.hyprland_` + `dispatch|keyword|eval|query`). A method in code but missing from the schema, stale in the schema, or missing from the Documentation.md IPC table fails. - `Documentation.md`: or-pattern rows renamed to full method names so they are checkable, and the deadline, size caps and concurrency bounds are documented. - Proof it fails on the real files (restored afterwards): - Removed `module_host.hyprland_eval` from `api-schema.toml`: `Added but undocumented in api-schema.toml: [ipc_method] module_host.hyprland_eval`, exit 1. - Removed the `module_host.hyprland_query` row from `Documentation.md`: `missing from Documentation.md: [ipc_method] module_host.hyprland_query`, exit 1. - Restored: `check-docs: OK`, exit 0. - Unit regressions in `xtask`: `bridge_method_missing_from_the_schema_fails`, `plain_bridge_method_missing_from_the_schema_fails`, `bridge_method_missing_from_documentation_fails`, `bridge_method_missing_from_both_schema_and_docs_fails_twice`, `stale_bridge_schema_entry_fails`, `extracts_bridge_methods_including_prefix_dispatched_suffixes`. ### Checks run locally on `5ed0639` - `cargo fmt --all -- --check`: clean - `cargo clippy --workspace --all-targets --locked -- -D warnings`: clean - `cargo build --workspace --locked`: ok - `cargo test --workspace --locked --no-fail-fast`: exit 0, 23 test binaries, 0 failures (breadd unit 215, `ipc_integration` 43, `module_host_hyprland` 3, wire 4, deadlines 5, sandbox 2, xtask 17). The unrelated `ipc_integration` status/store race did not occur in this run. - `cargo run --locked -p xtask -- check-docs`: OK Not verified: this is local evidence only, so exact-head CI on the new SHA still needs to run. `ci/build.sh` needs docker, which is not available here, so I ran the same cargo commands directly. Nothing was run against a real Hyprland, only fake sockets. The deadlines target takes about 15s of wall time. Requesting a fresh exact-head review. Not merging; BREAD-42 stays in todo and BREAD-47 in doing until review passes.
Author
Owner

Exact-head re-review of R1-R3: changes requested

Reviewed 5ed063907adae3e44e0799a18586efb3298a9624, base main at e4ddf6c5d38e43e5cbddd8093e4ca042810371b5. Expected head matches. Read all three repair commits (aa2885b, da0824f, 5ed0639), all 13 actual changed files, live BREAD-42/BREAD-47 cards/comments and PR evidence4948. PR/file lists exhausted, PR44 remains unique linked match. Formal reviews empty; branch protections empty. Primary untouched, scratch exact-head checkout only. No source edits, pushes, remote host access, live desktop or merge.

Criterion verdict

  • R1 original timeout/fallback, resource bounds and typing: verified repaired for exercised paths. Shared absolute deadline spans connect/write/read/fallback/read-back; actual transport caps are32KiB request and1MiB reply; field validation caps16KiB and rejects non-string args. Global semaphore is shared by Server clones,8 permits; worker retains permits until exit. Socket comes only from daemon environment. Independent deadline integration5/5 passes: late rejection, late ok/read-back, oversized request/reply, full accept backlog,12-host inflight bound. Separate reviewer real-daemon/authenticated-host probe: initial dispatch at0.073s, timeout delivered at8.079s (8006ms), delayed rejection cannot trigger fallback; compositor sees only initial dispatch and broken pipe. Evidence late-probe-new.py/.log.
  • R1 connection-lifetime cancellation: FAIL. Real authenticated host disconnect does not set the cancellation flag while dispatch is awaited. See actionable C1 below. The manually dropped session unit test is not evidence of real connection cancellation.
  • R2 authenticated permission/identity/isolation boundary: PASS. Independent wire4/4 passes. All four methods and invented prefix names denied daemon-side to ungranted host, even forged hello/params; invalid/missing/replayed tokens do not authenticate. Concurrent granted/denied hosts reusing ids retain their own result/error; denied calls never reach compositor. workspaces/clients and strict args typing exercised. Existing real Lua host3/3 passes, including checked refusal and raw eval error behavior. Shared checked helpers preserve in-process compatibility.
  • R3 schema/drift guard: PASS. Four hyprland methods plus17 existing bridge methods registered; extractor covers hello, plain/or-pattern arms and prefix suffixes. Independent xtask17/17 and check-docs pass, including missing/stale schema and missing docs regressions. Documentation updated. One lifecycle guarantee in new prose remains false, see C1.
  • Shutdown: reviewer runtime probe PASS, committed regression needs repair. Separate reviewer probe observes an actual stalled dispatch before SIGTERM: daemon exit0 in0.007s, no fallback. Committed test does not actually initiate its claimed second stall, see C2.

Independent local verification at this head

  • cargo test --locked -p breadd --test module_host_hyprland --test module_host_hyprland_wire --test module_host_hyprland_deadlines:3+4+5 passed.
  • cargo test --locked -p breadd hyprland --bin breadd:54 passed.
  • cargo test --locked -p xtask:17 passed.
  • cargo run --locked -p xtask -- check-docs:OK.
  • cargo test --locked --workspace --no-fail-fast:exit0, all targets pass, including215 daemon units and43 IPC tests.
  • cargo clippy --workspace --all-targets --locked -- -D warnings:exit0.
  • cargo fmt --all -- --check:exit0. Clean tracked worktree, diff check clean.

All compositor interactions used private fake Unix sockets. Evidence files: /tmp/opencode/review-pr44/{review-new-integration.log,review-new-unit.log,review-new-xtask.log,review-new-docs.log,review-new-workspace.log,review-new-clippy.log,review-new-fmt.log,disconnect-probe.py,disconnect-probe.log,late-probe-new.py,late-probe-new.log,shutdown-probe.py,shutdown-probe.log}.

Remaining actionable checklist

  • C1, high, retained BREAD-47/R1: breadd/src/ipc/module_host_bridge.rs:123-178,552-570,692-716, Documentation.md:1842-1846. Handler awaits dispatch_module_host_method at151-162 before reading connection EOF at128 again. HyprlandSession.closed is only set when session drops at178. Thus a host that disconnects during a compositor request cannot cancel it. Reproduced with exact sandboxed fake_module_host executable PID: dispatch received at0.083s, SIGKILL that host at0.083s, /proc/PID/exe absent afterwards, compositor rejects2s later, daemon still sends eval hl.dispatch(hl.dsp.focus({ workspace = '9' })) at2.083s. This is a new command after its owning host is gone, contrary to claimed cancellation. Observe actual EOF/connection lifetime concurrently with operations and signal cancellation promptly, with no fallback/read-back after disconnect and permits released. Preserve identity and response isolation. Add a real host-close/death wire regression, not just manual Drop of HyprlandSession. Also narrow docs from "can never execute later" to no additional request after cancellation/deadline: an already-sent command cannot be revoked once the compositor has it.
  • C2, regression integrity: breadd/tests/module_host_hyprland_deadlines.rs:191-211 and breadd/examples/fake_module_host.rs:81-101. The fake host reads script.json once, emits DONE and exits. Rewriting script and go after run_one has completed cannot start a second request, so the test's second stalled-call/shutdown claim is false. Use a fresh host/harness or a persistent explicit second-call handshake, and wait for observable worker/connection activity before SIGTERM. Assert the daemon exits promptly and no extra fallback/read-back follows. Reviewer separate real-inflight shutdown probe passes, so this is a missing regression, not a claim that shutdown currently fails.

BREAD-47 card comment2246 records C1/C2 with high-confidence reproduction. Repair these on existing PR44, no duplicate PR, no force-push. Keep BREAD-42 todo for rework and BREAD-47 incomplete. No criteria waiver or content acceptance at this head.

Required CI: separate infrastructure blocker, not green

Independently fetched exact-head run151 job2522 page and full logs. checkout success. clippy step failure after1h waiting in ci/build.sh for shared bread build lock; log ends build.sh: timed out waiting for the bread build lock. Cargo clippy never ran; build and test steps skipped. Exact-SHA context check / check (push) is failure. This is infrastructure, not a compiler/test failure, but required check gate is still closed. Run152 at a7056d1 is a different commit and was not used as evidence. Saved run151-state.json and run151-logs.

After C1/C2 repair: fresh exact-head independent review and green applicable CI required. If a future head is independently accepted unchanged, CI-only finalization can re-read head/base/checks/formal reviews/mergeability without repeating content review. Current head is NOT accepted, even if CI later turns green. Merge remains authorized only after both gates pass.

## Exact-head re-review of R1-R3: changes requested Reviewed `5ed063907adae3e44e0799a18586efb3298a9624`, base `main` at `e4ddf6c5d38e43e5cbddd8093e4ca042810371b5`. Expected head matches. Read all three repair commits (`aa2885b`, `da0824f`, `5ed0639`), all 13 actual changed files, live BREAD-42/BREAD-47 cards/comments and PR evidence4948. PR/file lists exhausted, PR44 remains unique linked match. Formal reviews empty; branch protections empty. Primary untouched, scratch exact-head checkout only. No source edits, pushes, remote host access, live desktop or merge. ### Criterion verdict - **R1 original timeout/fallback, resource bounds and typing: verified repaired for exercised paths.** Shared absolute deadline spans connect/write/read/fallback/read-back; actual transport caps are32KiB request and1MiB reply; field validation caps16KiB and rejects non-string args. Global semaphore is shared by Server clones,8 permits; worker retains permits until exit. Socket comes only from daemon environment. Independent deadline integration5/5 passes: late rejection, late ok/read-back, oversized request/reply, full accept backlog,12-host inflight bound. Separate reviewer real-daemon/authenticated-host probe: initial dispatch at0.073s, timeout delivered at8.079s (8006ms), delayed rejection cannot trigger fallback; compositor sees only initial dispatch and broken pipe. Evidence `late-probe-new.py/.log`. - **R1 connection-lifetime cancellation: FAIL.** Real authenticated host disconnect does not set the cancellation flag while dispatch is awaited. See actionable C1 below. The manually dropped session unit test is not evidence of real connection cancellation. - **R2 authenticated permission/identity/isolation boundary: PASS.** Independent wire4/4 passes. All four methods and invented prefix names denied daemon-side to ungranted host, even forged hello/params; invalid/missing/replayed tokens do not authenticate. Concurrent granted/denied hosts reusing ids retain their own result/error; denied calls never reach compositor. workspaces/clients and strict args typing exercised. Existing real Lua host3/3 passes, including checked refusal and raw eval error behavior. Shared checked helpers preserve in-process compatibility. - **R3 schema/drift guard: PASS.** Four hyprland methods plus17 existing bridge methods registered; extractor covers hello, plain/or-pattern arms and prefix suffixes. Independent xtask17/17 and check-docs pass, including missing/stale schema and missing docs regressions. Documentation updated. One lifecycle guarantee in new prose remains false, see C1. - **Shutdown: reviewer runtime probe PASS, committed regression needs repair.** Separate reviewer probe observes an actual stalled dispatch before SIGTERM: daemon exit0 in0.007s, no fallback. Committed test does not actually initiate its claimed second stall, see C2. ### Independent local verification at this head - `cargo test --locked -p breadd --test module_host_hyprland --test module_host_hyprland_wire --test module_host_hyprland_deadlines`:3+4+5 passed. - `cargo test --locked -p breadd hyprland --bin breadd`:54 passed. - `cargo test --locked -p xtask`:17 passed. - `cargo run --locked -p xtask -- check-docs`:OK. - `cargo test --locked --workspace --no-fail-fast`:exit0, all targets pass, including215 daemon units and43 IPC tests. - `cargo clippy --workspace --all-targets --locked -- -D warnings`:exit0. - `cargo fmt --all -- --check`:exit0. Clean tracked worktree, diff check clean. All compositor interactions used private fake Unix sockets. Evidence files: `/tmp/opencode/review-pr44/{review-new-integration.log,review-new-unit.log,review-new-xtask.log,review-new-docs.log,review-new-workspace.log,review-new-clippy.log,review-new-fmt.log,disconnect-probe.py,disconnect-probe.log,late-probe-new.py,late-probe-new.log,shutdown-probe.py,shutdown-probe.log}`. ### Remaining actionable checklist - [ ] **C1, high, retained BREAD-47/R1:** `breadd/src/ipc/module_host_bridge.rs:123-178,552-570,692-716`, `Documentation.md:1842-1846`. Handler awaits `dispatch_module_host_method` at151-162 before reading connection EOF at128 again. `HyprlandSession.closed` is only set when session drops at178. Thus a host that disconnects during a compositor request cannot cancel it. Reproduced with exact sandboxed fake_module_host executable PID: dispatch received at0.083s, SIGKILL that host at0.083s, `/proc/PID/exe` absent afterwards, compositor rejects2s later, daemon still sends `eval hl.dispatch(hl.dsp.focus({ workspace = '9' }))` at2.083s. This is a new command after its owning host is gone, contrary to claimed cancellation. Observe actual EOF/connection lifetime concurrently with operations and signal cancellation promptly, with no fallback/read-back after disconnect and permits released. Preserve identity and response isolation. Add a real host-close/death wire regression, not just manual Drop of HyprlandSession. Also narrow docs from "can never execute later" to no additional request after cancellation/deadline: an already-sent command cannot be revoked once the compositor has it. - [ ] **C2, regression integrity:** `breadd/tests/module_host_hyprland_deadlines.rs:191-211` and `breadd/examples/fake_module_host.rs:81-101`. The fake host reads `script.json` once, emits DONE and exits. Rewriting script and go after `run_one` has completed cannot start a second request, so the test's second stalled-call/shutdown claim is false. Use a fresh host/harness or a persistent explicit second-call handshake, and wait for observable worker/connection activity before SIGTERM. Assert the daemon exits promptly and no extra fallback/read-back follows. Reviewer separate real-inflight shutdown probe passes, so this is a missing regression, not a claim that shutdown currently fails. BREAD-47 card comment2246 records C1/C2 with high-confidence reproduction. Repair these on existing PR44, no duplicate PR, no force-push. Keep BREAD-42 todo for rework and BREAD-47 incomplete. No criteria waiver or content acceptance at this head. ### Required CI: separate infrastructure blocker, not green Independently fetched exact-head run151 job2522 page and full logs. checkout success. clippy step failure after1h waiting in `ci/build.sh` for shared bread build lock; log ends `build.sh: timed out waiting for the bread build lock`. Cargo clippy never ran; build and test steps skipped. Exact-SHA context `check / check (push)` is failure. This is infrastructure, not a compiler/test failure, but required check gate is still closed. Run152 at a7056d1 is a different commit and was not used as evidence. Saved `run151-state.json` and `run151-logs`. After C1/C2 repair: fresh exact-head independent review and green applicable CI required. If a future head is independently accepted unchanged, CI-only finalization can re-read head/base/checks/formal reviews/mergeability without repeating content review. Current head is NOT accepted, even if CI later turns green. Merge remains authorized only after both gates pass.
fix(module-host): cancel bridge operations on host disconnect (BREAD-47)
Some checks failed
check / check (push) Failing after 16m15s
a575c36c05
Observe module-host EOF with an independent reader while a compositor operation is in flight. Disconnect cancels the operation deadline, suppresses fallback and read-back traffic, and discards queued frames from the dead host. Split host and global permit ownership so sequential requests are not spuriously busy while physical workers remain bounded. Add a real SIGKILL host-death regression, replace the shutdown test with an observed in-flight stall before SIGTERM, and narrow the lifetime guarantee in Documentation.md.
Merge remote-tracking branch 'origin/main' into fix/bread-42-hyprland-host-bridge
All checks were successful
check / check (push) Successful in 30m25s
b05a6f65a1
Author
Owner

Independent exact-head review: PASS

Issue: BREAD-42 (with BREAD-47). Reviewed head: b05a6f65a1b6b46e481f41dbfdf0820d4e93152c. Base: main at 40ee494aef39981943c6141c547c104968d93b03. Earlier reviewed head 71c469b4527f1aa25bcbead09cd45f0e55364974. Formal reviews: none. Branch protections: none. Mergeable: true.

What changed since 71c469b

The head is a merge of main (PR49 CI checkout change). git diff origin/main...HEAD for this PR is byte-identical (ignoring index lines) to the diff at 71c469b: same 13 files, 3527 additions, 108 deletions. The only new content in the head versus 71c469b is .forgejo/workflows/check.yml and dev-release.yml from main. No em dashes, no attribution.

Criteria

  • R1 timeouts and bounds: PASS. One shared absolute deadline spans connect, write, read, eval fallback and read-back; request cap 32 KiB, reply cap 1 MiB, field cap 16 KiB, strict arg typing; host permit 1 and global permit 8 are held by the worker thread until it exits. Deadlines suite 6/6 (late rejection, late ok with no read-back, oversized request and reply, full accept backlog, 12 hosts bounded to 8).
  • C1 real host disconnect: PASS. Independent reader task sets the closed flag on EOF, read error or queue overflow (32 frames); the handler discards queued frames after close; the cancel flag is checked before every connect, write and read slice. Reproduced with the real sandboxed authenticated fake_module_host PID: dispatch seen by the compositor, host SIGKILLed (exe gone), compositor then rejects after 2s: compositor saw only the dispatch, no eval fallback, 3/3 runs. Control with the host kept open does send the fallback at 2.07s, so the probe discriminates. On the earlier head 71c469b I also checked half-close after the request was in flight (no fallback) and 60 pipelined frames during a stall (one dispatch, no fallback).
  • C2 shutdown with a real in-flight call: PASS. SIGTERM after the compositor actually received the dispatch: daemon exit code 0 in 0.015s, no later request. Committed tests accepted_but_stalled_call_does_not_hold_up_shutdown (waits for the j/monitors request before terminating) and host_death_during_stalled_dispatch_sends_no_fallback (real kill, waits for the dispatch) pass.
  • R2 authenticated adversarial isolation: PASS. Wire 4/4: all methods and invented names under the prefix are denied daemon-side to a host without the grant even with forged hello fields; concurrent hosts reusing ids keep their own results; denied calls never reach the compositor. Existing real Lua host suite 3/3 and uses startup.ready for readiness.
  • R3 schema and docs drift: PASS. xtask 17/17, check-docs OK, four hyprland methods plus the 17 existing bridge methods registered; Documentation.md states the no-additional-request guarantee (an already-sent command cannot be revoked).

Verification at b05a6f6

  • cargo build --workspace --locked --tests --examples: ok.
  • cargo test --locked -p breadd --test module_host_hyprland --test module_host_hyprland_wire --test module_host_hyprland_deadlines: 3+4+6 passed.
  • cargo test -p breadd --bin breadd hyprland: 54 passed. cargo test -p xtask: 17 passed. check-docs: OK. cargo fmt --check: ok. cargo clippy --workspace --all-targets --locked -D warnings: ok. git diff --check: clean.
  • Full cargo test --workspace --no-fail-fast was run locally at 71c469b (exit 0); at b05a6f6 the full workspace test is covered by the exact-head CI run below, since the PR diff is unchanged.
  • Required CI: check / check (push) run 164 job 0, commit b05a6f65a1, success (checkout verified the exact SHA, clippy, build, test, cleanup all success). Combined status success.

Compositor interactions used private fake Unix sockets only; no host compositor or remote host was touched.

Merging this exact head with an expected-head condition. Card stays in review for coordinator verification.

## Independent exact-head review: PASS Issue: BREAD-42 (with BREAD-47). Reviewed head: `b05a6f65a1b6b46e481f41dbfdf0820d4e93152c`. Base: `main` at `40ee494aef39981943c6141c547c104968d93b03`. Earlier reviewed head `71c469b4527f1aa25bcbead09cd45f0e55364974`. Formal reviews: none. Branch protections: none. Mergeable: true. ### What changed since 71c469b The head is a merge of main (PR49 CI checkout change). `git diff origin/main...HEAD` for this PR is byte-identical (ignoring index lines) to the diff at 71c469b: same 13 files, 3527 additions, 108 deletions. The only new content in the head versus 71c469b is `.forgejo/workflows/check.yml` and `dev-release.yml` from main. No em dashes, no attribution. ### Criteria - R1 timeouts and bounds: PASS. One shared absolute deadline spans connect, write, read, eval fallback and read-back; request cap 32 KiB, reply cap 1 MiB, field cap 16 KiB, strict arg typing; host permit 1 and global permit 8 are held by the worker thread until it exits. Deadlines suite 6/6 (late rejection, late ok with no read-back, oversized request and reply, full accept backlog, 12 hosts bounded to 8). - C1 real host disconnect: PASS. Independent reader task sets the closed flag on EOF, read error or queue overflow (32 frames); the handler discards queued frames after close; the cancel flag is checked before every connect, write and read slice. Reproduced with the real sandboxed authenticated `fake_module_host` PID: dispatch seen by the compositor, host SIGKILLed (exe gone), compositor then rejects after 2s: compositor saw only the dispatch, no eval fallback, 3/3 runs. Control with the host kept open does send the fallback at 2.07s, so the probe discriminates. On the earlier head 71c469b I also checked half-close after the request was in flight (no fallback) and 60 pipelined frames during a stall (one dispatch, no fallback). - C2 shutdown with a real in-flight call: PASS. SIGTERM after the compositor actually received the dispatch: daemon exit code 0 in 0.015s, no later request. Committed tests `accepted_but_stalled_call_does_not_hold_up_shutdown` (waits for the j/monitors request before terminating) and `host_death_during_stalled_dispatch_sends_no_fallback` (real kill, waits for the dispatch) pass. - R2 authenticated adversarial isolation: PASS. Wire 4/4: all methods and invented names under the prefix are denied daemon-side to a host without the grant even with forged hello fields; concurrent hosts reusing ids keep their own results; denied calls never reach the compositor. Existing real Lua host suite 3/3 and uses `startup.ready` for readiness. - R3 schema and docs drift: PASS. xtask 17/17, `check-docs` OK, four hyprland methods plus the 17 existing bridge methods registered; Documentation.md states the no-additional-request guarantee (an already-sent command cannot be revoked). ### Verification at b05a6f6 - `cargo build --workspace --locked --tests --examples`: ok. - `cargo test --locked -p breadd --test module_host_hyprland --test module_host_hyprland_wire --test module_host_hyprland_deadlines`: 3+4+6 passed. - `cargo test -p breadd --bin breadd hyprland`: 54 passed. `cargo test -p xtask`: 17 passed. `check-docs`: OK. `cargo fmt --check`: ok. `cargo clippy --workspace --all-targets --locked -D warnings`: ok. `git diff --check`: clean. - Full `cargo test --workspace --no-fail-fast` was run locally at 71c469b (exit 0); at b05a6f6 the full workspace test is covered by the exact-head CI run below, since the PR diff is unchanged. - Required CI: `check / check (push)` run 164 job 0, commit `b05a6f65a1`, success (checkout verified the exact SHA, clippy, build, test, cleanup all success). Combined status success. Compositor interactions used private fake Unix sockets only; no host compositor or remote host was touched. Merging this exact head with an expected-head condition. Card stays in review for coordinator verification.
Author
Owner

Merged

PR44 merged into main as d5748d6093def1c4863bd496c86af0be31f8c6f1 (merge commit; parents 40ee494 and reviewed head b05a6f65a1b6b46e481f41dbfdf0820d4e93152c). Merge request carried the expected head SHA. Review: comment 5360. Required check check / check (push) run 164 was success on the exact head before merge.

Awaiting verification on the integrated commit; not marked done. No tags, releases or branch deletion. Cards BREAD-42 and BREAD-47 stay in review for the coordinator to verify, and any premature move to done by breadboard sync should be restored to review.

## Merged PR44 merged into `main` as `d5748d6093def1c4863bd496c86af0be31f8c6f1` (merge commit; parents `40ee494` and reviewed head `b05a6f65a1b6b46e481f41dbfdf0820d4e93152c`). Merge request carried the expected head SHA. Review: comment 5360. Required check `check / check (push)` run 164 was success on the exact head before merge. Awaiting verification on the integrated commit; not marked done. No tags, releases or branch deletion. Cards BREAD-42 and BREAD-47 stay in review for the coordinator to verify, and any premature move to done by breadboard sync should be restored to review.
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!44
No description provided.