feat(intune): model Win32 app deployment transactions (#357) - #525
Conversation
|
Important Review skippedNo new commits to review since the last review. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR adds a public Win32 Intune analysis API with source classification, record rules, transaction models, evidence-backed findings, redacted exports, bounded parsing, fixture validation, shared redaction updates, and per-content download synthesis. ChangesWin32 Intune analysis
Download statistics synthesis
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant ArtifactBundle
participant Win32SourceInput
participant classify_record
participant analyze_win32_bundle
participant derive_findings
ArtifactBundle->>Win32SourceInput: captured and unreadable artifacts
Win32SourceInput->>classify_record: confirmed source components
classify_record->>analyze_win32_bundle: classified observations
analyze_win32_bundle->>derive_findings: immutable Win32Analysis
derive_findings->>ArtifactBundle: findings with evidence references
Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Consolidated multi-agent review (3 dimensions, findings adversarially verified)Verdict: needs a semantic-hardening round before merge. This lane was implemented before the Reducer Framework v1 pilot landed; it shares several of the defect classes the Store pilot just fixed, plus privacy gaps of its own. Typed-intent authority, timestamp-proximity isolation, framing delegation, and doc quality are genuinely strong — the issues below are concentrated in terminal precedence, coverage honesty, and redaction. Confirmed Major — semantics (ADR-001/002/003)
Confirmed Major — privacy (ADR-004)
Confirmed Major — contract
Minor (selected)
Handled well (verified by reviewers)Typed intent is regex-from-log-text only with no caller-writable path to outcome; timestamp proximity never creates correlation (identity-only grouping, Review produced by 3 parallel read-only reviewers (semantics/ADR, privacy/fixtures, API/coverage) with load-bearing findings re-verified against the branch. Refs #357, ADR-001..004. |
Extracted from codex/recovery-intune-357-win32 onto origin/main. Parser, reducer, rules, models, sources, redaction + 16 synthetic fixtures. Verified: focused 21/21, full parser 2005/0, strict clippy -D warnings clean, wasm32-unknown-unknown check clean, git diff --check clean. Lane-scoped only. Pre-existing repo-wide rustfmt drift on main left untouched (out of lane scope).
- split_rotation: strip .log case-insensitively (mixed-case archives) - reducer: key linked_artifacts by full Win32TransactionKey, not app_id alone (prevents cross-deployment-type corroboration leak) - reducer: normalize seen_basenames via split_rotation and move the expected-artifact Missing loop before degraded_coverage so absent expected artifacts actually lower transaction confidence - redaction: command_line_re preserves trailing switches (/quiet) for unquoted secrets and handles quoted values; redacted_export_projection now masks failed_requirements free text (correlation IDs stay verbatim) Focused 21/21 green, strict clippy clean. Remaining majors: finding_id uniqueness, mod.rs wildcard exports, additional regression tests.
…ction (#357) redact_observation masked message and provenance path but left requirement_name and retained-attribute values verbatim; both are log-derived free text that can carry a path or UPN. Mask them via redact_text. App/deployment-type/dependency ids and attribute names stay verbatim (correlation keys / schema labels). Full parser 2007/0, strict clippy clean, wasm32 clean, diff-check clean.
The case-insensitive .log strip sliced the name by byte index (&trimmed[..len-4]), which panics when the fourth-from-last byte is not a char boundary (e.g. Журнал.log). Check the suffix on a lowercased copy and slice only after confirming the trailing 4 bytes are the ASCII suffix, so the boundary is always valid. Added regression tests: multi-byte stem, mixed-case extension, non-.log extension. Full parser 2009/0, strict clippy clean, wasm32 clean.
Review findings 1-2 (semantic majors) and the ordering half of finding 4. The fold's max-rank Fold::set let any later-ranked statement absorb a proven failure: an unlinked success overwrote a failed enforcement cycle, ReportingFailed (rank 9) was absorbing even after the retry upload landed, and a scheduled retry (Deferred, rank 6) masked a ContentDeliveryFailed (rank 4) recorded after it. Adopt the Store pilot's proven shape (ADR-003): - terminal statements become equal-authority TerminalCandidates carrying their artifact id, record number, and trusted UTC; the only linkage that orders two candidates is the same artifact's own record numbers (the agent's append-ordered journal, across enforcement-cycle boundaries) or strictly-later trusted timestamps both records stated themselves. Nothing else counts; caller vector order never does. - a candidate explicitly ordered after another supersedes it, which is what lets a linked retry land on its final outcome; superseded *failures* survive as Win32Transaction::superseded_failures plus a win32-superseded-failure finding instead of being erased. - surviving contradictory candidates stay conservative as the new Win32Outcome::Conflicting (non-terminal, Low confidence, its own finding and next-evidence request) rather than an arbitrary winner. - ReportSubmitted records clear a ReportingFailed candidate they are explicitly ordered after; in-flight states (Assigned, Enforcing, Deferred) resolve by pending_rank and never contest a terminal. - order_records drops artifact_index (caller vector position) from every sort key: canonical (artifact_id, record_number) is the fallback, so permuting the input vector changes no conclusion. Per-record timestamp trust stays all-or-nothing for the phase fold because a total sort over a partial order needs an arbitrary tie-break; outcome resolution uses the partial order directly. New adversarial tests: linked retry supersession with failure survival, unorderable cross-artifact contradiction (both input orders), offsetless cross-artifact contradiction, trusted strictly-later linkage (both input orders), report-clearance, retry-then-failure, input-vector permutation, and artifact duplication.
…dence (#357) Review findings 3 and 5 (coverage honesty, ADR-001). - An artifact whose content classified Unknown, or an Available capture with no content, no longer seeds the expected-artifact check by file name alone. The synthesized 'expected:...' Missing entry survives, the missing-artifact finding stays, coverage stays degraded, and the base confidence cap applies. A caller-declared unreadable artifact still closes the synthesized gap because its own coverage entry expresses the same absence with better fidelity (pinned by test). - reconcile_partial_keys now marks a deployment type it filled in from bundle-wide uniqueness as inferred. The inference still completes the transaction key, but confidence_for only accepts a deployment type some record actually stated (itself or through its own execution block), so an inferred key component can no longer promote a transaction to High.
) Review findings 6, 7, and the win32 half of 8 (ADR-004). - win32/redaction.rs deletes its local rule copies and stable_token and re-exports the shared common::redact_text, exactly as scripts does. The fork had already reintroduced the fixed JSON-escaped-path leak (its user_path_re lacked the shared [\\/]{1,2} form); a pinned test now proves the JSON-escaped shape masks. No new token kind or token API is introduced (ADR-004): the shared FNV-1a token behavior is the accepted status quo, and the win32-only unsalted copy is gone. - derive_findings now passes every summary through the shared redaction grammar at the single push() choke point. Rules splice log-derived free text (failed requirement names, tokens) into summaries, and the raw snapshot fed a completely unredacted findings surface. Titles and recommended checks are static. Pinned by a unit test whose requirement name quotes a UPN. - the fixture harness's redaction scan now covers derived findings with the same redactionMustNotContain needles as the projection. - the shared harness gains manifest-declared privacyProbes: exact sensitive-shaped strings a scenario deliberately plants, exempt from the corpus prohibitions in that scenario only, and each probe must be covered by a redactionMustNotContain needle or validation fails (adversarial test included). The corpus-wide SID and C:\Users\ prohibitions had made the very shapes the redaction contract must catch untestable. - the privacy-redaction fixture now plants a space-containing account name, an MSI-property secret, a Windows SID, a device name, and a profile path with a space, and asserts all of them are absent from both the projection and the findings. Prior expectations were unsafe because they proved only 3 needles of the claimed surface and could not express these shapes at all. - common: account/host field values may now start with '[' so a malformed token-lookalike is masked rather than trusted; well-formed tokens are skipped by the already_masked guard (idempotence pinned).
Review finding 9 (contract: one behavior owner), as the minimal wrap. - download_stats now owns the content-download vocabulary explicitly: its started/completed/failed/stalled regex accessors are pub(crate) and its module doc states that win32 owns the transaction view while consuming these primitives. win32/signals.rs drops its parallel download regexes and composes the shared ones exactly the way download_stats itself does (bare 'cancelled'/'aborted' gated by the download-shaped-line vocabulary). Day-one drift closed: stall/timeout phrasing is now recognized as the new Win32Signal::DownloadStalled -- deliberately not a terminal statement, because a stall is trouble in flight, not a proven outcome. - guid_registry now owns the one textual GUID shape (GUID_PATTERN); event_tracker's win32 guid rules and win32's identifier rules both compose it instead of spelling three private copies. - event_tracker gains the same ownership note. - primitives deliberately not reused are documented at the site: appworkload_retry_re conflates retry-exhausted with retry-scheduled, which is harmless for statistics and wrong for a transaction outcome; 'content downloaded successfully' and 'downloading content' are IME wordings the shared vocabulary does not carry and are kept as local additions, not copies. - ordering fix surfaced by the composition: content-unavailable is now checked before the shared download-failed alternation so the specific no-usable-content diagnosis wins over the generic delivery failure.
Review finding 10. NotTargeted, NotApplicable, EnforcementCommandFailed, and InsufficientEvidence had no fixture, no integration test, and no unit test; their finding rules were dead in test. Four new corpus scenarios (the pinned SCENARIOS matrix grows 16 -> 20, and the corpus-equality test enforces the growth): - not-targeted: removal from targeting is a terminal answer with no next-evidence request and no enforcement phase claimed. - not-applicable: terminal, distinct from not-targeted, and a failed applicability pass does not advance the last confirmed phase. - enforcement-command-failed: terminal, with no installer return token asserted because the installer never ran; the launch error code stays on the record, not on the transaction. - insufficient-evidence: identity alone never becomes a verdict; the unresolved finding names the smallest artifact that would advance the diagnosis, and no phase is claimed.
Selected minors from the consolidated review: - finding_id now carries the full transaction key including execution_context, so System and User deployments of the same app and deployment type no longer collide; the rule segment stays static kebab-case and every key segment is lowercase, one grammar with the coverage ids. All 20 fixture expectations updated (prior ids were ambiguous across contexts by construction). - push_unknown_vocabulary cites exactly the records that raised the flag via the new Win32Observation::enforcement_shaped_but_unmatched (serde-defaulted, additive) instead of dragging every unclassified line into the finding. - metadata join and the return-code table both honor deployment_type_id: a scoped entry wins, an app-wide entry applies everywhere, and an entry for a different deployment type never labels or remaps this transaction. Win32ReturnCodeMapping gains an optional serde-defaulted deployment_type_id. - Capped decision (ADR-001), documented at confidence_for and pinned by test: framed records in a truncated artifact are authentic evidence, so a terminal outcome (including Succeeded) stands, but the missing tail is a coverage gap and High is unreachable. - input bound: MAX_RECORDS_PER_ARTIFACT (100k) caps per-artifact framed records; overflow marks the artifact Capped in coverage with a detail, which degrades confidence like any truncation. The '(record_index + 1) as u32' silent truncation becomes a checked conversion guarded by the bound. - Win32Analysis::default() now yields the current schema_version instead of an invalid 0, and schema_version deserializes with a default for forward compatibility. - new corpus-wide referential-integrity test: every cited evidence id (transactions, superseded failures, unkeyed list, findings) resolves to a real observation, and every coverage-gap citation resolves to a real coverage entry.
#357) Pure rename plus encapsulation, no behavior change (2246 tests unchanged before and after): - signals.rs -> rules.rs (record classification) and rules.rs -> findings.rs (derive_findings), matching microsoft_store and the rest of the family where 'rules' means classification and 'findings' means findings. - private modules with one curated pub use surface: every public name is now reachable at exactly one path (win32::Name); the previous pub-mod-everything layout published each item at two paths. Reference sweep per the no-semantic-search checklist: direct imports (reducer.rs super::signals), type-level references (none external), string/doc references (mod.rs table and ownership note), re-exports (mod.rs curated list), and tests (integration tests import only the curated surface; no test named the old paths).
ea7ad7d to
1b2a40d
Compare
…linkage-based (#357) Two ADR-003 defects in the reducer: - resolve_outcome indexed surviving[0] on a set that a sequencing cycle can empty: sequenced_after mixes same-artifact record order with cross-artifact trusted timestamps and is not transitive, so a 3-cycle eliminated every candidate and panicked. An empty survivor set now reduces to Conflicting with no superseded entries, since supersession requires a surviving eliminator. - DetectionSatisfied/DetectionNotSatisfied decided pre/post-enforcement from fold position, whose cross-artifact fallback half is the (artifact id, record number) sort -- so the caller's artifact naming picked the diagnosis. Detection verdicts are now placed by explicit linkage against the transaction's enforcement records (EnforcementLinkage): terminal claims are minted only with sequenced_after proof, and an unprovable position stays cited evidence. Regression tests: a_sequencing_cycle_across_artifacts_stays_conservative_ instead_of_panicking, detection_diagnosis_is_decided_by_linkage_not_artifact_ id_sort_order. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ate and restore lost phrasings (#357) - download_stats' transition-template ignore gate (Adding new state transition - From: ...) was private and checked first upstream, but win32 composed the download vocabulary without it, so a template line quoting 'Download Failed' minted a terminal ContentDeliveryFailed. The gate is now exposed as is_state_transition_template and checked before every composed download check in win32, mirroring the owner's own composition. - The consolidation into download_stats dropped pre-refactor IME phrasings. The owner regexes now carry them so both consumers gain the recall: failed: 'Download has failed', 'Download state: Failed', 'Download result = Failed'; completed: 'Download is complete', 'Download is completed', 'Download complete'; started: 'Started the download', 'Start content download'. Tests: the_state_transition_template_never_mints_a_download_signal, every_pre_refactor_download_phrasing_still_classifies (win32), and the_shared_vocabulary_carries_the_pre_consolidation_ime_phrasings (download_stats owner pin). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ounded framing (#357) - A readable artifact whose records failed content confirmation reported coverage Available while being excluded from reduction. It now downgrades to ParseFailed in the one coverage entry, so degraded_coverage, the win32-coverage-unusable-artifact finding, and confidence all see the same answer (test: a_content_misclassified_artifact_is_not_reported_available). - installer_artifacts was keyed by lowercased basename, so a second input with the same basename silently overwrote the first: one artifact vanished and the survivor corroborated on a guess. The map now keeps every artifact id per basename; a reference links only when exactly one candidate exists, and ambiguous candidates all stay visible in unlinked_installer_artifacts, sorted for ADR-003 canonicality (test: same_basename_installer_artifacts_never_collapse_or_link_ambiguously). - MAX_RECORDS_PER_ARTIFACT was enforced by parsing everything and truncating afterwards, so the cap bounded state but not framing work, and the Capped coverage detail ('records past the bound were not read') was false. Framing now stops at the bound: parse_ime_content_bounded frames one record past the limit to detect the remainder, and the record, fragment, and fallback paths all honor it (tests: bounded_parsing_stops_at_the_limit_and_reports_the_remainder, bounded_parsing_bounds_the_fallback_and_fragment_paths_too). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd generalize retry clearing (#357) - return_code / return_code_kind / reboot_required were the fold's last write, so a retry-kind 1618 completion clobbered the outcome-bearing cycle's attribution: 1603-then-1618 exported (1618, Retry) and silenced the unmapped-code finding, and 3010-then-1618 paired a Retry token with a stale reboot flag. The exported triple now comes from the winning completion candidate (winning_attribution): retry-kind completions mint no candidate and can never clobber it, and a Conflicting outcome still drops the attribution entirely. - ReportSubmitted-clears-ReportingFailed was a bespoke vector while a download completed after a download failure cleared nothing. Both now go through one Clearance mechanism (phase + polarity: a positive statement supersedes earlier candidates of one signal it is explicitly ordered after). DownloadCompleted clears DownloadFailed candidates only -- hash-validation and staging failures happen after a download completes and are deliberately not cleared. Cleared failures survive as superseded_failures instead of vanishing, for reporting and download alike. Tests: a_retry_kind_completion_does_not_clobber_the_outcome_bearing_return_ code, a_retry_kind_completion_after_a_reboot_success_keeps_the_winning_ attribution, a_download_completed_after_a_download_failure_clears_it_like_ reporting, a_download_completed_does_not_clear_a_hash_or_staging_failure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…profile roots (#357) - account_field_re / host_field_re re-hashed a value that began with an emitted token plus trailing prose ('UserName: [upn:...] is retrying' became one opaque [account:...] hash), destroying the stable token and the prose. A starts_with_token guard in both closures now preserves such values whole -- the equivalent of the lost leading-[ exclusion, chosen over the character-class form because a malformed token-lookalike must still be masked rather than trusted (pinned by malformed_mask_tokens_are_not_treated_as_already_masked). Stale doc comments on both rules rewritten to describe the real guard. - The profile-path prefix lost 'Documents and Settings'; the alternation now covers both roots in the same [\\/]{1,2} single-or-JSON-escaped form. Tests: an_account_value_starting_with_a_token_keeps_the_token_and_the_prose, a_host_value_starting_with_a_token_is_not_rehashed, a_documents_and_settings_profile_path_is_masked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…#356/#357) Three holes in the privacyProbes mechanism: - Substring coverage counted as coverage: a needle matching any fragment of a probe exempted the whole probe from the prohibition scan while only the fragment was proven redacted. A probe must now be declared verbatim as a redactionMustNotContain needle; the win32 privacy fixture declares its path probe exactly. - The probe strip ran over manifest.json and expected.json wholesale, so a probe leaking into an asserted output, an assertion, or a sanitized path was silently erased before the scan. The strip is now scoped to evidence files; descriptors are scanned with only the two declaration fields (privacyProbes, redactionMustNotContain) removed, so a leak anywhere else in them stays detectable. validate_descriptor_privacy drops its probes parameter accordingly. - A privacyProbes value that is present but not an array (or carries non-string / empty entries) was silently treated as no probes; it now fails validation loudly. Mutation tests: a_probe_covered_only_by_a_substring_needle_is_rejected, a_non_array_privacy_probes_declaration_is_rejected, a_probe_leaking_into_a_descriptor_output_field_is_detected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
needless_borrow at the return-code classification call and a contains() simplification in the fixture harness. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hermes charter reviewReviewed exact head Findings (most severe first)1. High — bundle-wide execution-context inference can merge unrelated transactions
Disposition: Valid, merge-blocking semantic finding. Not listed in the prior fix-round tables. 2. High — a block silently assigns one deployment type across conflicting deployment types
Disposition: Valid, merge-blocking semantic finding. Not listed in the prior fix-round tables. 3. Medium — the new public findings API is not fully documented as a published-crate contractThe final head still exposes Disposition: Valid, non-blocking documentation finding. The earlier CodeRabbit request is accepted here; it was not part of the already-fixed behavioral rounds. Contract layer
Adversarial layerApplied the charter attack surface to identity and transaction boundaries: same app across contexts, same app across deployment types, partial keys, out-of-order and cross-artifact evidence, duplicate/irrelevant records, retry/terminal contradictions, malformed/capped evidence, supplemental artifact ambiguity, and redaction. The two high findings are concrete false-story attacks that survive the existing tests. The existing permutation, duplicate-id, cycle, detection-linkage, retry, template, and privacy tests were treated as evidence of coverage rather than repeated as findings. Mechanical layer
Gate states
Explicitly rejected / not re-reported
Coverage statementThis review covered the charter, routing indexes, specialist context, reducer ADRs/checklist, contract/adversary/integration charters, the full production Win32 modules, prioritized shared-file changes, the Win32 harness/support changes, PR fix-round history, exact-head GitHub checks, and CodeRabbit state. It did not claim native Intune/Windows acceptance, did not check out the branch, did not modify repository files, and did not resolve threads or merge anything. Review disposition: two merge-blocking semantic findings remain; gate state is reported above rather than issuing a generic merge verdict. |
…s observed context Hermes charter review on PR #525, finding 1 (High). reconcile_partial_keys widened an Unknown execution context to the single context observed anywhere in the bundle for that app. Execution context is a runtime session property, not app identity: the same app deploys in System and in User context as distinct transactions, so the promotion merged unrelated captures and let one inherit the other's terminal outcome, return-code attribution, evidence, and confidence (ADR-002 weak-identity promotion). A context now stays Unknown unless the record stated it or its own execution block established it, and an unknown context keys its own transaction. Deployment-type uniqueness inference in the same function is retained deliberately: a deployment type id is a stable configuration identity subordinate to an exactly-matched app id (moderate strength under ADR-002), it is flagged deployment_type_inferred, and it never raises confidence (ADR-001). The doc comment now states that boundary explicitly. RED counterexample (Hermes's): same app, one System-context success capture, one context-less failure from a separate capture. Before the fix they fused into one System transaction whose outcome the unrelated failure overwrote. The privacy-redaction fixture relied on the promotion: its IME policy record states no context and sits in no shared execution block with the AppWorkload records, so it now honestly keys its own unknown-context transaction. The expectation records the split and the new unresolved finding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… dispute Hermes charter review on PR #525, finding 2 (High). apply_block_key refused to spread a key only when two records named different apps; a block stating two deployment types or two execution contexts silently kept the first value seen and spread it to every record lacking that field, attributing unkeyed terminal evidence to whichever deployment type or context happened to be logged first (ADR-002 explicit identity boundaries). The conflict rule is now per component, mirroring the app-id rule: a block whose records state two apps still refuses to key at all (the block boundary itself is wrong); a block whose records dispute the deployment type or the execution context withholds that component, so an unkeyed record keeps a partial key instead of a guess while uncontested components still spread. RED counterexamples (Hermes's): one block with a DT1 policy, an explicit DT2 record, and an unkeyed completion - the completion adopted DT1; and the same shape with System/User contexts - the completion adopted System. Both now key partially and carry their own outcome. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hermes charter review on PR #525, finding 3 (Medium), accepting the earlier CodeRabbit follow-up that was outside the diff range: derive_findings is a public API of the published cmtraceopen-parser crate and carried only a one-line summary. The Rustdoc now specifies the contract: the input is an immutable reduced snapshot (no live state, no I/O, same snapshot in, same findings out), the returned ordering is deterministic (fixed rule order, then the snapshot's canonical key-sorted transaction order, stable finding ids), and the evidence semantics (every finding is evidence-backed against the snapshot, independent severity/confidence axes, summaries pass the shared redaction grammar). No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CONFIG CHANGE, pre-authorized with mandatory disclosure: this lane branched before main's 96b841c, so its .coderabbit.yaml still carried drafts: false, request_changes_workflow: false, and auto_apply_labels: false. CodeRabbit reads the config from the PR branch, so on this draft PR it reported 'Review skipped: draft pull request', which blocks incremental reviews and the approve flow the merge gate requires. This commit copies origin/main's .coderabbit.yaml byte-for-byte (zero diff against main) and changes nothing else. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re: Hermes charter review — dispositions (fixed at
|
|
@coderabbitai review |
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/cmtraceopen-parser/tests/support/mod.rs (1)
879-887: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winExclude trailing punctuation from the returned email occurrence.
Line 879 trims terminal punctuation from
domain, but Line 887 stores the untrimmedtoken. If content containsuser@contoso.com., a declareduser@contoso.comprobe does not cover the returned span. The validator then reports a false email leak.Build the occurrence from
localand the trimmeddomain. Add a regression for an email followed by a period.Proposed fix
- occurrences.push((start, token.to_owned())); + occurrences.push((start, format!("{local}@{domain}")));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/cmtraceopen-parser/tests/support/mod.rs` around lines 879 - 887, Update the occurrence construction in the email-scanning logic to use the trimmed domain together with local, rather than storing the original token with trailing punctuation. Preserve the existing domain validation and invalid-domain exclusions, and add a regression test covering an email followed by a period.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@crates/cmtraceopen-parser/tests/support/mod.rs`:
- Around line 879-887: Update the occurrence construction in the email-scanning
logic to use the trimmed domain together with local, rather than storing the
original token with trailing punctuation. Preserve the existing domain
validation and invalid-domain exclusions, and add a regression test covering an
email followed by a period.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 546c77a9-9d86-4c7f-a42d-a526f0f624fd
📒 Files selected for processing (6)
.coderabbit.yamlcrates/cmtraceopen-parser/src/intune/apps/windows/win32/findings.rscrates/cmtraceopen-parser/src/intune/apps/windows/win32/reducer.rscrates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/privacy-redaction/expected.jsoncrates/cmtraceopen-parser/tests/intune_windows_win32.rscrates/cmtraceopen-parser/tests/support/mod.rs
Hermes charter re-review (head 35aadf7)Reviewed the branch at exact head Prior findings
DT-inference adjudication (ADR-002)I accept the distinction; I do not treat deployment-type inference as the same defect. ADR-002 expressly permits a stable secondary identity at moderate strength. Here the retained inference is narrowly bounded: it requires an exactly matched app identity, exactly one observed deployment type for that app, and it is subordinate to the app key. Ambiguous apps retain a partial key. The inferred component is explicitly marked This acceptance is conditional on the implementation boundary shown at this head: DT inference must remain an identity completion only, never a standalone join or confidence upgrade. The current code and regression Privacy-redaction fixtureAccepted as honest. The changed expectation records two transactions: the context-bearing User transaction remains successful, while the IME policy record that states no context and is outside the AppWorkload execution block becomes a separate Gate states observed at review time
VerdictMy two blocking identity-inference findings are cleared at head |
|
@coderabbitai approve |
✅ Action performedComments resolved and changes approved. |
|
@coderabbitai review |
|
|
@coderabbitai review |
|
There was a problem hiding this comment.
Pull request overview
Adds a new Intune Win32 deployment transaction analyzer to cmtraceopen-parser (evidence-backed, phase-aware, privacy-safe exports), plus supporting fixture/harness updates and a small src-tauri download-stats merge fix so Intune diagnostics remain stable in the UI.
Changes:
- Implement
cmtraceopen_parser::intune::apps::windows::win32(models, signal classification, reduction, findings, and redaction). - Extend the fixture harness with explicit
privacyProbessupport and stronger privacy scanning semantics (evidence + descriptors). - Improve Intune downloads handling in
src-tauriby merging synthesized download stats per content-id and sorting merged downloads chronologically (epoch-first).
Reviewed changes
Copilot reviewed 56 out of 112 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| .coderabbit.yaml | Enables CodeRabbit review behavior on drafts and auto label / request-changes workflow settings. |
| src-tauri/src/commands/intune.rs | Merges event-synthesized downloads per content id and adds regression tests + chronological sort. |
| crates/cmtraceopen-parser/src/intune/ime_parser.rs | Adds bounded IME parsing (parse_ime_content_bounded) and threads entry caps through record/fragments/fallback paths. |
| crates/cmtraceopen-parser/src/intune/guid_registry.rs | Introduces shared GUID_PATTERN for consistent GUID extraction across analyzers. |
| crates/cmtraceopen-parser/src/intune/event_tracker.rs | Switches Win32 GUID extraction regexes to compose from GUID_PATTERN and documents behavior ownership boundaries. |
| crates/cmtraceopen-parser/src/intune/download_stats.rs | Centralizes download vocabulary + template gate, exposes shared predicates for Win32 analyzer composition, and adds tests. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/mod.rs | Defines the public Win32 analyzer surface + detailed module contract docs and curated exports. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/redaction.rs | Implements Win32 analysis redaction/export projection using the shared redaction grammar; adds projection-focused tests. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/models.rs | Win32 analyzer public models (schema surface) used by fixtures and exports. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/sources.rs | Win32 artifact/source classification and coverage logic. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/rules.rs | Record classification rules for Win32 signals and tokens. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/reducer.rs | Identity-keyed reduction into immutable transaction snapshots and coverage handling. |
| crates/cmtraceopen-parser/src/intune/apps/windows/win32/findings.rs | Evidence-backed findings derivation for Win32 transactions. |
| crates/cmtraceopen-parser/tests/intune_windows_win32.rs | Integration tests validating the Win32 fixture corpus + privacy probe behavior. |
| crates/cmtraceopen-parser/tests/support/mod.rs | Adds privacyProbes contract, probe-aware privacy scanning, and stronger descriptor validation. |
| crates/cmtraceopen-parser/tests/intune_skeleton_contract.rs | Updates descriptor-privacy test call site to new signature. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/already-installed-detection/manifest.json | Win32 fixture manifest: already-installed detection scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/already-installed-detection/expected.json | Win32 fixture expected output: already-installed detection scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/already-installed-detection/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (already-installed detection). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/already-installed-detection/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (already-installed detection). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/already-installed-detection/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (already-installed detection). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/complete-success/manifest.json | Win32 fixture manifest: complete success scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/complete-success/expected.json | Win32 fixture expected output: complete success scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/complete-success/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (complete success). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/complete-success/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (complete success). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/complete-success/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (complete success). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/dependency-failure/manifest.json | Win32 fixture manifest: dependency failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/dependency-failure/expected.json | Win32 fixture expected output: dependency failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/dependency-failure/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (dependency failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/dependency-failure/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (dependency failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/dependency-failure/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (dependency failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/enforcement-command-failed/manifest.json | Win32 fixture manifest: enforcement command launch failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/enforcement-command-failed/expected.json | Win32 fixture expected output: enforcement command launch failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/enforcement-command-failed/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (enforcement command failed). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/enforcement-command-failed/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (enforcement command failed). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/enforcement-command-failed/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (enforcement command failed). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/hash-or-staging-failure/manifest.json | Win32 fixture manifest: hash/staging failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/hash-or-staging-failure/expected.json | Win32 fixture expected output: hash/staging failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/hash-or-staging-failure/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (hash/staging failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/hash-or-staging-failure/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (hash/staging failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/hash-or-staging-failure/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (hash/staging failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/incomplete-bundle-missing-appworkload/manifest.json | Win32 fixture manifest: incomplete bundle missing AppWorkload scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/incomplete-bundle-missing-appworkload/expected.json | Win32 fixture expected output: incomplete bundle missing AppWorkload scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/incomplete-bundle-missing-appworkload/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (incomplete bundle missing AppWorkload). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/insufficient-evidence/manifest.json | Win32 fixture manifest: insufficient evidence scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/insufficient-evidence/expected.json | Win32 fixture expected output: insufficient evidence scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/insufficient-evidence/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (insufficient evidence). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/insufficient-evidence/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (insufficient evidence). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/insufficient-evidence/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (insufficient evidence). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-known-nonzero-code/manifest.json | Win32 fixture manifest: mapped nonzero return code scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-known-nonzero-code/expected.json | Win32 fixture expected output: mapped nonzero return code scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-known-nonzero-code/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (mapped nonzero return code). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-known-nonzero-code/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (mapped nonzero return code). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-known-nonzero-code/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (mapped nonzero return code). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-unknown-code/manifest.json | Win32 fixture manifest: unmapped installer return code scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-unknown-code/expected.json | Win32 fixture expected output: unmapped installer return code scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-unknown-code/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (unmapped return code). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-unknown-code/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (unmapped return code). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installer-unknown-code/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (unmapped return code). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installed-but-not-detected/manifest.json | Win32 fixture manifest: installed-but-not-detected scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installed-but-not-detected/expected.json | Win32 fixture expected output: installed-but-not-detected scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installed-but-not-detected/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (installed-but-not-detected). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installed-but-not-detected/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (installed-but-not-detected). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/installed-but-not-detected/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (installed-but-not-detected). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/no-usable-content/manifest.json | Win32 fixture manifest: no usable content scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/no-usable-content/expected.json | Win32 fixture expected output: no usable content scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/no-usable-content/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (no usable content). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/no-usable-content/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (no usable content). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/no-usable-content/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (no usable content). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-applicable/manifest.json | Win32 fixture manifest: not applicable scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-applicable/expected.json | Win32 fixture expected output: not applicable scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-applicable/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (not applicable). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-applicable/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (not applicable). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-applicable/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (not applicable). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-targeted/manifest.json | Win32 fixture manifest: not targeted scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-targeted/expected.json | Win32 fixture expected output: not targeted scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-targeted/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (not targeted). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-targeted/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (not targeted). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/not-targeted/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (not targeted). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/privacy-redaction/manifest.json | Win32 fixture manifest: privacy/redaction scenario (declares privacyProbes). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/privacy-redaction/expected.json | Win32 fixture expected output: privacy/redaction scenario (redaction needles). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/privacy-redaction/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (privacy/redaction). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/privacy-redaction/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (privacy/redaction). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/reporting-failure-after-local-outcome/manifest.json | Win32 fixture manifest: reporting failure after local success scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/reporting-failure-after-local-outcome/expected.json | Win32 fixture expected output: reporting failure after local success scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/reporting-failure-after-local-outcome/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (reporting failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/reporting-failure-after-local-outcome/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (reporting failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/reporting-failure-after-local-outcome/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (reporting failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/requirement-failure/manifest.json | Win32 fixture manifest: requirement failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/requirement-failure/expected.json | Win32 fixture expected output: requirement failure scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/requirement-failure/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (requirement failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/requirement-failure/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (requirement failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/requirement-failure/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (requirement failure). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/retry-without-terminal-outcome/manifest.json | Win32 fixture manifest: retry scheduled / no terminal outcome scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/retry-without-terminal-outcome/expected.json | Win32 fixture expected output: retry scheduled / no terminal outcome scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/retry-without-terminal-outcome/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (retry scheduled). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/retry-without-terminal-outcome/evidence/app-action-processor-current/current/AppActionProcessor.log | Fixture evidence: AppActionProcessor.log (retry scheduled). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/retry-without-terminal-outcome/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (retry scheduled). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/rotation-split-record/manifest.json | Win32 fixture manifest: rotation-split record/fragment scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/rotation-split-record/expected.json | Win32 fixture expected output: rotation-split record/fragment scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/rotation-split-record/evidence/app-workload-rotation/rotated/AppWorkload-1.log | Fixture evidence: rotated AppWorkload segment with truncated record. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/rotation-split-record/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: current AppWorkload segment with fragment continuation. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/rotation-split-record/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (rotation-split record). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/same-minute-unrelated-apps/manifest.json | Win32 fixture manifest: disjoint apps within same minute scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/same-minute-unrelated-apps/expected.json | Win32 fixture expected output: disjoint apps within same minute scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/same-minute-unrelated-apps/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (same-minute unrelated apps). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/same-minute-unrelated-apps/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (same-minute unrelated apps). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/unkeyed-malformed-record/manifest.json | Win32 fixture manifest: unkeyed/malformed record + fragment scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/unkeyed-malformed-record/expected.json | Win32 fixture expected output: unkeyed/malformed record + fragment scenario. |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/unkeyed-malformed-record/evidence/app-workload-current/current/AppWorkload.log | Fixture evidence: AppWorkload.log (unkeyed/malformed record). |
| crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/unkeyed-malformed-record/evidence/ime-current/current/IntuneManagementExtension.log | Fixture evidence: IME log (unkeyed/malformed record). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| downloads.sort_by(|left, right| { | ||
| left.timestamp_epoch | ||
| .cmp(&right.timestamp_epoch) | ||
| .then_with(|| left.timestamp.cmp(&right.timestamp)) | ||
| .then_with(|| left.content_id.cmp(&right.content_id)) | ||
| }); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 56 out of 112 changed files in this pull request and generated no new comments.
Suppressed comments (3)
crates/cmtraceopen-parser/tests/intune_windows_win32.rs:412
- The golden corpus only checks that expected findings are present; it never rejects unexpected findings. A regression that emits a false warning or failure in every scenario would still pass this suite. Compare the complete sorted finding-ID lists before validating each expected finding's fields.
src-tauri/src/commands/intune.rs:1165 - This deduplication is case-sensitive even though GUID identity is not.
event_tracker::extract_guidpreserves source casing, while explicit JSON identities indownload_statsare lowercased byguid_registry; an uppercaseAppIdcan therefore add a synthesized uppercase stat beside the extracted lowercase stat. Canonicalize both sets of content IDs before comparison.
crates/cmtraceopen-parser/src/intune/apps/windows/win32/rules.rs:236 - Unquoted installer-output paths with spaces cannot link. The privacy fixture itself contains
Install output file: C:\Users\Probe User\...\contoso-setup.log; this branch captures onlyC:\Users\Probe, sofile_name_from_referenceproducesProbeand a suppliedcontoso-setup.logartifact remains unlinked even though the keyed record names it. Bound the unquoted alternative by the supported artifact extension rather than whitespace.
r#"(?i)\b(?:output|log)\s+file\s*[:=]\s*(?P<path>"[^"\r\n]+"|[^\s,;]+)"#
What is done
Implements
cmtraceopen_parser::intune::apps::windows::win32, the canonical evidence-backed transaction view of an Intune Win32 app deployment across assignment, applicability, requirements, dependencies, content, detection, enforcement, post-install detection, and reporting.New modules under
crates/cmtraceopen-parser/src/intune/apps/windows/win32/:models.rs: public types on top ofintune::evidence;Win32Outcomedistinguishes all 14 required states (not targeted, not applicable, requirement failed, dependency unresolved, detection already satisfied, content unavailable, content delivery/hash/staging failure, enforcement command failure, installer-reported failure, installed-but-not-detected, reporting failure, success, deferred/retry, insufficient evidence) plus in-flightAssigned/Enforcing.sources.rs: artifact classification (IntuneManagementExtension.log, AppWorkload.log, AppActionProcessor.log, rotations including underscore/numbered variants, AgentExecutor.log, supplemental installer output) and coverage state.signals.rs: per-logical-record classification with typed known/unknown return-code tokens (Win32ReturnCodeKind::Unmappedinstead of invented meaning).reducer.rs: identity-keyed reduction into immutable snapshots. Identifiers outrank time proximity; unkeyed/malformed records and physical-line fragments cannot create or terminate a transaction; supplemental MSI/PSADT/Burn/EXE evidence attaches only when a keyed record names it.rules.rs:derive_findingswith severity and confidence separated from cause classification; every finding cites exact evidence, last confirmed phase, and the smallest next artifact request; high-confidence failure requires terminal or corroborating evidence.redaction.rs: deterministic default-safe export projection; raw user/execution context, UPNs, and local paths are redacted by default.Seam decision: raw records are framed by the shared CCM parser via
intune::ime_parser::parse_ime_content— no second raw CCM parser.intune::event_tracker,download_stats, andtimelinekeep their public APIs and behavior unchanged; this module is the single owner of the transaction view. Semantic classification runs only after logical-record framing.Fixture matrix (16 scenarios, all synthetic, under
crates/cmtraceopen-parser/tests/fixtures/intune/apps/windows/win32/): complete-success, already-installed-detection, requirement-failure, dependency-failure, no-usable-content, hash-or-staging-failure, installer-known-nonzero-code, installer-unknown-code, installed-but-not-detected, reporting-failure-after-local-outcome, retry-without-terminal-outcome, incomplete-bundle-missing-appworkload, rotation-split-record, same-minute-unrelated-apps, unkeyed-malformed-record, privacy-redaction. Each hasmanifest.json("syntheticFixture": true), evidence logs carrying theSYNTHETIC FIXTUREmarker, andexpected.jsongolden serialization.Deliberately not done
src-taurinative known-source discovery or bundle collection; current discovery already names the primary artifacts, and the issue allows deferring native changes to a separate commit. None was needed.event_tracker/download_stats/timelineunder the new namespace; they are wrapped conceptually (kept as-is with one behavior owner) rather than relocated, per the "wrap, do not reimplement" allowance during migration.cargo fmt --checkdrift on main (55 diffs in files this lane never touched, e.g.collector/profile.rs,intune_skeleton_contract.rs) is left alone; lane files are fmt-clean.Assumptions
tests/fixtures/intune/apps/windows/win32/(microsoft-store and scripts convention) rather than the issue text'stests/fixtures/intune/windows/win32/; conventions in the tree win over the issue's path sketch.Verification (run from the worktree root)
cargo test --locked -p cmtraceopen-parser: 2338 passed, 0 failed (871 unit, 1461 across 46 integration suites, 6 doc-tests)cargo test --locked -p cmtraceopen-parser --test intune_windows_win32: 21 passed, 0 failedcargo clippy --locked -p cmtraceopen-parser --all-targets -- -D warnings: cleancargo check --workspace: cleancargo check --locked -p cmtraceopen-parser --target wasm32-unknown-unknown: cleangit diff --check: cleancargo fmt --check --all: 55 pre-existing diffs on main, none in files this PR touchesHardening round (consolidated multi-agent review)
Every finding of the consolidated review is mapped to a fix commit or a deliberate deferral.
b6c517e0. Terminal statements are equal-authority candidates; the only linkage that orders two of them is the same artifact's own record numbers or strictly-later trusted timestamps both records stated. Linked retry success supersedes but the failure survives assuperseded_failures+ awin32-superseded-failurefinding; unordered contradictions become the new conservativeWin32Outcome::Conflicting.ReportingFailedabsorbing;RetryScheduledmasks laterContentDeliveryFailedb6c517e0.ReportSubmittedclears aReportingFailedcandidate it is explicitly ordered after; retries are in-flight (pending) states that can never contest a terminal candidate recorded before or after them.e0ec95f3. Only usable evidence (confirmed content, or a caller-declared gap that carries its own entry) satisfies the expected-artifact check; the synthesizedMissingentry, the finding, and the confidence cap all survive.b6c517e0.artifact_indexremoved from every sort key; fallback is canonical(artifact_id, record_number). Permutation and duplication adversarial tests added. Timestamp trust stays all-or-nothing for the phase fold with the reason documented (a total sort over a partial order needs an arbitrary tie-break); outcome resolution uses the partial order per-record viasequenced_after.reconcile_partial_keysinference promotes confidence to Highe0ec95f3. Inferred key components are flagged and complete the key without counting towardconfidence_for's High; only a stated deployment type does.stable_tokenis a new unsalted cross-export identifier3ea90177and the module reusescommon's existing token behavior, adding no new token API. Defining the equality-scope contract remains the Store pilot's task.3ea90177. Every finding summary passes through the shared redaction grammar at the singlepush()choke point; the fixture harness now scans derived findings with the same needles as the projection.fd8b026d(shared module, own commit: account fields bounded like the path rule, MSI-property credentials,/sigil, SIDs, hostname fields + UNC hosts, tenant-id fields) and3ea90177(win32 collapses ontocommon::redact_text; JSON-escaped path leak pinned by test; privacy fixture extended with SID + hostname + MSI secret + space-containing account via the new manifest-declaredprivacyProbes, which the harness only accepts when each probe is pinned by aredactionMustNotContainneedle).8408ec94.download_statsowns the content-download vocabulary viapub(crate)accessors that win32 composes exactly asdownload_statsdoes;guid_registryowns the GUID shape for bothevent_trackerand win32; ownership notes added to both legacy modules; day-one drift closed (DownloadStalledrecognized, deliberately non-terminal). The retry vocabulary is deliberately not reused, documented at the site.780dc210. New scenariosnot-targeted,not-applicable,enforcement-command-failed,insufficient-evidence; SCENARIOS pin grows 16 → 20 with the corpus-equality test enforcing it.finding_idomits execution context; id grammar drift0f3e84b1(full key incl. lowercase context segment; all 20 fixture expectations updated).push_unknown_vocabularycites unrelated records0f3e84b1viaWin32Observation::enforcement_shaped_but_unmatched.deployment_type_id0f3e84b1(scoped entry wins, app-wide applies, other-deployment-type never labels).0f3e84b1(Win32ReturnCodeMapping::deployment_type_id, serde-defaulted, exact scope wins).Succeeded0f3e84b1: framed records in a truncated artifact are authentic evidence, so the terminal outcome stands, but the cap is a coverage gap and High is unreachable (pinned by test).pub modeverything, double public paths, invertedsignals/rulesnamingea7ad7da(pure renamesignals.rs→rules.rs,rules.rs→findings.rs; private mods + curatedpub use; reference sweep per the no-semantic-search checklist recorded in the commit message).as u32truncation;Defaultyields invalidschema_version; no#[serde(default)]0f3e84b1(MAX_RECORDS_PER_ARTIFACTwith analyzer-setCappedcoverage on overflow; checkedu32::try_from;Defaultyields the current schema version and additive fields are serde-defaulted).insufficient-evidenceis a no-verdict scenario; a dedicatedcapped/accessDenied/parseFaileddegraded-artifact corpus scenario and a full true-negative scenario are deferred — the behaviors are covered by unit tests (a_capped_artifact_proves_a_terminal_outcome_only_at_demoted_confidence,a_declared_unreadable_artifact_reports_its_own_coverage_status) but not yet by corpus fixtures.Deferrals, explicitly: (a) the ADR-004 stable-token equality-scope contract (owned by the Store pilot per instruction); (b) corpus-level degraded-artifact and true-negative scenarios (behavior covered by unit tests, fixtures deferred to keep this round reviewable); (c) per-record timestamp trust inside the phase fold (documented at
order_records— the partial order is honored where it is safe, in outcome resolution).Hardening verification (after
ea7ad7da)cargo test -p cmtraceopen-parser: 2246 passed, 0 failedcargo clippy -p cmtraceopen-parser --all-targets -- -D warnings: cleancargo check --workspace: cleancargo check -p cmtraceopen-parser --target wasm32-unknown-unknown: cleanCloses #357
🤖 Generated with Claude Code
Review fix round 2
13 verified findings, fixed test-first. Every behavioral fix landed with a failing regression test before the change.
surviving[0]panic: asequenced_after3-cycle eliminates every terminal candidate4f26ef4e: empty survivor set reduces toConflictingwith no superseded entries (supersession requires a surviving eliminator). Test:a_sequencing_cycle_across_artifacts_stays_conservative_instead_of_panicking.download_stats' transition-template ignore gate, minting terminalContentDeliveryFailedfrom template lines6906d7d3: gate exposed asis_state_transition_template(one owner) and checked before every composed download check. Tests:the_state_transition_template_never_mints_a_download_signal(win32, incl. the exact linedownload_statspins).6906d7d3:download_statsregexes widened so both consumers gain the recall. Tests:every_pre_refactor_download_phrasing_still_classifies(win32) +the_shared_vocabulary_carries_the_pre_consolidation_ime_phrasings(owner pin).4f26ef4e: detection arms judge by explicitsequenced_afterlinkage against precomputedEnforcementLinkage; unprovable positions mint nothing and stay cited evidence. Test:detection_diagnosis_is_decided_by_linkage_not_artifact_id_sort_order(id-rename invariance + no unprovenDetectedBeforeEnforcement).Availableecb99f55: downgraded toParseFailedin the one coverage entry;degraded_coverage,win32-coverage-unusable-artifact, and confidence all read it. Test:a_content_misclassified_artifact_is_not_reported_available.2e216bc5: exported triple comes from the winning completion candidate (winning_attribution); retry-kind completions mint no candidate. Tests:a_retry_kind_completion_does_not_clobber_the_outcome_bearing_return_code(1603 kept, unmapped finding fires),a_retry_kind_completion_after_a_reboot_success_keeps_the_winning_attribution. Divergence: the round-2 spec said 3010-then-1618 should exportreboot_required: false; deriving the flag from the winning 3010 candidate (the stated mechanism, and the field's documented contract "true only when a reboot code was observed") yieldstrue, andfalseis reachable only via exactly the last-write coupling this finding removes. The test pinstrue.account_field_re/host_field_rere-hashed values beginning with an emitted token plus prose3c74cc33via the allowed equivalent guard:starts_with_tokenin both closures preserves token+prose whole; the character-class form was rejected because the module pins that malformed token-lookalikes must still be masked (malformed_mask_tokens_are_not_treated_as_already_masked). Stale doc comments rewritten. Tests:an_account_value_starting_with_a_token_keeps_the_token_and_the_prose,a_host_value_starting_with_a_token_is_not_rehashed.Documents and Settingsdropped from the profile-path alternation3c74cc33, keeping the[\\/]{1,2}single-or-JSON-escaped form for both roots. Test:a_documents_and_settings_profile_path_is_masked(raw + JSON-escaped).ecb99f55: basename maps to every artifact id; a reference links only when unambiguous; all candidates stay visible inunlinked_installer_artifacts(sorted for ADR-003 canonicality). Test:same_basename_installer_artifacts_never_collapse_or_link_ambiguously.318809d3: probes must be declared verbatim as needles; descriptors are scanned with only the two declaration fields removed (leaks in outputs stay detectable); non-array/non-string/empty declarations fail loudly. Fixture updated to the tightened contract. Mutation tests:a_probe_covered_only_by_a_substring_needle_is_rejected,a_non_array_privacy_probes_declaration_is_rejected,a_probe_leaking_into_a_descriptor_output_field_is_detected.Cappeddetail claimed records "were not read"ecb99f55:parse_ime_content_boundedstops framing at the bound (record, fragment, and fallback paths), making the detail true. Tests:bounded_parsing_stops_at_the_limit_and_reports_the_remainder,bounded_parsing_bounds_the_fallback_and_fragment_paths_too.DownloadCompletedcould not clear an earlierDownloadFailedthe wayReportSubmittedclearsReportingFailed2e216bc5: one generalizedClearancemechanism (positive statement supersedes one signal's candidates it is ordered after); cleared failures survive assuperseded_failuresfor reporting and download alike; hash/staging failures deliberately not cleared. Tests:a_download_completed_after_a_download_failure_clears_it_like_reporting,a_download_completed_does_not_clear_a_hash_or_staging_failure.#[serde(default = "default_schema_version")]compatibility fallbackc8ab6236(AGENTS.md forbids fallbacks; nothing deserializes the type; siblingStoreAnalysishas none).ff707198carries two clippy fixups for the batch.Round 2 verification (after
ff707198)cargo test -p cmtraceopen-parser: 48 suites, 0 failures (915 lib tests + integration)cargo clippy -p cmtraceopen-parser --all-targets -- -D warnings: cleancargo check --workspace: cleancargo check -p cmtraceopen-parser --target wasm32-unknown-unknown: cleannpx tsc --noEmit: cleanReview fix round 3
12 verified findings plus below-cap items, fixed test-first in eight reviewable slices. Findings 1, 3, and 4 were treated as one class per the review directive: survivorship was re-derived independently by
resolve_outcome,winning_attribution, the fold-timelocal_outcomesnapshot, andcollect_superseded, and the four answers could disagree.winning_attributionwas survivorship-blind and used a max tie-break where the outcome pick used min40cf9c0f: oneResolutionstruct computed in one pass. Attribution is the earliest-canonical surviving completion stating the resolved outcome that no differently-concluding candidate is transitively ordered after; when a non-completion candidate decided the outcome, no return token is exported. One comparator (SequenceKey::canonical) serves the outcome pick and the attribution pick. Tests:a_superseded_reboot_completion_does_not_leak_its_return_code,attribution_follows_linkage_not_artifact_id_sort_order.DetectionNotSatisfiedvanished into a silent cleanSucceeded1f9b60d3:Win32Transaction.unlinked_detection_observations(additive field) carries the unplaced records;win32-unlinked-detection-failure(Warning, Medium) cites them;next_evidence_requestnow keys on more than the outcome and names the timestamp/journal linkage evidence that would place the verdict.InstalledNotDetectedis still never minted without proof. Tests:an_unplaceable_not_detected_record_is_surfaced_instead_of_a_silent_succeeded,a_provably_placed_not_detected_record_is_not_flagged_as_unlinked.40cf9c0f:CandidateOrderclosessequenced_aftertransitively; a candidate is superseded only by a contender that itself survives, so cycle members stay contenders and the knot resolvesConflictingwith no supersession claims. Test:a_cycle_does_not_let_an_independent_candidate_win_or_mint_false_supersessions(3-cycle + independent survivor, both input orders).local_outcomesnapshot40cf9c0f: the local outcome underReportingFailedis recomputed as the surviving outcome of the non-reporting candidates (same machinery, cleared candidates excluded). Tests:a_cleared_delivery_failure_leaves_no_stale_local_outcome_under_a_reporting_failure(was exporting the cleared failure),a_reporting_failure_after_a_retry_success_reports_the_surviving_local_outcome.5eda8589:is_state_transition_templatehoisted to the top ofclassify_signal— a template line returns Unclassified before any content/hash/staging/installer/detection rule and never raises unknown-vocabulary, matchingdownload_stats' own composition. Test:transition_templates_are_bookkeeping_for_every_rule_not_just_downloads(Hash Mismatch, Installation-is-done, staging and detection To:-field variants).download_start_reclassified "failed to start download" as a start31bdd8c9: no lookbehind in the regex crate, sois_download_startmatches the vocabulary and rejects a preceding failure verb in code (negated_start_re); the phrase is honest failure vocabulary and now lives indownload_failed_re, so a lone failed-start line yields one failedDownloadStatand win32 classifiesDownloadFailed. Both consumers share the one predicate. Tests:a_failed_start_is_a_download_failure_never_a_start,an_ordinary_start_line_still_asserts_a_start,a_failed_download_start_classifies_as_a_failure_not_a_start(win32).is_empty()gate collapsed the downloads panel on one spurious stat5aa98f20(separate src-tauri commit):merge_synthesized_downloadsfills in only the content ids the extractor produced nothing for; extracted stats win per id. Tests:one_spurious_extracted_stat_does_not_suppress_synthesized_downloads,merge_synthesized_downloads_still_covers_the_no_extraction_case.17022816:disambiguate_artifact_idssuffixes later holders (id#2, ...) at ingestion, mirroring the Store sibling'sunique_observation_id; the all-unique case borrows. Test:two_inputs_sharing_an_artifact_id_are_not_one_journal(no cross-file record-number supersession, distinct ids).a725c070: (a) the value pattern fires on a leading[only for token-shaped values, restoring main's behavior for[not signed in]prose while malformed token-lookalikes are still masked; (b)preserve_token_mask_tailkeeps the token and masks the non-empty remainder for account and host rules, idempotently.is_token_bodydedupes the validity predicate. Docs updated; scripts/remediations goldens stayed green. Tests:a_bracketed_prose_account_value_is_not_hashed_whole,an_account_value_starting_with_a_token_keeps_the_token_and_masks_the_tail(replaces the round-2 keep-the-prose pin: the trailing identity leak was the pre-existing bug that pin froze),a_host_value_starting_with_a_token_masks_its_trailing_fragment.redactionMustNotContainarray before the prohibition scan5c790ef5: only declared probe strings are stripped from within the two declaration arrays; non-probe needles stay scanned. Test:a_non_probe_needle_carrying_forbidden_material_is_rejected(a fakeC:\Users\needle without a matching probe now fails validation).build_line_startsscans past the bounded region; cap docs overclaimeda75a01ff:parse_ime_content_bounded,parse_ime_records, andMAX_RECORDS_PER_ARTIFACTnow state exactly what is bounded (entry materialization — framed records and fragments both count) and what is not (the single O(bytes) newline index kept for exact line numbers). Bounding the index itself would trade exact line numbers on capped tails for a scan that is already linear and allocation-free.CappedandParseFailedcollided: ParseFailed status with the cap's detaila75a01ff: one match reconciles them — ParseFailed dominates and the single detail states both facts. Test:a_capped_misclassified_artifact_reports_one_reconciled_status_and_detail.Cleanups folded in:
TerminalCandidate.reboot_requiredderived from the kind;push_terminalwrapper chain collapsed; the duplicated Clearance/TerminalCandidate sequence triple folded intoSequenceKey;collect_supersededcompares borrowed&str; attribution work skipped entirely onConflicting; the pre-consolidation phrase tables shared viadownload_stats::test_vocabulary.Fixture updates (justified in
40cf9c0f):installed-but-not-detectedandreporting-failure-after-local-outcomenow expect no top-level return token — their outcomes are decided by non-completion records, and the completion's story survives vialocalOutcome/superseded evidence.Round 3 verification (after
a75a01ff)cargo test -p cmtraceopen-parser: 48 suites, 0 failures (929 lib tests + integration)cargo clippy -p cmtraceopen-parser --all-targets -- -D warnings: cleancargo check --workspace: cleancargo check -p cmtraceopen-parser --target wasm32-unknown-unknown: cleancargo test(src-tauri): 29 suites, 0 failurescargo clippy -- -D warnings(src-tauri): cleanReview fix round 4 (CodeRabbit)
18 CodeRabbit threads verified against the code: 17 fixed (behavioral fixes test-first), 1 declined with rationale on the thread.
split_leading_tokenre-found the]and asserted it withexpectc32f6999: the closing bracket is located once and validated in place; noexpecton parsed log data.Vec::containsinside O(observations) filters (evidence_for_signal,push_unkeyed_signals,push_unlinked_detection_failure)c32f6999: oneBTreeSetmembership set per call.c32f6999: a public enum variant addition is documented as breaking (serde unknown-variant rejection; no#[non_exhaustive]per family convention);Win32Phasedocuments variant order as a load-bearing contract;Win32Outcome::Assigneddoc widened to match the reducer, resolving the rotation-split-record outcome/phase apparent contradiction.parse_code("-0x5")exported decimal -5 next to hex0x595734e8b(test first): negative hex routes through the same signed-to-u32 rendering as the decimal branch; out-of-i32-window negatives get no 32-bit hex view.4e1cfa93(test first):download_failed_recarries the exact negation x start-verb alternation; sharedNEGATED_START_FAILEDtable pins the pairing indownload_statsand the win32 rules tests.b1abaffd:content_id_reandextract_policy_idcompose fromGUID_PATTERN. The sibling family modules' duplicate consts are merged code outside this lane and left to a merged-surface audit.f7413ba4: grammar tests moved tocommon/redaction.rswith their owner (duplicates collapsed); the module now testsredact_observation/redact_transaction/redacted_export_projection(Sensitive masked field-by-field, Public verbatim, keys survive, projection idempotent under its honest name); new pina_malformed_token_lookalike_is_masked_not_trustedcovers uppercase-kind and wrong-length-hash lookalikes.948a9f40(harness side): needles are matched against unescaped string leaves of the redacted analysis and derived findings; pins prove both the old vacuity and the new detection.948a9f40:privacy_problems_excluding_probesexempts whole probe values only (raw + serde-escaped occurrence ranges), profile-path matches extend through the profile-name segment, SIDs exempt by covered range, emails by whole-value containment. Descriptor validation unchanged.948a9f40: counter and bool expectation keys are required and type-checked.rotation.fragmentCompletewas consumed by nothing, so stale flags were undetectable948a9f40: the flag is bound to the physical framing truth of each captured IME artifact; the binding caught a third stale flag the review had not named (unkeyed-malformed-record); all three nowfalse.948a9f40:"confidence": "high"asserted in all four fixtures; assertion reworded to "minimum artifact set".1036f8af(test first, src-tauri): sort bytimestamp_epochwith text and content id as deterministic tie-breakers.pub use models::*;contradicts a curated surfacemodels.rsis a curated public model file whose items are all deliberately part of the schema-version contract; switching only win32 would fork the family shape.dc66caccformats only the code this round added; pre-existing fmt drift stays untouched.Round 4 verification (after
dc66cacc)cargo test -p cmtraceopen-parser: 48 suites, 0 failures (943 lib tests + integration)cargo clippy -p cmtraceopen-parser --all-targets -- -D warnings: cleancargo check --workspace: cleancargo check -p cmtraceopen-parser --target wasm32-unknown-unknown: cleancargo test(src-tauri): 29 suites, 0 failurescargo clippy -- -D warnings(src-tauri): cleannpx tsc --noEmit: cleangit diff --check: cleanHermes review fixes (round 5, after
35aadf72)Fixes for the "Hermes charter review" comment, TDD (RED with Hermes's exact counterexamples first), one commit per finding.
reconcile_partial_keysno longer promotes an Unknown context to the bundle's single observed context; a context is set only by the record itself or its own execution block, and an unknown context keys its own transaction. Regression:a_context_less_record_never_adopts_the_bundles_observed_context. Deployment-type uniqueness inference in the same function was audited against the same discipline and deliberately retained: a deployment type id is a stable configuration identity subordinate to an exactly matched app id (moderate strength under ADR-002), it is flaggeddeployment_type_inferred, and it never raises confidence (ADR-001); the rationale is now in the function's Rustdoc. Theprivacy-redactionfixture relied on the promotion (its IME policy record states no context) and now honestly expects a second, unknown-context transaction.9da4acc4apply_block_keynow mirrors the app-id conflict rule per component: an app conflict still refuses to key the block at all; a deployment-type or context conflict withholds that component, so unkeyed records keep a partial key instead of a first-wins guess while uncontested components still spread. Regressions:a_block_with_conflicting_deployment_types_refuses_to_spread_one,a_block_with_conflicting_execution_contexts_refuses_to_spread_one.b17e959dderive_findingsunderdocumented as a published-crate API79a27e82Config change disclosure
35aadf72syncs.coderabbit.yamlbyte-for-byte fromorigin/main(zero diff vs main). This lane branched before main's96b841cc, so its copy still haddrafts: false(plusrequest_changes_workflow: false,auto_apply_labels: false), and CodeRabbit reported "Review skipped: draft pull request" on this draft PR, blocking incremental reviews and the approval the merge gate requires. The commit touches nothing else.Round 5 verification (after
35aadf72)cargo test --locked -p cmtraceopen-parser --no-fail-fast: 49 suites, 2293 passed, 0 failurescargo clippy --locked -p cmtraceopen-parser --all-targets -- -D warnings: cleancargo clippy --workspace --all-targets -- -D warnings: cleancargo check --workspace: cleancargo check -p cmtraceopen-parser --target wasm32-unknown-unknown: cleanSummary by CodeRabbit
New Features
Bug Fixes