diff --git a/AGENTS.md b/AGENTS.md index 02ca6f2..cfd2dee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -52,7 +52,7 @@ Keep it stable. Prefer pointers to canonical sources over copied structure, file - Add only durable style, ownership, gotchas, and at most a few stable commands agents should actually run. - Prefer links or pointers to canonical sources over copied lists. - Avoid project trees, architecture maps, generated inventories, current file sizes, issue lists, TODO inventories, and other snapshots that will rot. -- Stable commands: `cargo run -p hemx-xtask -- test`, `cargo run -p hemx-xtask -- mutation [PACKAGE] [SHARD/TOTAL]`, `cargo run -p hemx-xtask -- html-examples-smoke`, `cargo check --workspace`, `redgate refs`. Use the xtask runner for full verification so jobs are capped from local CPU and memory and commands resolve the workspace independently of the caller's directory; use the html_examples smoke for focused repo-owned browser verification of the HTML pattern gallery, no-reload dynamic interactions, and no `/tmp` scripts. Keep fast crate tests, focused browser smoke, and full xtask authority distinct; the full path should stay within a documented 10 minute local timeout or use every deterministic native mutation shard under the same wrapper. req: test/004 req: test/006 req: test/012 req: test/013 req: test/014 req: test/015 req: test/016 req: test/022 req: test/023 +- Stable commands: `cargo run -p hemx-xtask -- test`, `cargo run -p hemx-xtask -- mutation [PACKAGE] [SHARD/TOTAL]`, `cargo run -p hemx-xtask -- html-examples-smoke`, `cargo check --workspace`, `redgate refs`. Use the xtask runner for full verification so jobs are capped from local CPU and memory and commands resolve the workspace independently of the caller's directory; use the html_examples smoke for focused repo-owned browser verification of the HTML pattern gallery, no-reload dynamic interactions, and no `/tmp` scripts. Keep fast crate tests, focused browser smoke, and full xtask authority distinct; mutation shards use one-based `1..=TOTAL` numbering and allow the wrapper's 120-second floor for repo-owned compiler probes. The full path should stay within a documented 10 minute local timeout or use every deterministic mutation shard under the same wrapper. req: test/004 req: test/006 req: test/012 req: test/013 req: test/014 req: test/015 req: test/016 req: test/022 req: test/023 - Example behavior tests should prefer `hemx_test` generated-resource assertion methods over raw slot constants, raw effect/payload matching, or boolean predicates wrapped in opaque `assert!`; failures should include the expectation and actual effects, while rendered target/handle assertions should name the generated resource. Keep browser selector helpers as test adapters only, not authoring APIs. Process-backed tests use the RAII `TestProcess` harness rather than duplicating readiness loops and child cleanup. req: test/008 req: test/009 req: test/010 req: test/017 req: test/018 req: test/019 - Run the workout product exemplar with `cargo run -p hemx-xtask -- workout dev` and open `http://127.0.0.1:3028`; set `HEMX_WORKOUT_ADDR=127.0.0.1:3030` if the default port is busy. Its durable visual direction and recovery expectations live in `examples/workout/DESIGN.md`. req: examples/008 - Use the same Workout command surface for tests, production build, and mobile release: `cargo run -p hemx-xtask -- workout test`, `cargo run -p hemx-xtask -- workout build`, `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-release`, and `HEMX_WORKOUT_ORIGIN=https://workout.example.com cargo run -p hemx-xtask -- workout mobile-verify`; Android/iOS SDKs, store submission targets, and signing remain external blockers, not repo-owned secrets, and do not imply a broad `hemx-mobile` framework. req: examples/006 req: examples/011 req: examples/013 diff --git a/PLAN.md b/PLAN.md index 1dcc385..a2d14b3 100644 --- a/PLAN.md +++ b/PLAN.md @@ -21,7 +21,7 @@ - [ ] **State:** In progress — the package-native capped xtask entry point is reachable, rejects unknown packages, propagates mutest failure, and mutation-tests `hemx-axum`, `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-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts. The mutation entry point now accepts validated native `SHARD/TOTAL` operands with shard-specific output directories while preserving the unsharded gate. `hemx-build` shards `1/4` and `2/4` passed through xtask with 325 mutants each (`1/4`: 280 caught, 45 unviable; `2/4`: 286 caught, 39 unviable); shards `3/4` and `4/4` remain before the package gate is complete. The complete 470-mutant `hemx-axum` package gate now 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-build`, `hemx-derive`, and `hemx-lsp` outside already-clean focused contracts. The mutation entry point now accepts validated native `SHARD/TOTAL` operands with shard-specific output directories while preserving the unsharded gate. The shard wrapper now correctly maps one-based public numbering to mutest's zero-based native API and grants repo-owned compiler-probe tests a 120-second per-mutant floor instead of reporting false timeouts. Corrected `hemx-build` shard `1/8` passed with 163 mutants (87 caught, 76 unviable); shards `2/8` through `8/8` remain. The complete 470-mutant `hemx-axum` package gate now 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/REQUIREMENTS.md b/REQUIREMENTS.md index fa64d03..504b225 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -704,9 +704,9 @@ what a valid business email is. [north_star] 021 Unexplained missed mutants must block release; equivalent, invariant-only, and infrastructure-inapplicable mutants must be explicitly classified. [north_star] -022 `cargo run -p hemx-xtask -- mutation [PACKAGE] [SHARD/TOTAL]` must run capped exhaustive package-native mutation tests and fail on unexplained survivors. [north_star] +022 `cargo run -p hemx-xtask -- mutation [PACKAGE] [SHARD/TOTAL]` must run capped exhaustive package-native mutation tests with enough per-mutant time for repo-owned compiler probes, and fail on unexplained survivors. [north_star] -023 A supplied mutation `SHARD/TOTAL` must select a deterministic native shard and reject invalid bounds; omission preserves the full-package gate. [north_star] +023 A supplied mutation `SHARD/TOTAL` uses one-based `1..=TOTAL` numbering, maps to the deterministic native shard, and rejects invalid bounds; omission preserves the full-package gate. [north_star] --- diff --git a/hemx-xtask/src/main.rs b/hemx-xtask/src/main.rs index 6860c61..06eb4ec 100644 --- a/hemx-xtask/src/main.rs +++ b/hemx-xtask/src/main.rs @@ -1304,7 +1304,8 @@ fn mutation_shard(shard: Option<&str>) -> Result, String> { "invalid mutation shard `{shard}`; require TOTAL >= 2 and 1 <= SHARD <= TOTAL" )); } - Ok(Some(format!("{index}/{total}"))) + // mutest numbers shards from zero; xtask presents the conventional 1..=TOTAL surface. + Ok(Some(format!("{}/{total}", index - 1))) } fn run_mutation_plan(package: Option<&str>, shard: Option<&str>) -> ExitCode { @@ -1315,7 +1316,8 @@ fn run_mutation_plan(package: Option<&str>, shard: Option<&str>) -> ExitCode { return ExitCode::from(2); } }; - let shard = match mutation_shard(shard) { + let requested_shard = shard.map(str::to_owned); + let native_shard = match mutation_shard(shard) { Ok(shard) => shard, Err(error) => { eprintln!("{error}"); @@ -1337,7 +1339,7 @@ fn run_mutation_plan(package: Option<&str>, shard: Option<&str>) -> ExitCode { for package in packages { eprintln!("\n==> mutation: {package}"); - let output = shard.as_ref().map_or_else( + let output = requested_shard.as_ref().map_or_else( || output_root.join(package), |shard| { output_root @@ -1361,11 +1363,13 @@ fn run_mutation_plan(package: Option<&str>, shard: Option<&str>) -> ExitCode { "--annotations", "none", "--no-times", + "--minimum-test-timeout", + "120", "--exhaustive", "-o", ]) .arg(output); - if let Some(shard) = &shard { + if let Some(shard) = &native_shard { command.args(["--shard", shard]); } let status = command.status(); @@ -1628,8 +1632,8 @@ mod tests { assert!(error.contains("hemx-core")); assert_eq!(mutation_shard(None).unwrap(), None); - assert_eq!(mutation_shard(Some("1/4")).unwrap().as_deref(), Some("1/4")); - assert_eq!(mutation_shard(Some("4/4")).unwrap().as_deref(), Some("4/4")); + assert_eq!(mutation_shard(Some("1/4")).unwrap().as_deref(), Some("0/4")); + assert_eq!(mutation_shard(Some("4/4")).unwrap().as_deref(), Some("3/4")); for invalid in ["1", "a/4", "1/a", "0/4", "5/4", "1/1"] { assert!( mutation_shard(Some(invalid)).unwrap_err().contains(invalid),