Skip to content

refactor(intune): ask the citation predicate instead of restating it in two lanes - #548

Merged
adamgell merged 9 commits into
mainfrom
fix/evidence-backed-drift
Aug 10, 2026
Merged

refactor(intune): ask the citation predicate instead of restating it in two lanes#548
adamgell merged 9 commits into
mainfrom
fix/evidence-backed-drift

Conversation

@adamgell

@adamgell adamgell commented Aug 10, 2026

Copy link
Copy Markdown
Owner

What was reported

The Autopilot and Compliance lanes were reported as each carrying their own
is_evidence_backed predicate.

What is actually there

The premise is half right. There is exactly one is_evidence_backed in the
tree (crates/cmtraceopen-parser/src/intune/evidence.rs:355). What the two
lanes carried was the hand-inlined De Morgan negation of it, inside their
private finding() constructors:

if evidence.is_empty() && coverage_gap_ids.is_empty() { return None; }

The other three Windows lanes (Win32, Microsoft Store, Configuration) already
called the shared predicate at their own choke points.

Arm-by-arm comparison

The guard reads exactly two bits and no lane-specific state at all: it never
consults the snapshot, access state, parse state, severity, or confidence. So
the input space is four cells, and it is exhaustive.

evidence coverage_gap_ids Autopilot inline Compliance inline shared predicate
empty empty None (suppressed) None (suppressed) false
empty non-empty Some Some true
non-empty empty Some Some true
non-empty non-empty Some Some true

Suppression agrees with the negation of the shared predicate on every cell.

Autopilot normalizes (normalized_evidence, plus sort/dedup on the gap
ids) before deciding. That is safe rather than lucky: sort never changes
a vector's length and dedup never empties a non-empty one, so normalization
preserves both emptiness bits and cannot move the answer.

Verdict

The verdict is identical, and identical for the same stated reason. Each
lane's own doc comment already named IntuneFinding::is_evidence_backed as the
invariant it was enforcing, so the agreement is not coincidental, and a lane
emitting an uncited finding would violate the invariant declared on
IntuneFinding itself. That is all three parts of the doc's extraction test.

The constructors hosting it are deliberately per-lane and are NOT unified
here.
Autopilot normalizes both citation sets and takes
recommended_checks: &[String]; Compliance keeps citations verbatim and takes
a single check: &str; Win32 runs the redaction grammar over summary after
the gate; Microsoft Store takes &[&str]. A shared constructor would have to
pick one normalization policy and would either impose Autopilot's
byte-identical ordering contract on Compliance or retire it from Autopilot.

The ESP lane carries the same constructor shape at src/esp/rules.rs:669 over
EspDiagnosticFinding / EspEvidenceRef, a separate type family that cannot
call this predicate at all. Left alone.

What changed

Three commits, in this order:

  1. test(intune) pins the current behavior of both lanes across the full
    four-cell space, plus what is not shared between the constructors
    (Autopilot sorts and dedupes; Compliance preserves order and duplicates and
    wraps its single check).
  2. refactor(intune) replaces the two inlined negations with
    candidate.is_evidence_backed().then_some(candidate). The pinning tests are
    unchanged by this commit and still pass.
  3. docs(intune) adds the verdict to the "actually shared" table and adds
    protected divergence 9 covering the constructors, so the next consistency PR
    stops at the predicate. All eleven citations are repository-root-relative
    and were checked line by line against what the prose claims.

No behavior change rides along. No expected.json fixture is touched. No
genuine defect was found during the work.

Gates

cargo test -p cmtraceopen-parser
  suites: 50  passed: 2457  failed: 0  ignored: 1

cargo clippy -p cmtraceopen-parser --all-targets -- -D warnings
  Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.14s

git diff --check
  (no output, exit 0)

Stacked on fix/compliance-sid-redaction because PRs #545 and #546 already
rewrote tests/intune_windows_compliance.rs on that chain.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved finding validation so results are reported only when supported by valid evidence.
    • Preserved citation ordering and duplicate entries consistently.
    • Standardized citation handling across Windows compliance and enrollment checks.
    • Ensured recommended checks retain their associated evidence and coverage.
  • Documentation

    • Added documentation describing shared evidence-validation behavior and how it varies across Windows assessment areas.

