diff --git a/PLAN.md b/PLAN.md index 9ae1e7b..6c7c5af 100644 --- a/PLAN.md +++ b/PLAN.md @@ -18,10 +18,10 @@ ## 2. Make mutation testing a reproducible release gate -- [ ] **State:** In progress — the package-native capped xtask entry point is reachable, rejects unknown packages and invalid shards, propagates mutest failure, and mutation-tests `hemx`, `hemx-axum`, `hemx-build`, `hemx-core`, `hemx-derive`, `hemx-host`, `hemx-js`, `hemx-sync`, and `hemx-test` cleanly; full package closure remains. +- [ ] **State:** In progress — the package-native capped xtask entry point is reachable, rejects unknown packages and invalid shards, propagates mutest failure, and mutation-tests `hemx`, `hemx-axum`, `hemx-build`, `hemx-core`, `hemx-derive`, `hemx-host`, `hemx-js`, `hemx-sync`, `hemx-sync-macros`, and `hemx-test` cleanly; full package closure remains. - **User value:** maintainers can run one bounded repository command and trust that meaningful Rust logic across every mutation-applicable library is either killed or explicitly justified. - **Build:** add a capped `hemx-xtask` mutation command that invokes `/opt/repositories/mutest`/`mutest` through package-native test targets rather than the broken workspace-wide example path; enumerate only current mutation-applicable library/proc-macro packages; finish adversarial tests or simplify code until every survivor is classified; keep equivalent, invariant-only, and infrastructure-inapplicable classifications inspectable and minimal; document the exact local release command in the existing readiness surface. -- **Blocked by:** none; full package gates remain for `hemx-sync-macros` and `hemx-wasm`. `hemx-lsp` is a binary-only package and is deliberately outside the mutation-applicable library/proc-macro set elected by test/020; its package tests remain part of normal workspace verification. The complete `hemx` gate passes with 30 mutants (9 caught, 21 unviable), the complete `hemx-host` gate passes with 76 mutants (52 caught, 24 unviable), and the complete `hemx-sync` gate passes with 164 mutants (135 caught, 29 unviable). The xtask mutation runner creates shard output parents before invoking mutest, fixing first-use failure for newly sharded packages. All eight deterministic `hemx-derive` shards pass: 480 mutants total, 393 caught and 87 unviable, including final shard `8/8` with 54 mutants (42 caught, 12 unviable) after fail-closed malformed symbol-line handling, exact sorted/deduplicated component discovery, component filtering, non-handler exclusion, and direct quoted compile diagnostics. The mutation entry point accepts validated one-based `SHARD/TOTAL` operands, maps them to native zero-based shards, uses shard-specific output directories, grants repo-owned compiler probes a 120-second floor, and preserves the unsharded gate. All eight deterministic `hemx-build` shards now pass: 1,304 mutants total, 1,070 caught and 234 unviable, including final shard `8/8` with 159 mutants (139 caught, 20 unviable). The complete 470-mutant `hemx-axum` package gate passes with 262 caught and 208 unviable after public page/form/multipart/registry/response/runtime proofs and narrow classification of infallible header parsing and streamed multipart unwrap-equivalent mutants. +- **Blocked by:** none; the full `hemx-wasm` package gate remains. `hemx-lsp` is a binary-only package and is deliberately outside the mutation-applicable library/proc-macro set elected by test/020; its package tests remain part of normal workspace verification. The complete `hemx` gate passes with 30 mutants (9 caught, 21 unviable), the complete `hemx-host` gate passes with 76 mutants (52 caught, 24 unviable), the complete `hemx-sync` gate passes with 164 mutants (135 caught, 29 unviable), and the complete `hemx-sync-macros` gate passes with 33 mutants (14 caught, 19 unviable) after a public proc-macro consumer proved that the attribute preserves and expands its item. The xtask mutation runner creates shard output parents before invoking mutest, fixing first-use failure for newly sharded packages. All eight deterministic `hemx-derive` shards pass: 480 mutants total, 393 caught and 87 unviable, including final shard `8/8` with 54 mutants (42 caught, 12 unviable) after fail-closed malformed symbol-line handling, exact sorted/deduplicated component discovery, component filtering, non-handler exclusion, and direct quoted compile diagnostics. The mutation entry point accepts validated one-based `SHARD/TOTAL` operands, maps them to native zero-based shards, uses shard-specific output directories, grants repo-owned compiler probes a 120-second floor, and preserves the unsharded gate. All eight deterministic `hemx-build` shards now pass: 1,304 mutants total, 1,070 caught and 234 unviable, including final shard `8/8` with 159 mutants (139 caught, 20 unviable). The complete 470-mutant `hemx-axum` package gate passes with 262 caught and 208 unviable after public page/form/multipart/registry/response/runtime proofs and narrow classification of infallible header parsing and streamed multipart unwrap-equivalent mutants. - **Proof:** the new xtask mutation command exits zero within its documented bound, covers each applicable package, emits no unexplained missed mutant, and a deliberate adjacent mutation makes it fail. `cargo run -p hemx-xtask -- test` remains green. req: test/020 req: test/021 ## 3. Elect and enforce the release license policy diff --git a/hemx-sync-macros/tests/presence.rs b/hemx-sync-macros/tests/presence.rs new file mode 100644 index 0000000..20be2b2 --- /dev/null +++ b/hemx-sync-macros/tests/presence.rs @@ -0,0 +1,62 @@ +extern crate self as hemx_sync; + +use hemx_sync_macros::presence; + +pub trait IntoEffect {} + +impl IntoEffect for &'static str {} + +pub trait PresenceScope { + fn presence_channel(&self) -> String; +} + +pub trait PresenceUpdate { + fn channel(&self) -> &str; + fn effect(&self) -> &str; +} + +pub struct PresenceProjection { + channel: String, + effect: Effect, +} + +impl PresenceProjection { + pub fn new(channel: String, effect: Effect) -> Self { + Self { channel, effect } + } +} + +impl PresenceUpdate for PresenceProjection<&'static str> { + fn channel(&self) -> &str { + &self.channel + } + + fn effect(&self) -> &str { + self.effect + } +} + +struct Signal(&'static str); + +impl PresenceScope for Signal { + fn presence_channel(&self) -> String { + self.0.to_owned() + } +} + +#[presence] +fn project(signal: Signal) -> impl IntoEffect { + if signal.0 == "board" { + "joined" + } else { + "left" + } +} + +#[test] +fn public_presence_attribute_preserves_the_item_and_expands_it() { + let update = project(Signal("board")); + assert_eq!(update.channel(), "board"); + assert_eq!(update.effect(), "joined"); + // test req: sync/003 req: sync/005 +}