Round-2 adversarial-mutation-test coverage: query, magic CLI, validators, CopyArtifacts - #237
Round-2 adversarial-mutation-test coverage: query, magic CLI, validators, CopyArtifacts#237thedavidmeister wants to merge 2 commits into
Conversation
…ors, CopyArtifacts - New tests mod in crates/cli/src/meta/query/mod.rs: six process_meta_query httpmock tests pinning the success bytes and each failure classification, plus two multi-item get_authoring_meta tests (unpack-failure skip, scan beyond the first item). - New crates/cli/tests/magic_cli.rs pinning the exact `magic ls` output end-to-end via the built binary. - Strengthened common/v1.rs validator tests in place with discriminating invalids: "aA" symbol, DEL string, DEL-leading title, 64x'g' hash, "0X"-prefixed hash. - Strengthened testArtifactsCommitted in place: corrupt-both then run() restores byte-exact; delete-one then run() recreates. Single test function because forge runs test functions in parallel and every step shares the same on-disk committed files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 55 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round-2 AMT campaign over the units left uncovered by round 1:
process_meta_query/get_authoring_meta(crates/cli/src/meta/query/mod.rs), themagic lsCLI surface, thecommon/v1validator regexes, andscript/CopyArtifacts.sol— probed withnix run github:rainlanguage/adversarial-mutation-test#mutation-probeover two suites: rustnix develop rainix#rust-shell -c cargo test(baseline 137 passed) and solgit checkout -- crates/bindings/abi && git clean -fdq crates/bindings/abi && forge build && forge script ./script/CopyArtifacts.sol --ffi && forge test(baseline 16 passed).Sequence per the AMT protocol: all 49 mutants (40 rust + 9 sol) probed against the PRE-EXISTING suites first — rust 7 KILLED / 33 SURVIVED / 0 no-run, sol 4 KILLED / 4 SURVIVED / 1 NO-RUN (compile-enforced) — then every survivor either killed by a new or in-place-strengthened discriminating test and re-probed (
--onlypass 2: rust 21/21 KILLED, sol S1–S3 3/3 KILLED, both baselines green at 146/16), or recorded below as equivalent/dead/build-enforced with evidence, never forced.Behaviour matrix
Verdict legend: PRE = killed by pre-existing test (validates existing coverage), NEW = killed by a test added here, STR = killed by a pre-existing test strengthened in place.
datamember →NoRecordFoundmeta::query::tests::test_process_meta_query_missing_data_is_no_record_foundmeta(true absence) →NoRecordFoundtest_process_meta_query_missing_meta_is_no_record_foundrawByteshex →NoRecordFound, notCorruptMeta, not swallowed to emptytest_process_meta_query_bad_hex_is_no_record_foundtest_process_meta_query_success_exact_bytes,test_process_meta_query_non_json_is_reqwest_errorReqwestErrortest_process_meta_query_send_error_is_reqwest_errorReqwestErrortest_process_meta_query_non_json_is_reqwest_errorrawBytestest_process_meta_query_success_exact_bytestest_get_authoring_meta_skips_unpack_failuretest_get_authoring_meta_scans_beyond_first_itemmagic lsprints every KnownMagic, in order, correct columns, 0x-prefixed exact valuestests/magic_cli.rs::test_magic_ls_exact_output(e2e viaCARGO_BIN_EXE_rain-metadata)test_rain_symbol_validate(added"aA"invalid)test_rain_symbol_validatetest_solidity_identifier_validatetest_rain_string_validate(added"\u{7f}"invalid)test_rain_string_validatetest_rain_title_validate(added DEL-leading invalid)test_rain_title_validate0xprefixtest_hash_patterng), C21 (0Xaccepted)test_hash_pattern(added 64×gand"0X"+64-hex invalids)testArtifactsCommitted(corrupt both committed files →run()→ byte-exact restore against pre-corruption on-disk state)testArtifactsCommitted(delete one committed file →run()→ recreated byte-exact)testArtifactsCommittedforge buildatLibDescribedByMeta.sol:37Equivalent / dead / build-enforced dispositions (no test, never forced)
SliceReadraises every EOF atoffset == slice.len(), andcbor_decodecompares against exactly that slice length, so==vs<=is unobservable. Empirical truncation sweep (>10 EOF cases, alloffset == len).track/metasare pushed in the same iteration; the length check can never fire.create()uri-gate half removal unobservable.ValidationErrors::merge_alldrops all child results (children are keyed by their own field names /Fieldkind and never pass theerr.remove(field)+Structfilter;Operandcarries zero field rules). Behaviour already on file as BitIntegerRange/OperandArgRange/Output validation drops all sub-validation errors (ValidationErrors::merge_all misuse) #173/OpMeta validation silently discards nested BitInteger/Output errors (merge_all misused) #214 — no new issue.#[validate]attrs insolidity_abi/v2.rsmake the validate gates vacuous; already on file as SolidityAbiMeta validation is vacuous: Validate derives carry no rules, so the TryFrom validate gate and per-index annotation can never reject #153.Emptyarm is unreachable; already on file as CynicClientError::Empty is unreachable from CynicClient::query: missing/null data surfaces as a Request decode error #178. Empirical:{"data":null},{},{"data":null,"errors":null}all surface asRequestdecode errors.OUT_DIR, mutating the metaboardbuild.rsschema registration name fails compilation atlib.rs:5#[cynic::schema("metaboard")]("Could not find a schema with this name"), i.e. NO-RUN class like S9. The pass-1 SURVIVED verdict came from the probe's incremental build reusing staleOUT_DIRcynic-schemas/metaboard.{graphql,rs}residue from the unmutated baseline; demonstrated both ways (clean OUT_DIR → exit 101; stale artifacts restored → mutated crate builds green). No runtime test can pin a build-registry name.vm.writeFiletruncates before writing, so the remove-before-write is redundant for an existing dst.#[serde]Optionfields decode absent keys toNoneidentically with or without an explicit default; analytic serde equivalence recorded.Adjudication A-1: disproof
The round-1 adjudication claim that
generate sourceemits empty meta was DISPROVEN: fresh cargo build at bba50a7,printf '#main\n_: int-add(1 2);' | rain-metadata generate sourceyields selector0x37480e2a, meta length0x46, calldata meta bytes identical to the independently CBOR-encoded document,ff0a89c674ee7874document prefix present. The "empty meta" observation was a stale-binary artifact.Deviation: forge runs same-contract tests in parallel
The plan assumed test functions within one contract are serialized; forge 1.7.2 disproved this (new functions appended to
CopyArtifactsTestracedtestArtifactsCommittedon the shared on-disk committed files, flaking the suite). Since every step shares the same files,testArtifactsCommittedwas instead strengthened IN PLACE into one serialized sequence: original assertions first (unweakened) → corrupt both committed files →run()→ assert byte-exact restore (kills S1/S2) → delete one committed file →run()→ assert recreated byte-exact (kills S3).Issues filed (adversarial findings, labels
audit+adversarial)#231 (
solc artifactprintsnull, exit 0, for a missing component — adjudication A-2), #232 (Store::mergedeployer_hash_mapoverwrite asymmetry — A-3), #233 (str_to_bytes32/bytes32_to_strNUL round-trip asymmetry — A-4), #234 (process_meta_querycollapses corrupt payloads / bad hex / GraphQLerrorsintoNoRecordFound; meta-side sibling of #213), #235 (RainSymbol regex accepts trailing/double hyphens vs kebab-case contract), #236 (RainTitle validator message contradicts its regex and doc). Duplicates deliberately not re-filed: merge_all child-dropping (#173/#214), cynicEmptyunreachability (#178), vacuous SolidityAbiMeta validation (#153).QA
meta::query::tests::*(6 httpmock process_meta_query tests + 2 multi-item get_authoring_meta tests),tests/magic_cli.rs::test_magic_ls_exact_output(e2e against the built binary), strengthened in placetest_rain_symbol_validate/test_rain_string_validate/test_rain_title_validate/test_hash_pattern(new discriminating invalids only — no existing case weakened), soltestArtifactsCommitted(corrupt-both-restore + delete-one-recreate appended after the original unweakened assertions). Every pass-1 survivor selected for pass 2 flips to KILLED with the killer named by the probe fail-pattern (probe-rust-pass2: 21/21; probe-sol-pass2: 3/3; baselines green 146 / 16)..ok_or(Error::NoRecordFound)→CorruptMeta→test_process_meta_query_missing_data_is_no_record_found; CopyArtifacts exists-guard inverted → delete-one-recreate sequence).process_meta_query's "resolving if a record was found" contract, common/v1 regex doc contracts, CopyArtifacts committed-artifact invariant), the KnownMagic table for the exactmagic lspin, httpmock request-shape assertions (method, path, body), and independently constructed expected values (expected meta bytes hex-encoded in the test, not read back from the implementation; sol byte-exact oracle = pre-corruption on-disk state captured before mutating the files).Probe tool:
nix run github:rainlanguage/adversarial-mutation-test#mutation-probewith the two suite commands above, proof(\d+) passed; (\d+) failed, fail-pattern naming killer tests. Mutant files kept out of the repo.🤖 Generated with Claude Code