adamgell and others added 7 commits August 10, 2026 11:55
…, invariant docs)

Three items, all behavior-preserving.

1. The IntuneAccessState <-> IntuneArtifactStatus bijection existed as three
   copies. Both directions now live in intune/evidence.rs beside the enums,
   with exhaustive matches (no `_` arm) so a new variant is a compile error.
   Win32 and Microsoft Store call the shared pair directly; Autopilot's
   declared_status is now the composition of its own lane-local capture-state
   mapping with the shared one. Verified arm by arm as identical first.

2. Mechanical test-support consolidation into tests/support/mod.rs:
   scenario_root, artifact_status_for_capture_state (plus an
   access_state_for_capture_state adapter for Win32), wire, and
   sorted_evidence_ids.

   Deliberately left local: Microsoft Store's insertion-ordered evidence_ids
   (that leaf asserts citation order), and Autopilot's capture_state (returns a
   lane-local enum via serde, not IntuneArtifactStatus).

3. Docs: an ADR-001 addendum recording that the directional doctrine is shared
   prose while its mechanism is per-lane, and a new
   docs/architecture/shared-vs-workload-invariants.md protecting the tested
   divergences from a future "consistency" PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The compliance reducer folded observations in raw caller order and never
canonicalized them. Six merges read vector position rather than record
content, and one of them flipped an exported conclusion: phase.state
alternated between Submitted and Stale when two submissions straddled the
latest local evaluation, because last_submission_at was an unconditional
last-wins assignment feeding the staleness gate.

Every field now merges by content, following the template Configuration
already ships: smallest stated value, agreed value (None/Unknown on an
unresolved disagreement, per ADR-003), and terminal error by canonical
code ordering. last_submission_at is the latest submission by timestamp
and refuses to answer when several submissions cannot all be ordered.

Also closed in the same class: the weaker report-status tokens folded by
last-writer-wins rather than by rank, the prerequisite detail followed the
last unmet row, and the three exported fact vectors kept the caller's
order in the serialized snapshot.

No fixture expectation changed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…RED)

These tests fail. They are committed before the fix so the defect is
readable from history rather than asserted after the fact.

`docs/architecture/shared-vs-workload-invariants.md` divergence 7 states
that the masking grammar has exactly one owner
(`intune/apps/windows/common/redaction.rs::redact_text`) and that each
lane owns only its projection. The Compliance lane carried a private copy
of the grammar. The copy has drifted, and every drift leaks:

  - short SID: exported "S-1-5-21-1010" verbatim
  - legacy profile root: exported "Jane Roe" verbatim
  - JSON-escaped profile path: exported "Jane Roe" verbatim
  - device name field: exported "DESKTOP-AB12CD" verbatim
  - UNC server segment: exported "FILESRV01" verbatim
  - account field: exported "jsmith" verbatim
  - tenant id field: exported the tenant GUID verbatim
  - inline credential flag: exported "hunter2" verbatim
  - MSI property credential: exported "ABCD-1234-EFGH" verbatim

The third test pins the export surface itself, not just the helper: a SID
placed in a setting display name survives into the serialized redacted
projection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Makes the nine RED assertions from the previous commit pass by deleting
the fork rather than patching the one reported pattern.

The reported defect was the SID rule: Compliance required four
sub-authorities where the owner requires three, so `S-1-5-21-1010` -- a
SID that names a real principal -- reached the export verbatim while
every sibling lane masked it. Auditing the rest of the lane's grammar
found the SID rule was not special. The fork was missing or weaker on
eight further rules, and the direction was never once conservative:

  pattern              owner                     Compliance fork
  SID                  >= 3 sub-authorities      >= 4 (leaked short SIDs)
  profile path         Users + legacy root,      Users only, single
                       1-2 separators            separator (leaked JSON-
                                                 escaped and legacy paths)
  device name field    masked                    absent
  UNC server segment   masked                    absent
  account field        masked                    absent
  tenant id field      masked                    absent
  inline credential    masked                    absent
  MSI property         masked                    absent
  UPN                  masked                    identical (only match)

