test(derive): close seventh mutation shard

Prove all state, async, and Result registration combinations and the exact no-generated-component repair diagnostic.

req: component/003

req: derive_handler/003

req: test/020

req: test/021

req: test/022

req: test/023
This commit is contained in:
slhx agent
2026-07-17 14:47:17 +02:00
parent d1af300bd4
commit 5d6486c22c
2 changed files with 64 additions and 7 deletions
+1 -1
View File
@@ -21,7 +21,7 @@
- [ ] **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-axum`, `hemx-build`, `hemx-core`, `hemx-js`, and the full `hemx-test` package 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; broad survivors currently remain in `hemx-derive` and `hemx-lsp` outside already-clean focused contracts. The xtask mutation runner now creates shard output parents before invoking mutest, fixing first-use failure for newly sharded packages. `hemx-derive` public shards `1/8` through `6/8` are clean. Shard `6/8` passed with 60 mutants (50 caught, 10 unviable) after malformed parameter-manifest, handler-pattern, app diagnostic, and component registration guard coverage; an unreachable empty-handler branch was deleted, and static quote-owned syntax parsing is narrowly classified as invariant-equivalent. Shards `7/8` and `8/8` remain. 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; broad survivors currently remain in `hemx-derive` and `hemx-lsp` outside already-clean focused contracts. The xtask mutation runner now creates shard output parents before invoking mutest, fixing first-use failure for newly sharded packages. `hemx-derive` public shards `1/8` through `7/8` are clean. Shard `7/8` passed with 60 mutants (45 caught, 15 unviable) after exact coverage of all state/async/result registration shapes and the no-generated-component repair diagnostic. Shard `8/8` remains. 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
+63 -6
View File
@@ -1016,13 +1016,14 @@ fn compile_error(message: &str) -> TokenStream {
mod tests {
use super::{
add_app_registry_helper, add_component_register_helper, client_handler_has_inputs,
component_handler_names, expand_handler_function, form_contract_errors, form_decode_fields,
form_fields, form_impl_generics, form_model_type, form_resource_id, generic_inner_type,
handle_params, handle_requires_form, handler_arg_names, handler_form_model_type,
handler_placement, handler_syms_path, has_form_param, has_non_unit_return, is_type_named,
component_contract_errors, component_handler_names, component_registration_call,
expand_handler_function, form_contract_errors, form_decode_fields, form_fields,
form_impl_generics, form_model_type, form_resource_id, generic_inner_type, handle_params,
handle_requires_form, handler_arg_names, handler_form_model_type, handler_placement,
handler_syms_path, has_form_param, has_non_unit_return, is_type_named,
join_contract_errors, missing_component_handlers, missing_form_generated_files_message,
missing_handle_params, missing_handler_generated_files_message, parser_type,
returns_result, rust_ident, syms_contains_handle, HandlerPlacement,
returns_result, rust_ident, syms_contains_handle, ComponentHandler, HandlerPlacement,
};
use quote::{quote, ToTokens};
use syn::{parse_quote, ItemFn, Type};
@@ -1469,6 +1470,55 @@ mod tests {
let _ = std::fs::remove_file(path);
}
#[test]
fn component_registration_selects_each_state_async_result_shape() {
let component_ident: syn::Ident = parse_quote!(todos);
let expected = [
(0, false, false, quote!(.on(super::todos::save, save))),
(0, false, true, quote!(.on_result(super::todos::save, save))),
(0, true, false, quote!(.on_async(super::todos::save, save))),
(
0,
true,
true,
quote!(.on_async_result(super::todos::save, save)),
),
(1, false, false, quote!(.on_state(super::todos::save, save))),
(
1,
false,
true,
quote!(.on_state_result(super::todos::save, save)),
),
(
1,
true,
false,
quote!(.on_state_async(super::todos::save, save)),
),
(
1,
true,
true,
quote!(.on_state_async_result(super::todos::save, save)),
),
];
for (typed_arg_count, is_async, returns_result, expected) in expected {
let handler = ComponentHandler {
ident: parse_quote!(save),
is_async,
returns_result,
typed_arg_count,
};
assert_eq!(
component_registration_call(&handler, &component_ident).to_string(),
expected.to_string(),
"args={typed_arg_count} async={is_async} result={returns_result}"
);
}
// test req: component/003 req: derive_handler/003
}
#[test]
fn component_handlers_match_generated_handles() {
let path = std::env::temp_dir().join("hemx-derive-component-test.syms");
@@ -1495,7 +1545,14 @@ mod tests {
vec!["delete"]
);
let _ = std::fs::remove_file(path);
let _ = std::fs::remove_file(&path);
assert_eq!(
component_contract_errors(&path, Some("missing"), &items),
vec![
"#[hemx::component(\"missing\")] does not match any generated handles; no generated components with handles are available; add a data-hemx-handle to the component template or check build.rs generation",
"#[hemx::component] handler(s) not declared by this component's generated handles: create; move them to the matching component module or add data-hemx-handle in .heml",
]
);
}
#[test]