feat(boundary): DAL-A MC/DC fail-loud at cert/record; warn at dev#115
Merged
feat(boundary): DAL-A MC/DC fail-loud at cert/record; warn at dev#115
Conversation
…n gate Trace-first seed for the DAL-A fail-loud feature in the follow-up commit on this branch. HLR-066: at cert/record profile, generate refuses to assemble a bundle when an in-scope crate is at DAL-A and the project's boundary.toml does not record an auxiliary qualified MC/DC tool under `[dal.auxiliary_mcdc_tool]`. Rationale: stable Rust cannot emit MC/DC instrumentation today (rust-lang/rust#144999 removed the unstable `-Zcoverage-options=mcdc` flag on 2025-08-08; tracking issue rust-lang/rust#124144 has no active reimplementation), so the only viable DAL-A path is to record an external qualified tool's evidence by reference (LDRA, VectorCAST, Rapita RVS). Without that reference the bundle would silently underclaim DO-178C Annex A Table A-7 Obj-7 — a known sharp edge an auditor would catch but a careless DER might miss. Traces to SYS-004 (policy-gated emission). Dev profile downgrades to a stderr warning + continue. LLR-073: `evidence_core::check_dal_a_mcdc_evidence(dal_map, auxiliary_mcdc_tool)` returns Ok(()) when no in-scope crate is at DAL-A OR an `AuxiliaryMcdcTool` reference is present, otherwise `BoundaryCheckError::DalAMissingAuxiliaryMcdc { dal_a_crates, count }` with code BOUNDARY_DAL_A_MISSING_AUXILIARY_MCDC. Library is policy-free; the dev/cert severity split lives at the CLI layer in `enforce_dal_qualification` called from cmd_generate right after enforce_boundary_policy. TEST-080: four selectors covering the full decision matrix — library passes when no DAL-A in scope; library passes when auxiliary tool set; library returns sorted offender list when DAL-A is in scope without a tool reference; integration test verifies dev profile emits a `warning:`-prefixed message and does not abort on the gate's own envelope.
Closes the v0.1.3 review's #1 item (DAL-A fail-loud on missing MC/DC). Stable Rust cannot emit MC/DC instrumentation (rust-lang/rust#144999 removed the unstable flag on 2025-08-08; rust-lang/rust#124144 has no active reimplementation), so the only viable DAL-A path today is to record an external qualified tool's evidence by reference. Pre-this-PR, a DAL-A bundle could emit `VERIFY_OK` while `compliance/<crate>.json` reported A7-10 (MC/DC) as `NotMet` — a careful auditor catches it; a careless DER signs off. This PR makes the gap fail loud. Library: - `evidence_core::AuxiliaryMcdcTool` (public): `name`, optional `qualification_id`, optional `report` (bundle- relative path). Reads from `boundary.toml`'s `[dal.auxiliary_mcdc_tool]` table. - `evidence_core::check_dal_a_mcdc_evidence(dal_map, auxiliary_mcdc_tool)` returns Ok(()) when no DAL-A in scope OR a tool reference is present; otherwise `BoundaryCheckError::DalAMissingAuxiliaryMcdc { dal_a_crates, count }` with code `BOUNDARY_DAL_A_MISSING_AUXILIARY_MCDC` (Domain::Boundary, Severity::Error). - The library is policy-free — dev/cert severity split lives at the CLI layer. CLI: - `enforce_dal_qualification` runs from cmd_generate after enforce_boundary_policy. Cert/record: standard failure envelope (`fail` helper) + Ok(Some(EXIT_ERROR)). Dev: `warning: DAL-A qualification gap...` to stderr + Ok(None); iteration continues unblocked. - Error message names every offender, lists three remediation paths (record auxiliary tool, lower DAL, wait for upstream), and cites both upstream issues so the auditor can verify the rustc state independently. Trace + tests: - HLR-066 traces to SYS-004 (policy-gated emission). - LLR-073 traces to HLR-066, emits the new code. - TEST-080: 3 unit + 1 integration selector. Refactor: - `boundary_check.rs` cargo-metadata struct subset extracted to a sibling `boundary_check/metadata.rs` (the new variant + check function pushed the parent over the workspace 500-line limit). - The integration test for the dev-warns path lives in its own integration-test file `tests/dal_qualification_gate.rs` (cli.rs hit the same 500-line limit). Floors ratchet (post-0.1.3 baseline 150/65/72/77/133/351): - diagnostic_codes 150 → 151 (+1: BOUNDARY_DAL_A_MISSING_AUXILIARY_MCDC) - trace_hlr 65 → 66 (HLR-066) - trace_llr 72 → 73 (LLR-073) - trace_test 77 → 78 (TEST-080) - per_crate.evidence-core.test_count 351 → 355 (+4 unit) - per_crate.cargo-evidence.test_count 133 → 134 (+1 integration) Golden fixture regenerated for the new code.
luofang34
pushed a commit
that referenced
this pull request
May 2, 2026
…rface claim, CHANGELOG - **Blocker 1**: CONTRIBUTING.md's UUID workflow now points at the established `cargo evidence trace --backfill-uuids` policy and cross-references `cert/trace/README.md`'s rationale. The python3 one-liner the prior draft suggested was the exact hand-crafting form the existing policy bans (collision risk, weakens the "UUIDs are opaque" contract, tempts reading meaning into digits). Two contradictory authority docs on the same workflow is a quality-of-process regression — fixed. - **Blocker 2**: Sharpened the negative dogfood. The previous test used `mcdc_2024.rs`, which fails the duplicate regex for two independent reasons (no leading space + 4 digits exceeds the 2-digit cap). A regression that drops only the leading-space anchor would still pass. Added `mcdc_24.rs` (2 digits, no leading space) so each anchor is isolated by its own fixture. - **Minor 3**: HLR-069 now claims `surfaces = ["editor-duplicate gate"]`, matching the convention HLR-044 / HLR-046 / HLR-047 established for sibling hygiene gates. New entry in `KNOWN_SURFACES`. `cert/floors.toml` known_surfaces 21→22. - **Minor 5**: 0.1.4 hygiene-track entry added to CHANGELOG. Bundles the changes already in main from PRs #115 / #116 / #117 plus the changes landing in this PR. Per-PR cadence rather than batched release-prep PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the v0.1.3 review's #1 actionable item (the DAL-A MC/DC fail-loud).
Stable Rust cannot emit MC/DC instrumentation today — the unstable
-Zcoverage-options=mcdcflag was removed by rust-lang/rust#144999 (merged 2025-08-08), and rust-lang/rust#124144 has no active reimplementation. The only viable DAL-A path today is to record an external qualified tool's evidence (LDRA TBvision, VectorCAST, Rapita RVS, etc.) by reference.Pre-this-PR sharp edge: a DAL-A project could run
cargo evidence generate --profile certand get a bundle whose terminal was `VERIFY_OK` while `compliance/.json`'s A7-10 row reported `NotMet`. A careful auditor catches it; a careless DER signs off. This PR closes that asymmetry.What changes
evidence_core::policy::dalAuxiliaryMcdcTool(name, optionalqualification_id, optionalreport) read fromboundary.toml's[dal.auxiliary_mcdc_tool]table. New optional field onDalConfig.evidence_core::boundary_checkcheck_dal_a_mcdc_evidence(dal_map, auxiliary_mcdc_tool)returningOk(())when no DAL-A in scope OR tool reference present, otherwiseBoundaryCheckError::DalAMissingAuxiliaryMcdcwith codeBOUNDARY_DAL_A_MISSING_AUXILIARY_MCDC.cargo_evidence::cli::generate::policyenforce_dal_qualificationruns afterenforce_boundary_policy. Cert/record: hard fail with offender list + 3-path remediation prose. Dev:warning:-prefixed message + continue.Backwards compatibility
Existing projects without DAL-A in scope are unaffected — the gate fires only when at least one in-scope crate is
Dal::A.Existing DAL-A projects with no
[dal.auxiliary_mcdc_tool]entry will start failing on cert/record. That's the intended behavior; the previous silent under-claim was the bug.Refactors (workspace 500-line limit)
boundary_check.rscargo-metadata struct subset extracted toboundary_check/metadata.rs.tests/dal_qualification_gate.rs.Floors ratchet
diagnostic_codestrace_hlrtrace_llrtrace_testper_crate.evidence-core.test_countper_crate.cargo-evidence.test_countTest plan
Note on the trace-roots discovery bug (separate PR)
While reviewing this work, a separate architectural issue was identified: `evidence_core::floors::count_trace_per_layer` hardcodes `tool/trace/`, while `check` and `trace --validate` use `default_trace_roots` (which walks both `tool/trace` and `cert/trace`). A downstream project with traces under `cert/trace/` gets `current=0` from `floors` silently. That fix touches a public lib API, has higher blast radius, and deserves its own focused PR — landing right after this one.
🤖 Generated with Claude Code