Compliance is the lane that can least afford this: a custom-compliance
script prints whatever its author decided to print, and that output is
free text this grammar is the only thing standing in front of.

So the fix is structural. `redaction.rs` now re-exports
`intune::apps::windows::common::redact_text` -- the single owner named in
`docs/architecture/shared-vs-workload-invariants.md` divergence 7, and
the same arrangement win32, scripts and remediations already use -- and
keeps only what is genuinely this lane's: the projection deciding which
compliance fields are sensitive. Tightening the nine patterns in place
would have fixed today's drift and left the mechanism that produced it.

The four grammar tests in this module move to the owner's test module
rather than being deleted; all four cases were already pinned there. The
lane's own obligation is now asserted as byte-for-byte output parity with
the owner, which is strictly stronger and fails on any future fork.

No fixture expectation changed. The golden in
`deterministic-privacy-redaction/expected.json` still matches byte for
byte, because the two grammars hash identical spans to identical tokens
wherever they both fired -- the divergence was entirely about spans the
fork did not fire on at all.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lanes

Both lanes hand-inline the De Morgan negation of the shared invariant
IntuneFinding::is_evidence_backed inside their private finding()
constructors. Before touching either, pin what they do today.

The guard reads exactly two bits (is the evidence vector empty, is the
coverage-gap vector empty) and no lane-specific state at all, so the four
cells asserted here are the complete input space. Suppression is asserted
against the shared predicate rather than restated, so the two can only
agree.

The tests also pin what is NOT shared between the two constructors:
Autopilot sorts and de-duplicates both citation sets before deciding
(emptiness-preserving, so the verdict is unchanged, but it is this lane's
byte-identical output contract), while Compliance keeps its citations
verbatim and takes a single recommended check rather than a slice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Autopilot and Compliance finding constructors each hand-inlined the
De Morgan negation of IntuneFinding::is_evidence_backed while their own
comments named that predicate as the invariant they enforce. Both now
build the candidate and ask it, the way the Win32, Microsoft Store and
Configuration lanes already do at their own choke points.

Behavior-preserving, proved on the complete input space rather than by
shape. The guard reads two emptiness bits and no lane-specific state, so
the space is four cells, and suppression agrees with the predicate on all
four; the pinning tests from the previous commit assert exactly that and
are unchanged here. Autopilot's normalization is emptiness-preserving
(sort never changes length, dedup never empties a non-empty vector), so
moving the question after it cannot change the verdict.

What is NOT unified: the constructors themselves. Autopilot normalizes
both citation sets and takes a slice of recommended checks; Compliance
keeps citations verbatim and takes one check. The ESP lane carries the
same shape over EspDiagnosticFinding, a separate type family that cannot
call this predicate at all.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oes not

The verdict "does this finding cite anything" has one owner and now one
caller shape per lane, so it joins the "actually shared" table.

The constructors that ask it do not, and that is the part a future
consistency PR is likely to reach for next: three shapes across five
lanes, disagreeing on normalization, on the arity of recommended_checks,
and on whether a side effect is ordered against the gate. Divergence 9
records why the verdict passed the extraction test while the
constructors fail part 2 of it, and why the ESP lane's identical-looking
constructor is out of scope over a separate type family.

Every citation is repository-root-relative with a line number checked
against the line it names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added enhancement New feature or request intune Microsoft Intune related parser Log parser related labels Aug 10, 2026
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4c0faf89-1247-4e4b-93ad-7b2e81b5ee93

📥 Commits

Reviewing files that changed from the base of the PR and between 0bedcca and c66ed10.

📒 Files selected for processing (3)
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs
  • crates/cmtraceopen-parser/src/intune/enrollment/windows/autopilot/rules.rs
  • docs/architecture/shared-vs-workload-invariants.md

📝 Walkthrough

Walkthrough

The change updates Compliance and Autopilot finding constructors to use IntuneFinding::is_evidence_backed. Tests cover citation validation and normalization. Architecture documentation records the shared invariant and protected lane differences.

Changes

Finding validation

Layer / File(s) Summary
Constructor validation and tests
crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs, crates/cmtraceopen-parser/src/intune/enrollment/windows/autopilot/rules.rs
Both constructors validate candidate findings with IntuneFinding::is_evidence_backed. Tests cover empty inputs, citation ordering, duplicates, normalization, and recommended-check wrapping.
Shared invariant documentation
docs/architecture/shared-vs-workload-invariants.md
The architecture documentation identifies the shared citation invariant, updates Compliance references, and records constructor differences across Windows lanes, including the separate ESP finding family.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: test

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title follows Conventional Commits and accurately describes the shared citation-predicate refactor in the Intune lanes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/evidence-backed-drift

Comment @coderabbitai help to get the list of available commands.

@adamgell
adamgell changed the base branch from fix/compliance-sid-redaction to main August 10, 2026 21:18
# Conflicts:
#	crates/cmtraceopen-parser/src/intune/device/windows/compliance/reducer.rs
#	crates/cmtraceopen-parser/tests/intune_windows_compliance.rs
#	docs/architecture/decisions/ADR-001-evidence-strength-confidence.md
#	docs/architecture/shared-vs-workload-invariants.md
@adamgell
adamgell marked this pull request as ready for review August 10, 2026 21:20
Copilot AI lite review requested due to automatic review settings August 10, 2026 21:20
@coderabbitai coderabbitai Bot added the test Testing related label Aug 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@docs/architecture/shared-vs-workload-invariants.md`:
- Around line 199-203: Update docs/architecture/shared-vs-workload-invariants.md
lines 199-203 by replacing every lane’s placeholder “.../” path with the full
repository-relative crates/cmtraceopen-parser/src/... path for the referenced
constructors. Also update lines 221-226 by replacing the Autopilot and
Compliance test-reference placeholders with their full repository-relative
paths, ensuring all documented paths exist.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2199ec89-d147-4215-a7f2-c3cd965b6cb5

📥 Commits

Reviewing files that changed from the base of the PR and between 0bedcca and c94bb1c.

📒 Files selected for processing (3)
  • crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs
  • crates/cmtraceopen-parser/src/intune/enrollment/windows/autopilot/rules.rs
  • docs/architecture/shared-vs-workload-invariants.md

Comment thread docs/architecture/shared-vs-workload-invariants.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the Intune Windows Autopilot and Compliance lanes to delegate the “citation verdict” to the shared IntuneFinding::is_evidence_backed predicate (instead of inlining its negation), adds per-lane tests pinning guard behavior across the full 4-cell input space, and documents that the predicate is shared while constructor shapes remain intentionally lane-specific.

Changes:

  • Replace the Autopilot/Compliance inline “no citations => suppress” guard with candidate.is_evidence_backed().then_some(candidate).
  • Add constructor-focused unit tests in both lanes to pin guard semantics and lane-specific normalization/shape differences.
  • Update the shared-vs-divergent architecture doc to explicitly list the citation verdict as shared and record constructor divergence.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
docs/architecture/shared-vs-workload-invariants.md Documents the shared citation verdict and the protected divergence around per-lane finding constructors.
crates/cmtraceopen-parser/src/intune/enrollment/windows/autopilot/rules.rs Uses the shared predicate for the citation guard and adds tests covering the 4-cell input space plus normalization behavior.
crates/cmtraceopen-parser/src/intune/device/windows/compliance/rules.rs Uses the shared predicate for the citation guard and adds tests covering the 4-cell input space plus constructor shape guarantees.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 683 to +697
@@ -694,7 +693,8 @@ fn finding(
recommended_checks: vec![check.to_owned()],
evidence,
coverage_gap_ids,
})
};
candidate.is_evidence_backed().then_some(candidate)
Comment on lines 899 to +912
let mut coverage_gap_ids = coverage_gap_ids;
coverage_gap_ids.sort();
coverage_gap_ids.dedup();
if evidence.is_empty() && coverage_gap_ids.is_empty() {
return None;
}
Some(IntuneFinding {
let candidate = IntuneFinding {
finding_id: id.to_owned(),
severity,
confidence,
title: title.to_owned(),
summary: summary.to_owned(),
recommended_checks: recommended_checks.to_vec(),
evidence,
evidence: normalized_evidence(evidence),
coverage_gap_ids,
})
};
candidate.is_evidence_backed().then_some(candidate)
The divergence-9 section used '.../lane/file.rs' placeholders, which do not
identify a file from the repository root. All are now repository-relative with
the line number in path:line form.

Two further citations did not resolve and were not introduced here: the
divergence-7 entry added in #546 cites intune/device/windows/compliance/
redaction.rs and tests/intune_windows_compliance.rs without the crate prefix.
They are on main now, so they are corrected here rather than left for a
separate PR.

The check that was supposed to catch all of this only validated paths already
beginning with crates/ or docs/, so both an abbreviated '.../' path and a
crate-relative one were invisible to it. It is now prefix-agnostic and also
rejects any remaining '.../'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@adamgell

Copy link
Copy Markdown
Owner Author

Fixed at c66ed104. All .../ placeholders in the divergence-9 section are now repository-relative in path:line form.

The sweep also found two further citations that do not resolve and were not introduced here: the divergence-7 entry added in #546 cites intune/device/windows/compliance/redaction.rs and tests/intune_windows_compliance.rs without the crate prefix. Those are on main now, so I corrected them here rather than leaving a known-bad citation on main pending a separate PR.

Worth recording why they survived: my own citation check only validated paths already beginning with crates/ or docs/, so both an abbreviated .../ path and a crate-relative one were structurally invisible to the check written to catch exactly this. That is the third time this session a verifier has been narrower than the defect it targeted. The check is now prefix-agnostic and additionally rejects any surviving .../.

Verified: every path-shaped citation in the document resolves from the repository root, no abbreviations remain, and the cited line numbers point at what the prose claims.

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

@adamgell Full review requested for #548. The review will include the corrected documentation citations and the constructor and test changes.


✏️ Learnings added
Learnt from: adamgell
URL: https://github.com/adamgell/cmtraceopen/pull/548

Timestamp: 2026-08-10T21:24:36.000Z
Learning: For repository-root documentation citations, validation must be prefix-agnostic. In particular, the validator must resolve each path-shaped citation from the repository root and reject unresolved `.../` placeholders. Restricting validation to paths that start with `crates/` or `docs/` misses abbreviated and crate-relative citations.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Full review finished.

@adamgell
adamgell merged commit f174012 into main Aug 10, 2026
16 checks passed
@adamgell
adamgell deleted the fix/evidence-backed-drift branch August 10, 2026 22:03
adamgell added a commit that referenced this pull request Aug 11, 2026
Revision 1 was written as a proposal with six open questions and a
recommendation attached to each. The owner has ruled, so the document now
states decisions rather than options. The six questions become eight recorded
rulings, each carrying the reasoning that supports it, one line on what a lane
author must now do differently, and the mechanism that catches a violation
(compiler, test, or review).

Two rulings refine what the draft recommended and say so explicitly:

- Ruling 3 replaces the draft's caller-supplied "analysis identity" with an
  opaque caller-owned RedactionContext. The crate does not interpret the value,
  derive meaning from it, or require it to name anything. This dissolves the
  draft's open question about which identity a caller should pass, and makes
  every testable property relational rather than semantic.
- Ruling 4 forbids the fallback the draft left unruled. Configuration degrades
  its scope to generatedAtUtc alone when no scope is supplied. A lane with no
  context must now decline or emit with no equality; it may not substitute
  material that travels with the export.

Ruling 6 sharpens Restricted from "a masked value" to no value-derived
representation at all, enforced by one shared test asserting that two differing
restricted inputs produce identical output. Ruling 7 states exhaustive
construction recursively and splits the enforcement honestly: the compiler
catches a new field only once the constructor is exhaustive, so the
construction style itself is a review obligation.

Re-verified against origin/main at f174012, which moved three of the draft's
claims. Compliance no longer carries a private masking grammar (#546 deleted
the fork; the lane re-exports the shared owner and pins byte-for-byte parity),
its structural citations moved, and its defect is the inverse of the shape the
draft described: non-exhaustive at the top level, exhaustive in a nested view.
The grammar-owner row in shared-vs-workload-invariants.md also moved (#548).
Compliance's private unsalted minter did survive, which is a useful
demonstration that sharing the grammar and sharing the derivation are
independent questions.

Scope is unchanged and contract-only: no primitive named, no migration plan,
no source file touched. The security requirement stays a property.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
adamgell added a commit that referenced this pull request Aug 13, 2026
…pe and ownership (#550)

* docs(adr): propose ADR-004 revision 1 (redaction contract scope and ownership)

A decision document, not an implementation. It decides what the redaction
contract promises and who owns each part of it, and decides nothing about how.

Six rulings, each independently acceptable, amendable, or rejectable:

1. Where the contract binds: the crate/library API, generalizing the two lanes
   that already bind by construction. IPC/emit deferred; frontend egress
   explicitly out of scope as a boundary.
2. Equality scope: one analysis, caller-supplied identity. The security
   requirement is stated as a property, not an algorithm.
3. Ownership: grammar shared, projection per-lane, derivation shared, with a
   test for the distinction rather than a list.
4. Restricted vs Sensitive: give Restricted a real distinct behaviour rather
   than removing it or leaving it decorative.
5. Structural obligations: exhaustive construction enforced recursively by the
   compiler; self-description by type where the lane can express it.
6. Cross-lane correlation: out of scope, stated plainly, with a prohibition on
   presenting a shared derivation as delivering it.

Token mechanics and migration are deliberately deferred. No source file changes.

Records a direct contradiction inside the existing architecture: ADR-004 forbids
stable cross-artifact correlation tokens and five of six Windows Intune lanes
mint exactly those, with global stability stated as the design goal in their own
module docs.

Every code reference was opened and verified against origin/main at 2678f1f.
Five inventory claims were found to be wrong or imprecise and are corrected in
the document rather than silently applied, including that SCCM already projects
by construction on its export path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(adr): record the owner's eight rulings on ADR-004 revision 1

Revision 1 was written as a proposal with six open questions and a
recommendation attached to each. The owner has ruled, so the document now
states decisions rather than options. The six questions become eight recorded
rulings, each carrying the reasoning that supports it, one line on what a lane
author must now do differently, and the mechanism that catches a violation
(compiler, test, or review).

Two rulings refine what the draft recommended and say so explicitly:

- Ruling 3 replaces the draft's caller-supplied "analysis identity" with an
  opaque caller-owned RedactionContext. The crate does not interpret the value,
  derive meaning from it, or require it to name anything. This dissolves the
  draft's open question about which identity a caller should pass, and makes
  every testable property relational rather than semantic.
- Ruling 4 forbids the fallback the draft left unruled. Configuration degrades
  its scope to generatedAtUtc alone when no scope is supplied. A lane with no
  context must now decline or emit with no equality; it may not substitute
  material that travels with the export.

Ruling 6 sharpens Restricted from "a masked value" to no value-derived
representation at all, enforced by one shared test asserting that two differing
restricted inputs produce identical output. Ruling 7 states exhaustive
construction recursively and splits the enforcement honestly: the compiler
catches a new field only once the constructor is exhaustive, so the
construction style itself is a review obligation.

Re-verified against origin/main at f174012, which moved three of the draft's
claims. Compliance no longer carries a private masking grammar (#546 deleted
the fork; the lane re-exports the shared owner and pins byte-for-byte parity),
its structural citations moved, and its defect is the inverse of the shape the
draft described: non-exhaustive at the top level, exhaustive in a nested view.
The grammar-owner row in shared-vs-workload-invariants.md also moved (#548).
Compliance's private unsalted minter did survive, which is a useful
demonstration that sharing the grammar and sharing the derivation are
independent questions.

Scope is unchanged and contract-only: no primitive named, no migration plan,
no source file touched. The security requirement stays a property.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(adr): stop overstating what revision 1 decides

Revision 1 resolves the equality scope and the caller-owned context, not the
key, algorithm, encoding, secret source, or cross-export behaviour. The status
notices, the frontend projection claim, the token-equality biconditional, the
grammar-ownership exception, the invariant table, the migration bullet, and the
cross-export answer are all restated to match what the rulings actually decide,
and the original ADR's notice and status no longer describe equality scope as
both resolved and provisional.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request intune Microsoft Intune related parser Log parser related test Testing related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants