Skip to content

test(sccm): prepare Task Sequence corpus - #352

Merged
adamgell merged 23 commits into
codex/parser-family-skeletonfrom
codex/sccm-324-task-sequence-corpus
Aug 1, 2026
Merged

test(sccm): prepare Task Sequence corpus#352
adamgell merged 23 commits into
codex/parser-family-skeletonfrom
codex/sccm-324-task-sequence-corpus

Conversation

@adamgell

@adamgell adamgell commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • add a 17-scenario, 22-artifact synthetic client Task Sequence corpus covering WinPE, post-format, pre-client, client-installed, completed/relocated fragments, same-time unrelated runs, rotation boundaries, incomplete coverage, terminal failures, reboot continuation, invalid offsets, unknown profiles, and complete-looking unkeyed evidence
  • add a validator-backed Rust contract for exact execution keys, _SMSTSLogPath provenance, path classes/relocation order, CCM logical completeness, timestamp provenance, phase/terminal semantics, bounded coverage gaps, deterministic bytes/lines/digest, privacy, and fail-closed adversarial mutations
  • require all four declared execution-key fields to co-occur in every cited complete CCM record; aggregate substring pooling across unrelated records is rejected
  • derive physical completeness, source-path/profile provenance, relocation order, terminal outcomes, confidence ceilings, finding semantics, and absent-coverage behavior from cited evidence instead of mutually editable JSON claims
  • model the split rotation record only as an explicit ordered lo→current logical reconstruction; per-artifact path claims remain physical, and shared fingerprint alone supplies no evidence
  • add the issue-scoped preparation specification with supported path/profile scope, unsupported boot/recovery variants, native-validation deferral, and replay gates

Boundaries

Corpus inventory

  • 17 scenarios
  • 22 artifact rows: 21 captured and 1 absent
  • 21 evidence files: 19 complete logical CCM records and 2 partial rotation fragments
  • 17 logical coverage rows: 15 captured, 1 partial, 1 absent
  • 8,243 bytes, 21 lines
  • SHA-256 917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b

Verification

  • focused initial TDD RED: missing Task Sequence fixture root
  • focused CodeRabbit blocker RED: a mixed run-A/run-B key was incorrectly accepted when substrings were pooled across citations
  • focused independent-review RED at b880179: the real validate_contract accepted exactly 14/14 coherent path/profile/completeness/order/outcome/confidence/finding/coverage mutations
  • focused fresh-review RED at 6f5f2d2: the real validator accepted exactly 2/2 shared-fingerprint path-provenance mutations
  • cargo test -p cmtraceopen-parser --test sccm_client_task_sequence_fixture_contract (10/10)
  • cargo test -p cmtraceopen-parser (664/664)
  • cargo clippy -p cmtraceopen-parser --all-targets -- -D warnings
  • cargo check -p cmtraceopen-parser --target wasm32-unknown-unknown
  • npx tsc --noEmit
  • scoped rustfmt --edition 2021 --check
  • git diff --check
  • independent exact corpus recomputation: 17 scenarios / 22 artifacts / 21 files / 8,243 bytes / 21 lines / 19 complete physical fragments / 2 partial fragments / unchanged digest
  • committed-tree proof: all 21 ignored smsts.log/smsts.lo_ evidence files are tracked

Review evidence

  • branch remains based directly on 25b37333affde22b4ef8a19f4a5f3d89c082b599
  • initial preparation commit range-diff: cddba36 = 94fd08d
  • staged CodeRabbit findings for capture-state wording and escaped-path privacy detection were fixed in 94fd08d
  • exact-head CodeRabbit finding 5137395468 identified cross-record key pooling; the precise adversarial mutation was captured RED and fixed in b880179199c89a5b7b67686e7fe0e1a069dfc0a2
  • independent exact-range review 4824185973 reproduced 14 coherent validator bypasses against the real private validator; all 14 are committed as fail-closed mutations and fixed in 6f5f2d2e4341feace86e422008f397fd519bd353
  • fresh CodeRabbit exact-head review 5137635021 found shared-fingerprint path borrowing; changed-token and same-fingerprint-donor mutations were captured RED and fixed in 37dc6d08920c9dcb04a325f5dfe7531531695d9a
  • the three accepted inline review threads were replied to and resolved only after their mutations were green
  • fresh exact-head CodeRabbit response 5137740173 re-reviewed 37dc6d08920c9dcb04a325f5dfe7531531695d9a against direct base 25b37333affde22b4ef8a19f4a5f3d89c082b599 and reported no findings; the PR remains draft
  • the next independent review is intentionally deferred until SCCM: add shared diagnostic contracts and source catalog #318 merges and this draft branch is restacked onto the resulting live base

Refs #324

Epic: #317

Summary by CodeRabbit

  • Tests

    • Added comprehensive coverage for SCCM client task-sequence scenarios, including successful, failed, incomplete, rotated, relocated, and ambiguous logs.
    • Added validation for artifact provenance, ordering, coverage, timestamps, privacy boundaries, correlation rules, and conservative classifications.
    • Added integrity checks across a broad synthetic scenario corpus.
  • Documentation

    • Documented the synthetic task-sequence corpus, supported scenarios, validation rules, integrity checks, privacy constraints, and replay guidance.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8c07a640-4e03-437c-93b4-0f609313df4d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added a synthetic SCCM client Task Sequence corpus with 17 scenario fixtures, manifests, expected analysis results, rotated and relocated log evidence, corpus documentation, and contract and mutation tests.

Changes

SCCM Task Sequence corpus

Layer / File(s) Summary
Corpus contract and inventory
docs/sccm/preparation/issue-324-client-task-sequence-corpus.md, crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs
Defines scenario semantics, artifact provenance, rotation rules, privacy boundaries, inventory checks, and corpus digest handling.
Scenario manifests and expected outcomes
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/{client-install-failure,client-installed,complete-looking-unkeyed,completed,disk-image-failure,incomplete,invalid-offset,post-format,pre-client,reboot-continuation,software-install-failure,terminal-preflight,unknown-profile,unrelated-runs,winpe}/*
Adds synthetic manifests and expected results for successful, failed, incomplete, deferred, unkeyed, unknown-profile, and unrelated-run states.
Rotation and relocation fixtures
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/{relocated-fragments,rotation-boundary}/*
Adds ordered artifacts for relocated path classes and controlled .lo_-to-current reconstruction.
Contract validation and mutation coverage
crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs
Validates storage metadata, provenance, evidence binding, execution keys, timestamps, coverage, classifications, privacy limits, and fail-closed mutations.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • adamgell/cmtraceopen issue 324 — The corpus specification, scenario fixtures, relocation and rotation cases, and contract tests implement the client Task Sequence requirements.
  • adamgell/cmtraceopen issue 319 — The fixtures and validation cover SCCM evidence intake, artifact provenance, missing coverage, and log rotation.
  • adamgell/cmtraceopen issue 317 — The changes implement the tracked Task Sequence corpus and fixture-contract work.

Possibly related PRs

  • adamgell/cmtraceopen#336 — The contract tests exercise rotation, artifact, catalog, and provenance models introduced by this PR.
  • adamgell/cmtraceopen#342 — The fixtures test logical CCM evidence, timestamp ordering, rotation, provenance, and normalization.
  • adamgell/cmtraceopen#353 — The contract tests exercise evidence-backed findings and classifications.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.98% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the SCCM Task Sequence corpus preparation, which is the main change.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

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

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please review exact head 94fd08d3e5e1f7024d6fc78335d2064c96639852 against base 25b37333affde22b4ef8a19f4a5f3d89c082b599.

Scope is fixtures/tests/specification only. Treat the explicit synthetic execution keys as corpus contracts; do not infer production reducer readiness from the experimental low-confidence extractor. Please focus on false joins, physical-vs-logical coverage, relocation/rotation ordering, CCM record completeness, phase/terminal semantics, privacy, determinism, and native/server-causality overclaiming. The two findings from the staged review were fixed before this exact-head request.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='25b37333affde22b4ef8a19f4a5f3d89c082b599'
head='94fd08d3e5e1f7024d6fc78335d2064c96639852'

git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== RANGE ==='
git diff --stat "$base" "$head"
echo '=== CHANGED FILES ==='
git diff --name-status "$base" "$head"
echo '=== DIFF CHECK ==='
git diff --check "$base" "$head" || true
echo '=== DIFF ==='
git diff --find-renames --find-copies --no-ext-diff "$base" "$head"

Length of output: 192676


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'

echo '=== CONTRACT OUTLINE ==='
ast-grep outline "$test_file" --items all --type function --view expanded

echo '=== TARGETED CONTRACT RANGES ==='
for range in '300,650' '650,1050' '1050,1450' '1450,1695'; do
  echo "--- ${test_file}:${range} ---"
  sed -n "${range}p" "$test_file" | nl -ba -v "${range%,*}"
done

echo '=== SPECIFICATION ==='
nl -ba "$spec_file"

echo '=== TRACKED EVIDENCE FILES ==='
git ls-files "$fixture_root" | rg '/evidence/.*smsts\.(log|lo_)$' | sort

echo '=== STATIC FIXTURE RECONCILIATION ==='
python3 - <<'PY'
import hashlib
import json
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
scenarios = sorted(p for p in root.iterdir() if p.is_dir())
all_artifacts, physical, rows = [], [], []
errors = []
for scenario_dir in scenarios:
    manifest = json.loads((scenario_dir / "manifest.json").read_text())
    expected = json.loads((scenario_dir / "expected.json").read_text())
    artifacts = manifest["artifacts"]
    ids = {a["artifactId"]: a for a in artifacts}
    all_artifacts.extend(artifacts)
    expected_paths = set()
    for a in artifacts:
        rel = a.get("relativePath")
        if rel is not None:
            path = scenario_dir / rel
            if not path.is_file():
                errors.append(f"missing: {path}")
                continue
            data = path.read_bytes()
            physical.append(path)
            expected_paths.add(path.resolve())
            if a["bytesCopied"] != len(data):
                errors.append(f"bytes mismatch: {scenario_dir.name}/{a['artifactId']}")
            rows.append(
                f"{scenario_dir.name}\0{a['artifactId']}\0{rel}\0"
                f"{hashlib.sha256(data).hexdigest()}\n"
            )
    actual_paths = {p.resolve() for p in (scenario_dir / "evidence").rglob("*") if p.is_file()} \
        if (scenario_dir / "evidence").exists() else set()
    if actual_paths != expected_paths:
        errors.append(f"physical/reference mismatch: {scenario_dir.name}")

    refs = []
    def collect(v):
        if isinstance(v, dict):
            if {"artifactId", "startLine", "endLine"} <= v.keys():
                refs.append(v)
            for value in v.values():
                collect(value)
        elif isinstance(v, list):
            for value in v:
                collect(value)
    collect(expected)
    for ref in refs:
        a = ids.get(ref["artifactId"])
        if a is None or not a.get("relativePath"):
            errors.append(f"invalid cited artifact: {scenario_dir.name}/{ref['artifactId']}")
            continue
        lines = (scenario_dir / a["relativePath"]).read_text().splitlines()
        if not (1 <= ref["startLine"] <= ref["endLine"] <= len(lines)):
            errors.append(f"invalid cited lines: {scenario_dir.name}/{ref}")

print("scenarios:", len(scenarios), [p.name for p in scenarios])
print("artifacts:", len(all_artifacts))
print("capture states:", {s: sum(a["captureState"] == s for a in all_artifacts)
                          for s in sorted({a["captureState"] for a in all_artifacts})})
print("physical files:", len(physical))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("errors:", errors or "none")
PY

echo '=== PRIVACY / SCOPE / OVERCLAIM SCAN ==='
rg -n -i -P \
  '([A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 5966


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'

print_range() {
  local start="$1"
  local end="$2"
  local file="$3"
  echo "--- ${file}:${start}-${end} ---"
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{printf "%5d  %s\n", n++, $0}'
}

echo '=== VALIDATOR AND TESTS ==='
print_range 456 1114 "$test_file"
print_range 1115 1695 "$test_file"

echo '=== SPECIFICATION ==='
awk '{printf "%5d  %s\n", NR, $0}' "$spec_file"

echo '=== TRACKED EVIDENCE FILES ==='
git ls-files "$fixture_root" | grep -E '/evidence/.*smsts\.(log|lo_)$' | sort

echo '=== STATIC FIXTURE RECONCILIATION ==='
python3 - <<'PY'
import hashlib
import json
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
scenarios = sorted(p for p in root.iterdir() if p.is_dir())
all_artifacts, physical, rows, errors = [], [], [], []
for scenario_dir in scenarios:
    manifest = json.loads((scenario_dir / "manifest.json").read_text())
    expected = json.loads((scenario_dir / "expected.json").read_text())
    artifacts = manifest["artifacts"]
    ids = {a["artifactId"]: a for a in artifacts}
    all_artifacts.extend(artifacts)
    expected_paths = set()
    for a in artifacts:
        rel = a.get("relativePath")
        if rel is not None:
            path = scenario_dir / rel
            if not path.is_file():
                errors.append(f"missing: {path}")
                continue
            data = path.read_bytes()
            physical.append(path)
            expected_paths.add(path.resolve())
            if a["bytesCopied"] != len(data):
                errors.append(f"bytes mismatch: {scenario_dir.name}/{a['artifactId']}")
            rows.append(f"{scenario_dir.name}\0{a['artifactId']}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    evidence_root = scenario_dir / "evidence"
    actual_paths = {p.resolve() for p in evidence_root.rglob("*") if p.is_file()} if evidence_root.exists() else set()
    if actual_paths != expected_paths:
        errors.append(f"physical/reference mismatch: {scenario_dir.name}")

    refs = []
    def collect(v):
        if isinstance(v, dict):
            if {"artifactId", "startLine", "endLine"} <= v.keys():
                refs.append(v)
            for value in v.values():
                collect(value)
        elif isinstance(v, list):
            for value in v:
                collect(value)
    collect(expected)
    for ref in refs:
        a = ids.get(ref["artifactId"])
        if a is None or not a.get("relativePath"):
            errors.append(f"invalid cited artifact: {scenario_dir.name}/{ref['artifactId']}")
            continue
        lines = (scenario_dir / a["relativePath"]).read_text().splitlines()
        if not (1 <= ref["startLine"] <= ref["endLine"] <= len(lines)):
            errors.append(f"invalid cited lines: {scenario_dir.name}/{ref}")

print("scenarios:", len(scenarios), [p.name for p in scenarios])
print("artifacts:", len(all_artifacts))
print("capture states:", {s: sum(a["captureState"] == s for a in all_artifacts) for s in sorted({a["captureState"] for a in all_artifacts})})
print("physical files:", len(physical))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("errors:", errors or "none")
PY

echo '=== PRIVACY / SCOPE / OVERCLAIM SCAN ==='
rg -n -i -P \
  '([A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 79789


@adamgell I found one false-join gap in the fixture contract.

  • P2 — Bind each cited record to the full execution key, rather than the aggregate evidence text
    In crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs, Lines 857-885 concatenate every transaction evidence reference into cited_text and then look for each key field in that combined string. A mutation can therefore cite both unrelated-runs records and construct a synthetic transaction whose executionId/runContext come from run A while its advertisementId comes from run B; every substring check passes although no single CCM record carries that declared exact key. This violates the corpus’s stated false-join boundary and would allow an invalid future fixture to pass. Validate the complete declared key against each cited complete CCM record (or against verified per-record key groups before assembly), and add this mixed-key unrelated-runs mutation to adversarial_contract_mutations_fail_closed.

The rest of the exact-head review reconciled successfully: all 17 scenarios, 22 artifacts, 21 evidence files, byte/line totals, and SHA-256 digest match the documented inventory; all evidence files are tracked; and the privacy/native/server-causality scan found no prohibited material or overclaims.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please re-review exact head b880179199c89a5b7b67686e7fe0e1a069dfc0a2 against base 25b37333affde22b4ef8a19f4a5f3d89c082b599.

Tracking finding #352 (comment): fixed in b880179.

  • captured the precise same-time unrelated-runs mixed-key mutation RED: run A executionId/runContext plus run B advertisementId was previously accepted through aggregate substring pooling
  • every transaction evidence reference must now resolve to one complete normalized CCM record containing every declared non-metadata key field in that same record
  • phase/state must co-occur in one already key-qualified cited record
  • path-sequence, ordering, and terminal references must come from the key-bound transaction evidence set
  • focused contract 8/8, full parser 662/662, clippy, wasm32, TypeScript, scoped rustfmt, and diff checks are green

Please verify false-join closure and the existing preparation-only/no-production-readiness boundaries. A status context alone is not being treated as substantive approval.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='25b37333affde22b4ef8a19f4a5f3d89c082b599'
head='b880179199c89a5b7b67686e7fe0e1a069dfc0a2'

git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== CHANGED FILES ==='
git diff --name-status "$base" "$head"

echo '=== FOLLOW-UP COMMIT DIFF ==='
git diff --find-renames --check 94fd08d3e5e1f7024d6fc78335d2064c96639852 "$head"
git diff --find-renames --unified=35 94fd08d3e5e1f7024d6fc78335d2064c96639852 "$head" -- \
  crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'

echo '=== CONTRACT OUTLINE ==='
ast-grep outline "$test_file" --items all --type function --view expanded

echo '=== FALSE-JOIN / KEY-BINDING LOCATIONS ==='
rg -n -i -C 8 \
  'cited_text|key.bound|key_bound|normalized|complete.*record|executionId|runContext|advertisementId|phase|terminal|path.sequence|adversarial.*mutation|unrelated-runs' \
  "$test_file"

echo '=== PREPARATION BOUNDARIES ==='
rg -n -i -C 5 \
  'preparation|production|reducer|extractor|native|Windows|server|causal|unsupported|scope|claim|readiness' \
  "$spec_file" "$test_file"

Length of output: 87006


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
scenario_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs'

print_range() {
  local file="$1" start="$2" end="$3"
  echo "=== ${file}:${start}-${end} ==="
  sed -n "${start},${end}p" "$file" | nl -ba -v "$start"
}

print_range "$test_file" 366 455
print_range "$test_file" 662 1072
print_range "$test_file" 1073 1160
print_range "$spec_file" 69 160
print_range "$scenario_root/expected.json" 1 260
print_range "$scenario_root/manifest.json" 1 260

echo '=== UNRELATED-RUNS EVIDENCE ==='
while IFS= read -r evidence; do
  echo "--- $evidence ---"
  nl -ba "$evidence"
done < <(fd -t f . "$scenario_root/evidence" | sort)

echo '=== STATIC INVENTORY / REFERENCE RECONCILIATION ==='
python3 - <<'PY'
import hashlib, json
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, scenarios = [], [], [], sorted(p for p in root.iterdir() if p.is_dir())
for scenario in scenarios:
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    seen_paths = set()
    refs = []
    def visit(v):
        if isinstance(v, dict):
            if {"artifactId", "startLine", "endLine"} <= v.keys(): refs.append(v)
            for x in v.values(): visit(x)
        elif isinstance(v, list):
            for x in v: visit(x)
    visit(expected)
    for artifact in artifacts.values():
        rel = artifact.get("relativePath")
        if rel:
            p = scenario / rel
            if not p.is_file(): errors.append(f"missing {p}"); continue
            data = p.read_bytes()
            physical.append(p)
            seen_paths.add(p.resolve())
            if artifact.get("bytesCopied") != len(data): errors.append(f"size {p}")
            rows.append(f"{scenario.name}\0{artifact['artifactId']}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    actual = {p.resolve() for p in (scenario / "evidence").rglob("*") if p.is_file()} if (scenario/"evidence").exists() else set()
    if actual != seen_paths: errors.append(f"storage mismatch {scenario.name}")
    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if not artifact or not artifact.get("relativePath"): errors.append(f"bad ref {scenario.name}:{ref}"); continue
        lines = (scenario/artifact["relativePath"]).read_text().splitlines()
        if not 1 <= ref["startLine"] <= ref["endLine"] <= len(lines): errors.append(f"span {scenario.name}:{ref}")
print("scenarios", len(scenarios))
print("physical_files", len(physical))
print("bytes", sum(p.stat().st_size for p in physical))
print("lines", sum(len(p.read_text().splitlines()) for p in physical))
print("digest", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("errors", errors or "none")
PY

echo '=== SCOPE / PRIVACY / OVERCLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence \
  "$spec_file" || true

Length of output: 3889


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
scenario_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs'

print_range() {
  local file="$1" start="$2" end="$3"
  echo "=== ${file}:${start}-${end} ==="
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{printf "%5d  %s\n", n++, $0}'
}

print_range "$test_file" 366 455
print_range "$test_file" 662 1072
print_range "$test_file" 1073 1160
print_range "$spec_file" 69 160
print_range "$scenario_root/expected.json" 1 260
print_range "$scenario_root/manifest.json" 1 260

echo '=== UNRELATED-RUNS EVIDENCE ==='
while IFS= read -r evidence; do
  echo "--- $evidence ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$evidence"
done < <(fd -t f . "$scenario_root/evidence" | sort)

echo '=== STATIC INVENTORY / REFERENCE RECONCILIATION ==='
python3 - <<'PY'
import hashlib, json
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, scenarios = [], [], [], sorted(p for p in root.iterdir() if p.is_dir())
for scenario in scenarios:
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    seen_paths, refs = set(), []
    def visit(v):
        if isinstance(v, dict):
            if {"artifactId", "startLine", "endLine"} <= v.keys():
                refs.append(v)
            for x in v.values():
                visit(x)
        elif isinstance(v, list):
            for x in v:
                visit(x)
    visit(expected)
    for artifact in artifacts.values():
        rel = artifact.get("relativePath")
        if rel:
            p = scenario / rel
            if not p.is_file():
                errors.append(f"missing {p}")
                continue
            data = p.read_bytes()
            physical.append(p)
            seen_paths.add(p.resolve())
            if artifact.get("bytesCopied") != len(data):
                errors.append(f"size {p}")
            rows.append(f"{scenario.name}\0{artifact['artifactId']}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    actual = {p.resolve() for p in (scenario / "evidence").rglob("*") if p.is_file()} if (scenario / "evidence").exists() else set()
    if actual != seen_paths:
        errors.append(f"storage mismatch {scenario.name}")
    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if not artifact or not artifact.get("relativePath"):
            errors.append(f"bad ref {scenario.name}:{ref}")
            continue
        lines = (scenario / artifact["relativePath"]).read_text().splitlines()
        if not 1 <= ref["startLine"] <= ref["endLine"] <= len(lines):
            errors.append(f"span {scenario.name}:{ref}")
print("scenarios", len(scenarios))
print("physical_files", len(physical))
print("bytes", sum(p.stat().st_size for p in physical))
print("lines", sum(len(p.read_text().splitlines()) for p in physical))
print("digest", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("errors", errors or "none")
PY

echo '=== TRACKED EVIDENCE FILES ==='
git ls-files crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence | \
  grep -E '/evidence/.*smsts\.(log|lo_)$' | sort

echo '=== SCOPE / PRIVACY / OVERCLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence \
  "$spec_file" || true

Length of output: 45210


🏁 Script executed:

#!/bin/bash
set -euo pipefail

root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'
spec='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'

echo '=== UNRELATED-RUNS RAW EVIDENCE ==='
find "$root/unrelated-runs/evidence" -type f -print | sort | while IFS= read -r evidence; do
  echo "--- $evidence ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$evidence"
done

echo '=== STATIC INVENTORY / REFERENCE RECONCILIATION ==='
python3 - <<'PY'
import hashlib, json
from pathlib import Path
root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical = [], [], []
scenarios = sorted(p for p in root.iterdir() if p.is_dir())
for scenario in scenarios:
    manifest = json.loads((scenario/"manifest.json").read_text())
    expected = json.loads((scenario/"expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    expected_paths, refs = set(), []
    def collect(v):
        if isinstance(v, dict):
            if {"artifactId","startLine","endLine"} <= v.keys(): refs.append(v)
            for x in v.values(): collect(x)
        elif isinstance(v, list):
            for x in v: collect(x)
    collect(expected)
    for a in artifacts.values():
        rel = a.get("relativePath")
        if not rel: continue
        p = scenario / rel
        if not p.is_file():
            errors.append(f"missing {p}"); continue
        data = p.read_bytes()
        physical.append(p); expected_paths.add(p.resolve())
        if a["bytesCopied"] != len(data): errors.append(f"bytes {p}")
        rows.append(f"{scenario.name}\0{a['artifactId']}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    actual_paths = {p.resolve() for p in (scenario/"evidence").rglob("*") if p.is_file()} if (scenario/"evidence").exists() else set()
    if actual_paths != expected_paths: errors.append(f"storage {scenario.name}")
    for ref in refs:
        a = artifacts.get(ref["artifactId"])
        if not a or not a.get("relativePath"):
            errors.append(f"reference {scenario.name}:{ref}"); continue
        count = len((scenario/a["relativePath"]).read_text().splitlines())
        if not 1 <= ref["startLine"] <= ref["endLine"] <= count:
            errors.append(f"span {scenario.name}:{ref}")
print("scenarios:", len(scenarios))
print("artifacts:", sum(len(json.loads((s/'manifest.json').read_text())['artifacts']) for s in scenarios))
print("physical_files:", len(physical))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("errors:", errors or "none")
PY

echo '=== TRACKED EVIDENCE COUNT ==='
git ls-files "$root" | grep -E '/evidence/.*smsts\.(log|lo_)$' | wc -l

echo '=== SCOPE / PRIVACY / OVERCLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$root" "$spec" || true

Length of output: 4737


@adamgell Re-reviewed exact head b880179199c89a5b7b67686e7fe0e1a069dfc0a2 against 25b37333affde22b4ef8a19f4a5f3d89c082b599. No findings.

The false-join closure is substantive:

  • Every transaction evidence citation must match the exact line span of a single normalized, complete CCM record.
  • Every declared non-metadata execution-key field must occur in that same record; records are no longer concatenated for substring matching.
  • The new unrelated-runs mutation combines run A’s execution ID/run context with run B’s advertisement ID and cites both records. It fails because neither individual complete record contains the synthetic combined key.
  • Phase/state is checked only after per-record key qualification. Path sequence artifacts, ordering evidence, and terminal evidence must be selected from the key-bound transaction evidence set.

The preparation-only boundaries remain intact in both the contract and specification: outputs remain proposedPending318And319; the corpus does not assert production reducer readiness, native Windows/live ConfigMgr acceptance, or server/application/policy causality.

Static reconciliation also matches the documented corpus inventory: 17 scenarios, 22 artifacts, 21 tracked physical evidence files, 8,243 bytes, 21 lines, and SHA-256 917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b. Reference/storage validation and the privacy/scope scan passed. Runtime tests were not executed in this read-only review sandbox.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@adamgell adamgell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Exact-range independent adversarial rereview — BLOCKED

Reviewed exact base 25b37333affde22b4ef8a19f4a5f3d89c082b599 through exact head b880179199c89a5b7b67686e7fe0e1a069dfc0a2 in a clean detached worktree. The committed corpus is internally consistent, and the per-record execution-key fix is good, but the claimed fail-closed validator contract is not yet sound enough to merge.

I compiled the committed test file unchanged into an external review harness with include!, pointed it at the exact committed fixtures, mutated the in-memory manifest.json/expected.json values, and invoked the real private validate_contract function. The baseline probes correctly rejected:

  • a four-field key split across two unrelated cited records;
  • each independently swapped executionId, taskSequencePackageId, advertisementId, and runContext;
  • same-time unrelated record pooling;
  • duplicate physical/canonical aliases;
  • one-field path/profile/timestamp/offset/coverage/relocation/rotation drift;
  • direct unkeyed confidence escalation;
  • missing failure terminal evidence, invalid phase, unbounded transaction request, and absent-to-captured coverage.

However, the same real validator returned Ok(()) for 14 coherent adversarial mutations:

  1. coherent pathClass drift;
  2. coherent _SMSTSLogPath/sanitized-path drift away from the cited record;
  3. sourceVersion drift;
  4. declared extraction-profile drift;
  5. invalid capture-timestamp drift;
  6. an incomplete smsts.lo_ fragment promoted to complete logical coverage;
  7. coherent relocation-order drift;
  8. complete-looking unkeyed evidence promoted to a success finding;
  9. a succeeded transaction with no terminal citation;
  10. a nonterminal finding promoted to confirmedFailure;
  11. an invalid-offset transaction promoted to high confidence;
  12. an unknown-version source promoted to an exact transaction under the synthetic profile;
  13. an unbounded finding-level next-artifact request; and
  14. an absent source promoted to a success/no-run finding.

These are not production-parser concerns; they are holes in the new fixture validator itself. The preparation spec says source/profile provenance is authoritative, unknown profiles stay source-local/Low, Complete needs terminal evidence, partial physical fragments cannot become logical records, findings remain evidence-first, and absence is coverage only. A future fixture change can currently violate those contracts while the advertised validator still passes.

Reconciliation and gates

  • Independent inventory: 17 scenarios; 22 artifacts (21 captured, 1 absent); 21 physical files; 8,243 bytes; 21 lines; 19 complete flags and 2 partial flags; digest 917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b.
  • git ls-files --stage contains all 21 physical smsts.log/smsts.lo_ files. All 17 manifests and 21 physical files carry explicit synthetic markers/handles. The privacy scan covers plain and JSON-escaped Windows-path forms, SIDs, email-like identities, credentials/tokens, and prohibited native/server/app-policy claims; no fixture hit.
  • Exact diff is fixtures, one test target, and the preparation spec only—no production reducer/catalog/native code or dependency changes.
  • Focused target: 8/8 passed.
  • Full parser: 662/662 passed.
  • Strict Clippy, wasm32 check, TypeScript, scoped Rust 1.88 formatting, and exact-range git diff --check: passed.
  • External adversarial harness: 2/2 reviewer tests passed; one proves the expected fail-closed edges, while the other records the 14 validator bypasses above.

The fresh exact-head CodeRabbit GitHub response reported no findings. A second exact-range CodeRabbit CLI attempt was rate-limited; I did not treat the rate status as approval. The executable mutation evidence above is the blocking result.

This review is anchored to b880179199c89a5b7b67686e7fe0e1a069dfc0a2. It does not mark the draft ready, merge it, close #324, or claim native/live acceptance.

Comment thread crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs Outdated

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please perform a fresh substantive exact-head review of 6f5f2d2e4341feace86e422008f397fd519bd353 against direct base 25b37333affde22b4ef8a19f4a5f3d89c082b599.

This follow-up closes the 14 coherent validator bypasses independently reproduced at b880179. Please inspect the committed real-validate_contract mutation test and re-evaluate each closure rather than relying only on incremental diff summaries: physical CCM completeness; _SMSTSLogPath/pathClass provenance; sourceVersion/profile/capture-time binding; evidence-derived relocation order; terminal success/failure citations; classification/state/confidence ceilings; unknown/unkeyed and invalid-offset promotion; finding terminality/request bounds; and absent-coverage/no-run behavior. Preserve the existing per-record exact-key, physical inventory/digest, synthetic privacy, preparation-only, and no-native/no-production boundaries.

Local exact-head proof: focused 9/9, full parser 663/663, strict Clippy, wasm32, TypeScript, scoped Rustfmt, and diff checks pass; corpus digest remains 917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b. PR remains draft.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='25b37333affde22b4ef8a19f4a5f3d89c082b599'
prior='b880179199c89a5b7b67686e7fe0e1a069dfc0a2'
head='6f5f2d2e4341feace86e422008f397fd519bd353'
test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'

git cat-file -e "${base}^{commit}"
git cat-file -e "${prior}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== COMMIT RELATIONSHIPS ==='
git merge-base --is-ancestor "$base" "$head" && echo 'base is ancestor of head'
git merge-base --is-ancestor "$prior" "$head" && echo 'prior reviewed head is ancestor of head'
git show -s --format='head=%H%nparents=%P%nsubject=%s' "$head"

echo '=== DIRECT-BASE CHANGED FILES ==='
git diff --name-status "$base" "$head"
echo '=== FOLLOW-UP CHANGED FILES ==='
git diff --name-status "$prior" "$head"
echo '=== DIFF CHECK ==='
git diff --check "$base" "$head"

echo '=== CONTRACT OUTLINE ==='
ast-grep outline "$test_file" --items all --type function --view expanded

echo '=== VALIDATOR / MUTATION / BOUNDARY LOCATIONS ==='
rg -n -i -C 6 \
  'validate_contract|mutation|complete.*CCM|_SMSTSLogPath|pathClass|sourceVersion|profile|capture.*time|relocat|terminal|classification|confidence|unknown|unkeyed|invalid.offset|finding|request|absent|no.run|executionId|runContext|advertisementId|proposedPending|production|native|server|causal' \
  "$test_file" "$spec_file"

echo '=== FOLLOW-UP CONTRACT DIFF ==='
git diff --unified=45 "$prior" "$head" -- "$test_file" "$spec_file"

echo '=== FIXTURE INVENTORY / REFERENCES / DIGEST ==='
python3 - <<'PY'
import hashlib, json, subprocess
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, all_artifacts = [], [], [], []
for scenario in sorted(p for p in root.iterdir() if p.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    all_artifacts.extend(artifacts.values())
    expected_paths, refs = set(), []

    def visit(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys():
                refs.append(value)
            for nested in value.values():
                visit(nested)
        elif isinstance(value, list):
            for nested in value:
                visit(nested)
    visit(expected)

    for artifact_id, artifact in artifacts.items():
        rel = artifact.get("relativePath")
        if not rel:
            continue
        path = scenario / rel
        if not path.is_file():
            errors.append(f"missing: {path}")
            continue
        data = path.read_bytes()
        physical.append(path)
        expected_paths.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied mismatch: {scenario.name}/{artifact_id}")
        rows.append(f"{scenario.name}\0{artifact_id}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")

    evidence = scenario / "evidence"
    actual_paths = {p.resolve() for p in evidence.rglob("*") if p.is_file()} if evidence.exists() else set()
    if actual_paths != expected_paths:
        errors.append(f"physical/reference mismatch: {scenario.name}")

    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if not artifact or not artifact.get("relativePath"):
            errors.append(f"invalid artifact reference: {scenario.name}/{ref}")
            continue
        lines = (scenario / artifact["relativePath"]).read_text().splitlines()
        if not 1 <= ref["startLine"] <= ref["endLine"] <= len(lines):
            errors.append(f"invalid line span: {scenario.name}/{ref}")

print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(all_artifacts))
print("capture_states:", {s: sum(a.get("captureState") == s for a in all_artifacts)
                          for s in sorted({a.get("captureState") for a in all_artifacts})})
print("physical_files:", len(physical))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("errors:", errors or "none")
PY

echo '=== TRACKED EVIDENCE FILES ==='
git ls-files "$fixture_root" | grep -E '/evidence/.*smsts\.(log|lo_)$' | sort

echo '=== PRIVACY / UNSUPPORTED-CLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 205015


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
base='25b37333affde22b4ef8a19f4a5f3d89c082b599'
head='6f5f2d2e4341feace86e422008f397fd519bd353'

print_range() {
  local file="$1" start="$2" end="$3"
  echo "=== ${file}:${start}-${end} ==="
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{printf "%5d  %s\n", n++, $0}'
}

echo '=== EXACT DIRECT-BASE FILES ==='
git diff --name-status "$base" "$head"

echo '=== PHYSICAL EVIDENCE / MANIFEST VALIDATION ==='
print_range "$test_file" 300 700

echo '=== COVERAGE / PROVENANCE / KEY / PATH / TIMESTAMP VALIDATION ==='
print_range "$test_file" 700 1238

echo '=== OUTCOME / FINDING / REFERENCE VALIDATION ==='
print_range "$test_file" 1239 1460

echo '=== REAL VALIDATE_CONTRACT COHERENT MUTATIONS ==='
print_range "$test_file" 2050 2270

echo '=== SPECIFICATION BOUNDARIES ==='
nl -ba "$spec_file" | sed -n '1,260p'

echo '=== MUTATED-SCENARIO MANIFEST FACTS ==='
for scenario in completed rotation-boundary relocated-fragments invalid-offset unknown-profile incomplete complete-looking-unkeyed client-installed; do
  printf '\n--- %s/manifest.json ---\n' "$scenario"
  jq -c '.artifacts[] | {artifactId,captureState,pathClass,pathFingerprint,sanitizedSourcePath,smstsLogPathEvidence,sourceVersion,capturedUtc,relocationOrdinal,rotation}' \
    "crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/$scenario/manifest.json"
  printf '%s\n' "--- $scenario/expected.json outcome fields ---"
  jq -c '{extractionProfile,coverage,transactions:(.transactions|map({transactionId,classification,state,confidence,confidenceCeiling,terminalEvidence,nextArtifact,pathSequence,orderingEvidence,timestampProvenance})),findings:(.findings|map({findingId,classification,evidence,coverageGapArtifactIds,boundedNextArtifact}))}' \
    "crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/$scenario/expected.json"
done

Length of output: 78193


🏁 Script executed:

#!/bin/bash
set -euo pipefail

spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'

echo '=== SPECIFICATION ==='
awk '{printf "%5d  %s\n", NR, $0}' "$spec_file"

echo '=== PHYSICAL _SMSTSLogPath / DECLARED PROVENANCE CONSISTENCY ==='
python3 - <<'PY'
import json
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
prefixes = {
    "SYNTHETIC://client/": "client",
    "SYNTHETIC://full-os/": "fullOs",
    "SYNTHETIC://setup/": "setup",
    "SYNTHETIC://unknown/": "unknown",
    "SYNTHETIC://winpe/": "winpe",
}
errors = []
for scenario in sorted(p for p in root.iterdir() if p.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    for artifact in manifest["artifacts"]:
        artifact_id = artifact["artifactId"]
        if artifact["captureState"] != "captured":
            if artifact["pathClass"] != "unknown":
                errors.append(f"{scenario.name}/{artifact_id}: noncapture class")
            continue
        contents = (scenario / artifact["relativePath"]).read_text()
        marker = "_SMSTSLogPath="
        observed = set()
        offset = 0
        while (index := contents.find(marker, offset)) >= 0:
            value = contents[index + len(marker):]
            end = next((i for i, c in enumerate(value) if c.isspace() or c == "]"), len(value))
            observed.add(value[:end])
            offset = index + len(marker)
        expected = artifact["sanitizedSourcePath"]
        actual_class = next((klass for prefix, klass in prefixes.items() if expected.startswith(prefix)), None)
        if observed != {expected}:
            errors.append(f"{scenario.name}/{artifact_id}: observed={sorted(observed)} expected={expected}")
        if artifact["smstsLogPathEvidence"] != expected or actual_class != artifact["pathClass"]:
            errors.append(f"{scenario.name}/{artifact_id}: declared provenance/class mismatch")
        print(f"{scenario.name}/{artifact_id}: {artifact['pathClass']} {artifact['rotation']['kind']} "
              f"ordinal={artifact['relocationOrdinal']} path={expected}")
print("errors:", errors or "none")
PY

echo '=== BOUNDARY AND PROHIBITED-CLAIM OCCURRENCES ==='
rg -n -i -C 2 \
  'proposedPending318And319|preparation|fixture|synthetic|production|reducer|extractor|native|Windows|ConfigMgr|server|caus|application|policy|no.run|noTaskSequence|unsupported|scope' \
  "$spec_file" crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs

Length of output: 59255


@adamgell I found one remaining provenance gap in the fresh exact-head review.

  • P2 — Bind _SMSTSLogPath to each physical artifact, not all artifacts sharing a fingerprint
    In crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs, Lines 671-713 aggregate _SMSTSLogPath values by pathFingerprint and then validate every captured artifact against that shared set. The rotation-boundary current smsts.log fragment contains no _SMSTSLogPath= value, yet it passes because the archived smsts.lo_ fragment has the same fingerprint and supplies SYNTHETIC://client/CCM/Logs/smsts.log. This lets an artifact borrow physical path provenance from a different file, which conflicts with the specification’s per-captured-artifact provenance contract. Validate the path observation against the artifact’s own physical evidence, or explicitly model the controlled archived-to-current reconstruction as a single logical provenance source and ensure per-fragment provenance is not claimed. Add a mutation that removes or changes the sole _SMSTSLogPath from one shared-fingerprint fragment and confirms the other fragment cannot still satisfy its independent claim.

The substantive bypass closures otherwise appear implemented in the real validate_contract harness: complete CCM grammar, source-version/profile/capture-time binding, evidence-derived relocation order, terminal outcome citations, confidence ceilings, unknown/unkeyed and invalid-offset restrictions, finding terminality/request bounds, and absent-coverage/no-run behavior.

The corpus inventory/digest and tracked evidence reconciliation match the documented values. The preparation-only, synthetic privacy, no-production-readiness, no-native-acceptance, and no-server/application/policy-causality boundaries remain explicit. Runtime tests were not executed in this read-only sandbox.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Owner Author

@coderabbitai review

Please re-review exact head 37dc6d08920c9dcb04a325f5dfe7531531695d9a against direct base 25b37333affde22b4ef8a19f4a5f3d89c082b599.

Tracking P2: #352 (comment). Fixed in 37dc6d0 with a test-first closure against the real validate_contract:

  • RED at 6f5f2d2: exactly 2/2 mutations were accepted — the current suffix borrowed a coherently changed lo path, and a same-fingerprint donor supplied path provenance after the lo token was removed
  • the current suffix now declares per-artifact smstsLogPathEvidence: null; its sanitizedSourcePath remains capture provenance only
  • every physical path claim must be present in that same artifact; complete records require their own observation, while incomplete fragments may explicitly declare absence
  • the only allowed logical path reconstruction explicitly orders lo then current, cites the lo line that physically contains _SMSTSLogPath, validates both fragments and exact joined CCM grammar, and stays partial/Low/source-local/noncorrelatable
  • shared fingerprint alone supplies no evidence; changed-token and same-fingerprint-donor mutations are committed and rejected
  • no evidence bytes changed; inventory remains 17 scenarios / 22 artifacts / 21 files / 8,243 bytes / 21 lines / 19 complete / 2 partial, digest 917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b
  • exact-head gates: focused 10/10, full parser 664/664, strict Clippy, wasm32, TypeScript, scoped Rustfmt, and diff checks pass

Please verify this P2 closure plus the previous 14 coherent-mutation closures and preparation-only/no-production/no-native boundaries. PR remains draft.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='25b37333affde22b4ef8a19f4a5f3d89c082b599'
prior='6f5f2d2e4341feace86e422008f397fd519bd353'
head='37dc6d08920c9dcb04a325f5dfe7531531695d9a'
test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'
rotation_root="${fixture_root}/rotation-boundary"

git cat-file -e "${base}^{commit}"
git cat-file -e "${prior}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== COMMIT RELATIONSHIPS ==='
git merge-base --is-ancestor "$base" "$head" && echo 'base is ancestor of head'
git merge-base --is-ancestor "$prior" "$head" && echo 'prior reviewed head is ancestor of head'
git show -s --format='head=%H%nparents=%P%nsubject=%s' "$head"

echo '=== DIRECT-BASE CHANGED FILES ==='
git diff --name-status "$base" "$head"
echo '=== P2 FOLLOW-UP DIFF / CHECK ==='
git diff --check "$prior" "$head"
git diff --unified=45 "$prior" "$head" -- "$test_file" "$spec_file" "$rotation_root"

echo '=== CONTRACT MAP ==='
ast-grep outline "$test_file" --items all --type function --view expanded

echo '=== TARGETED VALIDATOR / P2 / MUTATION LOCATIONS ==='
rg -n -i -C 8 \
  'fn validate_contract|smstsLogPathEvidence|_SMSTSLogPath|pathFingerprint|rotation|logical.*reconstruct|complete.*record|partial|mutation|assert.*err|coherent|sourceVersion|capture.*time|relocat|terminal|classification|confidence|unknown|unkeyed|invalid.offset|finding|request|absent|no.run|executionId|runContext|advertisementId' \
  "$test_file"

echo '=== SELECTED CONTRACT RANGES ==='
for range in '300,780' '780,1260' '1260,1510' '2000,2360'; do
  start="${range%,*}"; end="${range#*,}"
  echo "--- ${test_file}:${start}-${end} ---"
  sed -n "${start},${end}p" "$test_file" | awk -v n="$start" '{printf "%5d  %s\n", n++, $0}'
done

echo '=== ROTATION-BOUNDARY MANIFEST / EXPECTED / EVIDENCE ==='
for file in "$rotation_root/manifest.json" "$rotation_root/expected.json"; do
  echo "--- $file ---"
  nl -ba "$file"
done
while IFS= read -r file; do
  echo "--- $file ---"
  nl -ba "$file"
done < <(fd -t f . "$rotation_root/evidence" | sort)

echo '=== SPECIFICATION BOUNDARIES ==='
nl -ba "$spec_file" | sed -n '1,280p'

echo '=== INVENTORY / REFERENCE / DIGEST / TRACKING ==='
python3 - <<'PY'
import hashlib, json, subprocess
from pathlib import Path
root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, artifacts_all = [], [], [], []
for scenario in sorted(p for p in root.iterdir() if p.is_dir()):
    manifest = json.loads((scenario/"manifest.json").read_text())
    expected = json.loads((scenario/"expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    artifacts_all.extend(artifacts.values())
    refs, expected_paths = [], set()
    def walk(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys(): refs.append(value)
            for child in value.values(): walk(child)
        elif isinstance(value, list):
            for child in value: walk(child)
    walk(expected)
    for artifact_id, artifact in artifacts.items():
        rel = artifact.get("relativePath")
        if not rel: continue
        path = scenario / rel
        if not path.is_file():
            errors.append(f"missing {path}"); continue
        data = path.read_bytes()
        physical.append(path); expected_paths.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied {scenario.name}/{artifact_id}")
        rows.append(f"{scenario.name}\0{artifact_id}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    actual_paths = {p.resolve() for p in (scenario/"evidence").rglob("*") if p.is_file()} if (scenario/"evidence").exists() else set()
    if actual_paths != expected_paths: errors.append(f"storage {scenario.name}")
    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if not artifact or not artifact.get("relativePath"):
            errors.append(f"bad-ref {scenario.name}:{ref}"); continue
        line_count = len((scenario/artifact["relativePath"]).read_text().splitlines())
        if not 1 <= ref["startLine"] <= ref["endLine"] <= line_count:
            errors.append(f"span {scenario.name}:{ref}")
tracked = set(subprocess.check_output(["git","ls-files",str(root)], text=True).splitlines())
untracked = [str(p) for p in physical if str(p) not in tracked]
print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(artifacts_all))
print("capture_states:", {s: sum(a.get("captureState")==s for a in artifacts_all) for s in sorted({a.get("captureState") for a in artifacts_all})})
print("physical_files:", len(physical))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("untracked:", untracked or "none")
print("errors:", errors or "none")
PY

echo '=== PRIVACY / OVERCLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 241217


🏁 Script executed:

#!/bin/bash
set -euo pipefail

test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'
rotation_root="${fixture_root}/rotation-boundary"

print_range() {
  local file="$1" start="$2" end="$3"
  echo "--- ${file}:${start}-${end} ---"
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{printf "%5d  %s\n", n++, $0}'
}

echo '=== REMAINING COHERENT MUTATIONS AND P2 TEST ==='
print_range "$test_file" 2360 2630

echo '=== ROTATION FIXTURE ==='
for file in "$rotation_root/manifest.json" "$rotation_root/expected.json"; do
  echo "--- $file ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$file"
done
while IFS= read -r file; do
  echo "--- $file ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$file"
done < <(find "$rotation_root/evidence" -type f -print | sort)

echo '=== BOUNDARY ASSERTIONS AND SPEC ==='
print_range "$test_file" 1510 1680
awk '{printf "%5d  %s\n", NR, $0}' "$spec_file"

echo '=== STATIC INVENTORY / REFERENCES / TRACKING / DIGEST ==='
python3 - <<'PY'
import hashlib, json, subprocess
from pathlib import Path
root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, physical, rows, all_artifacts = [], [], [], []
for scenario in sorted(path for path in root.iterdir() if path.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {artifact["artifactId"]: artifact for artifact in manifest["artifacts"]}
    all_artifacts.extend(artifacts.values())
    refs = []
    def visit(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys(): refs.append(value)
            for nested in value.values(): visit(nested)
        elif isinstance(value, list):
            for nested in value: visit(nested)
    visit(expected)
    declared = set()
    for artifact_id, artifact in artifacts.items():
        rel = artifact.get("relativePath")
        if rel is None: continue
        path = scenario / rel
        if not path.is_file():
            errors.append(f"missing {path}"); continue
        data = path.read_bytes()
        physical.append(path); declared.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied {scenario.name}/{artifact_id}")
        rows.append(f"{scenario.name}\0{artifact_id}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    actual = {path.resolve() for path in (scenario / "evidence").rglob("*") if path.is_file()} if (scenario / "evidence").exists() else set()
    if actual != declared: errors.append(f"storage mismatch {scenario.name}")
    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if artifact is None or artifact.get("relativePath") is None:
            errors.append(f"invalid citation {scenario.name}:{ref}"); continue
        total = len((scenario / artifact["relativePath"]).read_text().splitlines())
        if not 1 <= ref["startLine"] <= ref["endLine"] <= total:
            errors.append(f"bad span {scenario.name}:{ref}")
tracked = set(subprocess.check_output(["git", "ls-files", str(root)], text=True).splitlines())
print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(all_artifacts))
print("capture_states:", {s: sum(a.get("captureState") == s for a in all_artifacts) for s in sorted({a.get("captureState") for a in all_artifacts})})
print("physical_files:", len(physical))
print("complete_physical:", sum(a.get("captureState") == "captured" and a.get("rotation",{}).get("fragmentComplete") is True for a in all_artifacts))
print("partial_physical:", sum(a.get("captureState") == "captured" and a.get("rotation",{}).get("fragmentComplete") is False for a in all_artifacts))
print("bytes:", sum(path.stat().st_size for path in physical))
print("lines:", sum(len(path.read_text().splitlines()) for path in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("untracked:", [str(path) for path in physical if str(path) not in tracked] or "none")
print("errors:", errors or "none")
PY

echo '=== PRIVACY / PROHIBITED CLAIMS ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 23485


🏁 Script executed:

#!/bin/bash
set -u

fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'
rotation_root="${fixture_root}/rotation-boundary"
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'

echo '=== RAW ROTATION EVIDENCE ==='
python3 - <<'PY'
from pathlib import Path
root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence")
for path in sorted(p for p in root.rglob("*") if p.is_file()):
    print(f"--- {path} ---")
    for number, line in enumerate(path.read_text().splitlines(), 1):
        print(f"{number:5d}  {line}")
PY

echo '=== INVENTORY / REFERENCES / TRACKING / DIGEST ==='
python3 - <<'PY'
import hashlib, json, subprocess
from pathlib import Path
root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, physical, rows, all_artifacts = [], [], [], []
for scenario in sorted(path for path in root.iterdir() if path.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {artifact["artifactId"]: artifact for artifact in manifest["artifacts"]}
    all_artifacts.extend(artifacts.values())
    refs = []
    def visit(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys():
                refs.append(value)
            for nested in value.values():
                visit(nested)
        elif isinstance(value, list):
            for nested in value:
                visit(nested)
    visit(expected)
    declared = set()
    for artifact_id, artifact in artifacts.items():
        rel = artifact.get("relativePath")
        if rel is None:
            continue
        path = scenario / rel
        if not path.is_file():
            errors.append(f"missing {path}")
            continue
        data = path.read_bytes()
        physical.append(path)
        declared.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied {scenario.name}/{artifact_id}")
        rows.append(f"{scenario.name}\0{artifact_id}\0{rel}\0{hashlib.sha256(data).hexdigest()}\n")
    evidence_root = scenario / "evidence"
    actual = {path.resolve() for path in evidence_root.rglob("*") if path.is_file()} if evidence_root.exists() else set()
    if actual != declared:
        errors.append(f"storage mismatch {scenario.name}")
    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if artifact is None or artifact.get("relativePath") is None:
            errors.append(f"invalid citation {scenario.name}:{ref}")
            continue
        total = len((scenario / artifact["relativePath"]).read_text().splitlines())
        if not 1 <= ref["startLine"] <= ref["endLine"] <= total:
            errors.append(f"bad span {scenario.name}:{ref}")
tracked = set(subprocess.check_output(["git", "ls-files", str(root)], text=True).splitlines())
print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(all_artifacts))
print("capture_states:", {s: sum(a.get("captureState") == s for a in all_artifacts) for s in sorted({a.get("captureState") for a in all_artifacts})})
print("physical_files:", len(physical))
print("complete_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is True for a in all_artifacts))
print("partial_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is False for a in all_artifacts))
print("bytes:", sum(path.stat().st_size for path in physical))
print("lines:", sum(len(path.read_text().splitlines()) for path in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("untracked:", [str(path) for path in physical if str(path) not in tracked] or "none")
print("errors:", errors or "none")
PY

echo '=== PRIVACY / PROHIBITED CLAIMS (MATCHES, IF ANY) ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 5507


@adamgell Re-reviewed exact head 37dc6d08920c9dcb04a325f5dfe7531531695d9a against direct base 25b37333affde22b4ef8a19f4a5f3d89c082b599. No findings.

The P2 closure is substantive:

  • _SMSTSLogPath is now checked against each artifact’s own physical contents; the prior shared-pathFingerprint aggregation is gone.
  • The current smsts.log suffix correctly declares smstsLogPathEvidence: null and physically contains no path token. The archived smsts.lo_ fragment contains the sole observed _SMSTSLogPath.
  • The explicit logicalReconstructions contract permits only the controlled lo → current join, cites the lo fragment’s physical path-token line, verifies that the ordered concatenation yields exactly one CCM record, and requires partial/Low/source-local/noncorrelatable semantics with no transaction promotion.
  • Each missing per-artifact path observation must have exactly one such constrained reconstruction. A shared fingerprint by itself supplies no provenance.
  • The committed changed-token and same-fingerprint-donor mutations invoke the real validate_contract and fail closed.

I also rechecked the previous coherent-mutation closures: physical CCM completeness; path class/source version/profile/capture-time binding; evidence-derived relocation ordering; exact per-record execution keys; terminal evidence and finding terminality; invalid-offset confidence limits; unknown/unkeyed non-promotion; bounded requests; and absent coverage remaining distinct from a no-run conclusion.

Static corpus reconciliation passed: 17 scenarios, 22 artifacts, 21 tracked evidence files, 19 complete and 2 partial physical fragments, 8,243 bytes, 21 lines, and SHA-256:

917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b

The preparation-only, no-production-readiness, no-native-acceptance, no-server/application/policy-causality, and synthetic privacy boundaries remain explicit. Runtime tests were not executed in this read-only sandbox.

You are interacting with an AI system.

@adamgell adamgell added test Testing related sccm SCCM/ConfigMgr related parser Log parser related enhancement New feature or request labels Jul 31, 2026
@adamgell adamgell added this to the SCCM End-to-End Diagnostics milestone Jul 31, 2026
@adamgell

Copy link
Copy Markdown
Owner Author

Coordinator restack owner active in isolated worktree .worktrees/sccm-324-restack-a8a, branch codex/sccm-324-restack-a8a, exact preparation head 37dc6d08920c9dcb04a325f5dfe7531531695d9a. Scope is only merging stable foundation a8a367c661cd17bd1e73b87724c143ec8565ffc7, combined-tree verification, and a non-force update after remote-head validation. No production reducer/native/live claim or speculative interface change. Fresh full-range CodeRabbit and a different exact-head reviewer remain mandatory; PR stays draft/open.

@adamgell

Copy link
Copy Markdown
Owner Author

🟢 #324 restack is pushed at exact head 823e6878adc1ec2f1a790ae2e3fbe8bc9c09c958.

Scope/dependency state:

Verification at 823e6878:

  • cargo +1.88.0 test --locked -p cmtraceopen-parser --test sccm_client_task_sequence_fixture_contract — 10 passed.
  • cargo +1.88.0 test --locked -p cmtraceopen-parser --test sccm_spine_contract — 136 passed.
  • cargo +1.88.0 test --locked -p cmtraceopen-parser --test sccm_client_intake_fixture_contract — 3 passed.
  • cargo +1.88.0 test --locked -p cmtraceopen-parser — 739 passed, 0 failed.
  • cargo clippy --locked -p cmtraceopen-parser --all-targets --all-features -- -D warnings — passed.
  • cargo +1.88.0 check --locked -p cmtraceopen-parser --target wasm32-unknown-unknown — passed.
  • npx tsc --noEmit — passed during this exact restack validation.
  • all changed JSON parsed successfully.
  • rustfmt +1.88.0 --edition 2021 --check crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs — passed.
  • git diff --check a8a367c6...HEAD — passed.
  • Workspace-wide cargo +1.88.0 fmt --all -- --check still reports only inherited formatting drift outside the SCCM Client: diagnose task-sequence execution across WinPE and post-client phases #324 file set; no SCCM Client: diagnose task-sequence execution across WinPE and post-client phases #324-owned file is implicated.

Next gate: full-range CodeRabbit at this exact SHA, then independent exact-head review.

@adamgell

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

Please perform a fresh full-range review of exact head 823e6878adc1ec2f1a790ae2e3fbe8bc9c09c958 against base a8a367c661cd17bd1e73b87724c143ec8565ffc7. Prior review of 37dc6d08 is stale after the foundation restack. Please specifically re-check task-sequence rotation/path provenance, coverage-state semantics, deterministic fixture projection, citation bounds, privacy, and conservative confidence. A status-only, skipped, rate-limited, or stale-SHA response will not be treated as approval.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='a8a367c661cd17bd1e73b87724c143ec8565ffc7'
head='823e6878adc1ec2f1a790ae2e3fbe8bc9c09c958'
test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'

git cat-file -e "${base}^{commit}"
git cat-file -e "${head}^{commit}"

echo '=== EXACT COMMITS AND RELATIONSHIP ==='
git show -s --format='base=%H%nbase_parents=%P%nbase_subject=%s' "$base"
git show -s --format='head=%H%nhead_parents=%P%nhead_subject=%s' "$head"
git merge-base --is-ancestor "$base" "$head" && echo 'base_is_ancestor=true'
echo 'merge_base='
git merge-base "$base" "$head"

echo '=== DIRECT-BASE CHANGED FILES ==='
git diff --name-status --find-renames "$base" "$head"
echo '=== DIFF CHECK ==='
git diff --check "$base" "$head"
echo '=== DIFF STAT ==='
git diff --stat "$base" "$head"

echo '=== CONTRACT OUTLINE ==='
ast-grep outline "$test_file" --items all --type function --view expanded

echo '=== VALIDATOR, MUTATIONS, AND BOUNDARY LOCATIONS ==='
rg -n -i -C 5 \
  'fn validate_contract|smstsLogPathEvidence|_SMSTSLogPath|pathFingerprint|logicalReconstructions|rotation|coverage|captureState|citation|startLine|endLine|digest|determin|confidence|confidenceCeiling|unknown|unkeyed|invalid.offset|terminal|finding|privacy|production|native|server|causal|mutation' \
  "$test_file" "$spec_file"

echo '=== FULL CONTRACT FILE ==='
nl -ba "$test_file"

echo '=== FULL PREPARATION SPECIFICATION ==='
nl -ba "$spec_file"

echo '=== DIRECT-BASE DIFF ==='
git diff --find-renames --unified=20 "$base" "$head"

echo '=== ROTATION-BOUNDARY FIXTURE ==='
for file in "$fixture_root/rotation-boundary/manifest.json" "$fixture_root/rotation-boundary/expected.json"; do
  echo "--- $file ---"
  nl -ba "$file"
done
while IFS= read -r file; do
  echo "--- $file ---"
  nl -ba "$file"
done < <(fd -t f . "$fixture_root/rotation-boundary/evidence" | sort)

echo '=== STATIC CORPUS RECONCILIATION ==='
python3 - <<'PY'
import hashlib
import json
import subprocess
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, all_artifacts = [], [], [], []
for scenario in sorted(p for p in root.iterdir() if p.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    all_artifacts.extend(artifacts.values())
    refs = []

    def visit(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys():
                refs.append(value)
            for nested in value.values():
                visit(nested)
        elif isinstance(value, list):
            for nested in value:
                visit(nested)
    visit(expected)

    declared_paths = set()
    for artifact_id, artifact in artifacts.items():
        relative_path = artifact.get("relativePath")
        if relative_path is None:
            continue
        path = scenario / relative_path
        if not path.is_file():
            errors.append(f"missing={scenario.name}/{relative_path}")
            continue
        data = path.read_bytes()
        physical.append(path)
        declared_paths.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied={scenario.name}/{artifact_id}")
        rows.append(
            f"{scenario.name}\0{artifact_id}\0{relative_path}\0"
            f"{hashlib.sha256(data).hexdigest()}\n"
        )

    evidence_root = scenario / "evidence"
    actual_paths = {p.resolve() for p in evidence_root.rglob("*") if p.is_file()} if evidence_root.exists() else set()
    if actual_paths != declared_paths:
        errors.append(f"evidence-storage={scenario.name}")

    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if artifact is None or artifact.get("relativePath") is None:
            errors.append(f"invalid-reference={scenario.name}:{ref}")
            continue
        lines = (scenario / artifact["relativePath"]).read_text().splitlines()
        if not 1 <= ref["startLine"] <= ref["endLine"] <= len(lines):
            errors.append(f"line-span={scenario.name}:{ref}")

tracked = set(subprocess.check_output(["git", "ls-files", str(root)], text=True).splitlines())
print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(all_artifacts))
print("physical_files:", len(physical))
print("complete_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is True for a in all_artifacts))
print("partial_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is False for a in all_artifacts))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("untracked:", [str(p) for p in physical if str(p) not in tracked] or "none")
print("errors:", errors or "none")
PY

echo '=== PROHIBITED PRIVACY AND OVERCLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 248871


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='a8a367c661cd17bd1e73b87724c143ec8565ffc7'
head='823e6878adc1ec2f1a790ae2e3fbe8bc9c09c958'
test_file='crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs'
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'
fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'
rotation_root="$fixture_root/rotation-boundary"

print_range() {
  local file="$1" start="$2" end="$3"
  echo "=== $file:$start-$end ==="
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{printf "%5d  %s\n", n++, $0}'
}

echo '=== VALIDATOR: MANIFEST, PHYSICAL PROVENANCE, AND COVERAGE ==='
print_range "$test_file" 517 776
print_range "$test_file" 777 1135

echo '=== VALIDATOR: KEY BINDING, ORDERING, CONFIDENCE, FINDINGS, AND CITATIONS ==='
print_range "$test_file" 1136 1675

echo '=== CONTRACT TESTS: DETERMINISM, COVERAGE, AND ROTATION ==='
print_range "$test_file" 1679 2172

echo '=== CONTRACT TESTS: ADVERSARIAL AND COHERENT MUTATIONS ==='
print_range "$test_file" 2173 2611

echo '=== PREPARATION SPECIFICATION ==='
awk '{printf "%5d  %s\n", NR, $0}' "$spec_file"

echo '=== ROTATION-BOUNDARY MANIFEST AND EXPECTED OUTPUT ==='
for file in "$rotation_root/manifest.json" "$rotation_root/expected.json"; do
  echo "--- $file ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$file"
done

echo '=== ROTATION-BOUNDARY PHYSICAL EVIDENCE ==='
while IFS= read -r file; do
  echo "--- $file ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$file"
done < <(fd -t f . "$rotation_root/evidence" | sort)

echo '=== STATIC INVENTORY, REFERENCES, TRACKING, AND DIGEST ==='
python3 - <<'PY'
import hashlib
import json
import subprocess
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, all_artifacts, citation_count = [], [], [], [], 0
for scenario in sorted(p for p in root.iterdir() if p.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    all_artifacts.extend(artifacts.values())
    refs = []
    def visit(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys():
                refs.append(value)
            for nested in value.values():
                visit(nested)
        elif isinstance(value, list):
            for nested in value:
                visit(nested)
    visit(expected)
    citation_count += len(refs)

    declared_paths = set()
    for artifact_id, artifact in artifacts.items():
        relative_path = artifact.get("relativePath")
        if relative_path is None:
            continue
        path = scenario / relative_path
        if not path.is_file():
            errors.append(f"missing={scenario.name}/{relative_path}")
            continue
        data = path.read_bytes()
        physical.append(path)
        declared_paths.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied={scenario.name}/{artifact_id}")
        rows.append(f"{scenario.name}\0{artifact_id}\0{relative_path}\0{hashlib.sha256(data).hexdigest()}\n")

    evidence_root = scenario / "evidence"
    actual_paths = {p.resolve() for p in evidence_root.rglob("*") if p.is_file()} if evidence_root.exists() else set()
    if actual_paths != declared_paths:
        errors.append(f"evidence-storage={scenario.name}")

    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if artifact is None or artifact.get("relativePath") is None:
            errors.append(f"invalid-reference={scenario.name}:{ref}")
            continue
        lines = (scenario / artifact["relativePath"]).read_text().splitlines()
        if not 1 <= ref["startLine"] <= ref["endLine"] <= len(lines):
            errors.append(f"line-span={scenario.name}:{ref}")

tracked = set(subprocess.check_output(["git", "ls-files", str(root)], text=True).splitlines())
print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(all_artifacts))
print("physical_files:", len(physical))
print("citations_checked:", citation_count)
print("complete_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is True for a in all_artifacts))
print("partial_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is False for a in all_artifacts))
print("capture_states:", {state: sum(a.get("captureState") == state for a in all_artifacts) for state in sorted({a.get("captureState") for a in all_artifacts})})
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("untracked:", [str(p) for p in physical if str(p) not in tracked] or "none")
print("errors:", errors or "none")
PY

echo '=== DIFF CHECK ==='
git diff --check "$base" "$head"

echo '=== PRIVACY AND PROHIBITED-CLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 130865


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fixture_root='crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence'
rotation_root="$fixture_root/rotation-boundary"
spec_file='docs/sccm/preparation/issue-324-client-task-sequence-corpus.md'

echo '=== ROTATION-BOUNDARY PHYSICAL EVIDENCE ==='
find "$rotation_root/evidence" -type f -print | sort | while IFS= read -r file; do
  echo "--- $file ---"
  awk '{printf "%5d  %s\n", NR, $0}' "$file"
done

echo '=== STATIC INVENTORY, REFERENCES, TRACKING, AND DIGEST ==='
python3 - <<'PY'
import hashlib
import json
import subprocess
from pathlib import Path

root = Path("crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence")
errors, rows, physical, artifacts_all = [], [], [], []
citation_count = 0
for scenario in sorted(p for p in root.iterdir() if p.is_dir()):
    manifest = json.loads((scenario / "manifest.json").read_text())
    expected = json.loads((scenario / "expected.json").read_text())
    artifacts = {a["artifactId"]: a for a in manifest["artifacts"]}
    artifacts_all.extend(artifacts.values())
    refs = []

    def visit(value):
        if isinstance(value, dict):
            if {"artifactId", "startLine", "endLine"} <= value.keys():
                refs.append(value)
            for nested in value.values():
                visit(nested)
        elif isinstance(value, list):
            for nested in value:
                visit(nested)
    visit(expected)
    citation_count += len(refs)

    declared_paths = set()
    for artifact_id, artifact in artifacts.items():
        relative_path = artifact.get("relativePath")
        if relative_path is None:
            continue
        path = scenario / relative_path
        if not path.is_file():
            errors.append(f"missing={scenario.name}/{relative_path}")
            continue
        data = path.read_bytes()
        physical.append(path)
        declared_paths.add(path.resolve())
        if artifact.get("bytesCopied") != len(data):
            errors.append(f"bytesCopied={scenario.name}/{artifact_id}")
        rows.append(f"{scenario.name}\0{artifact_id}\0{relative_path}\0{hashlib.sha256(data).hexdigest()}\n")

    evidence_root = scenario / "evidence"
    actual_paths = {p.resolve() for p in evidence_root.rglob("*") if p.is_file()} if evidence_root.exists() else set()
    if actual_paths != declared_paths:
        errors.append(f"evidence-storage={scenario.name}")

    for ref in refs:
        artifact = artifacts.get(ref["artifactId"])
        if artifact is None or artifact.get("relativePath") is None:
            errors.append(f"invalid-reference={scenario.name}:{ref}")
            continue
        line_count = len((scenario / artifact["relativePath"]).read_text().splitlines())
        if not 1 <= ref["startLine"] <= ref["endLine"] <= line_count:
            errors.append(f"line-span={scenario.name}:{ref}")

tracked = set(subprocess.check_output(["git", "ls-files", str(root)], text=True).splitlines())
print("scenarios:", len([p for p in root.iterdir() if p.is_dir()]))
print("artifacts:", len(artifacts_all))
print("physical_files:", len(physical))
print("citations_checked:", citation_count)
print("capture_states:", {s: sum(a.get("captureState") == s for a in artifacts_all) for s in sorted({a.get("captureState") for a in artifacts_all})})
print("complete_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is True for a in artifacts_all))
print("partial_physical:", sum(a.get("captureState") == "captured" and a.get("rotation", {}).get("fragmentComplete") is False for a in artifacts_all))
print("bytes:", sum(p.stat().st_size for p in physical))
print("lines:", sum(len(p.read_text().splitlines()) for p in physical))
print("digest:", hashlib.sha256("".join(sorted(rows)).encode()).hexdigest())
print("untracked:", [str(p) for p in physical if str(p) not in tracked] or "none")
print("errors:", errors or "none")
PY

echo '=== DIFF CHECK ==='
git diff --check a8a367c661cd17bd1e73b87724c143ec8565ffc7 823e6878adc1ec2f1a790ae2e3fbe8bc9c09c958

echo '=== PRIVACY AND PROHIBITED-CLAIM SCAN ==='
rg -n -i -P \
  '(?:[A-Z]:\\\\|S-1-\d+(?:-\d+){2,}|Authorization:|Bearer |client_secret|@[\w.+-]+\.[A-Za-z]{2,}|serverRootCause|appPolicyRootCause|nativeWindowsAccepted|noTaskSequenceRan|noTaskSequence)' \
  "$fixture_root" "$spec_file" || true

Length of output: 5667


@adamgell Fresh full-range review completed for exact head 823e6878adc1ec2f1a790ae2e3fbe8bc9c09c958 against base a8a367c661cd17bd1e73b87724c143ec8565ffc7. No findings.

The reviewed head is the requested restack merge. Its parents are 37dc6d08920c9dcb04a325f5dfe7531531695d9a and a8a367c661cd17bd1e73b87724c143ec8565ffc7. The requested base is an ancestor of the reviewed head.

Key review results:

  • The rotation contract binds _SMSTSLogPath to the physical smsts.lo_ fragment. The current smsts.log suffix declares smstsLogPathEvidence: null.
  • The only logical reconstruction is ordered lo then current. It must produce exactly one CCM record. Both physical fragments remain partial, low confidence, source-local, and non-correlatable.
  • A shared pathFingerprint provides no path provenance. The changed-token and same-fingerprint-donor mutations fail closed.
  • Coverage is derived from manifest capture state and physical CCM completeness. Absent smsts coverage remains insufficientEvidence. It cannot create a no-run conclusion.
  • Each transaction citation must resolve to one complete normalized CCM record. Every declared exact-key field must occur in that same record.
  • Path ordering uses cited normalized timestamps and contiguous relocation ordinals. Ordering evidence and terminal evidence must be key-bound transaction evidence.
  • Source-local observations remain low confidence and non-correlatable. Unknown-profile, unkeyed, invalid-offset, and partial-rotation evidence cannot be promoted beyond their declared conservative limits.
  • Findings cannot assert server, application, policy, or native-acceptance causality.

Static corpus reconciliation passed:

  • 17 scenarios
  • 22 artifacts
  • 21 tracked evidence files
  • 19 complete and 2 partial physical fragments
  • 8,243 bytes and 21 lines
  • 58 checked citation spans
  • SHA-256 917df82bdf96ae4debd3e02e669669a9b564e932d7052091fb39094305593c8b

The privacy and prohibited-claim scan produced no matches. git diff --check passed. I did not execute runtime tests in this read-only review sandbox.

✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 41 minutes.

@adamgell adamgell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Independent adversarial review of PR #352 at exact head 1db3f4c.
Foundation: merge-base with a8a367c is a8a367c.

Battery: sccm_client_task_sequence_fixture_contract 22 passed; sccm_spine_contract 136 passed;
full cargo test --locked 751 passed, 0 failed; cargo clippy --all-targets -D warnings clean;
wasm32-unknown-unknown check clean. All probes below were run against validate_contract and
reverted; the worktree ends clean at the exact head.

VERDICT: BLOCK. Two of the four previously blocked classes remain partially open.

Gap 1 (exact-token keys, residual admission through bracket delimiters).
complete_field_tokens splits on whitespace and on [ ] < >. Inside a CCM <![LOG[...]LOG]!> body a
bare ] or < is a legal value character (only the full ]LOG]!> sequence terminates the body), so
these characters cannot safely act as token boundaries. Executable evidence: mutating the completed
evidence to runContext=osd]stray while expected.json declares runContext=osd validates Ok; likewise
advertisementId=LAB20305 with declared advertisementId=LAB20305 validates Ok. A declared key
that is a strict prefix of the recorded value is admitted whenever the next on-disk character is one
of the four bracket delimiters. The new GREEN test only probes a non-delimiter suffix (005X).
Suggested fix: split candidate values on whitespace only, or require the needle occurrence to be
bounded by whitespace or record edges.

Gap 2 (one-run findings, source-local laundering).
The insufficientEvidence arm accepts any finding whose citations all match sourceLocalObservations,
but nothing prevents declaring observations that alias keyed transaction evidence. Executable
evidence: in unrelated-runs, adding two keyConfidence "candidate" observations citing the run A and
run B records (the same records cited as exact-keyed transaction evidence) and pooling both refs
into one insufficientEvidence finding validates Ok, reopening exactly the cross-run mixing this head
claims to close. Suggested fix: reject any sourceLocalObservation whose evidence ref equals any
transaction evidence, ordering, or terminal ref (observations exist for records that could not be
keyed), then the laundering path disappears.

Closed and verified at this head: boundary binding (8/8 adversarial variants fail closed, including
missing component, extra field, subset, reordered, unkeyed non-empty joinFields, and scope
escalation) and absent rotation (fragmentComplete, encoding, and collectionLimit all rejected on
noncapture artifacts; no truncated field exists in this schema family; the lane is stricter than the
deployment and health siblings). The lastSuccessfulPhase derivation gap from the earlier round was
closed at c8e597e and is present at head with mutation coverage. Privacy sweep of the lane fixture
directories and the 6629463..HEAD diff found nothing.

Join-fields design question: requiring declared joinFields to equal the enforced exact-key set is
correct for this corpus. The per-transaction validator unconditionally requires all four fields
(executionId, taskSequencePackageId, advertisementId, runContext) on every keyed transaction, so
equality is the only truthful declaration; unkeyed scenarios take the other branch and must declare
an empty list. No legitimate keyed scenario joins on a subset here, and binding both sides to the
same named constant forces declaration and enforcement to change together. The earlier local
CodeRabbit Major on this check was a false positive. Minor observation: the joinFields comparison is
order-sensitive while forbiddenJoinFields is sorted before comparison; this is inconsistent but only
in the fail-closed direction.

Additional observations (non-blocking): the shipped absent artifact in incomplete still carries
capturedUtc and sourceVersion, which the validator admits (parity with siblings); the manifest and
expected schemas are open, so unknown keys such as truncated or sameTimestampDoesNotJoin are
silently accepted.

This review applies to exact head 1db3f4c; any new commits require
re-review.

adamgell added 2 commits July 31, 2026 17:12
Before this change complete_field_tokens treated the bracket
characters as unconditional token boundaries, but inside a CCM
log body a bare bracket is a legal value character, so a
declared key that is a strict prefix of the recorded value was
admitted whenever the next character was a bracket. The
source-local finding path also trusted sourceLocalObservations
without checking that the observed records were not already
keyed transaction evidence, so aliasing observations could
launder a finding that pools two unrelated exact runs.

Add two failing mutation tests: one suffixes recorded values
with bracket-delimited junk and proves the truncated keys are
accepted, the other aliases the two unrelated-runs transaction
records as candidate observations and proves the pooled finding
validates. Both must fail closed.

Refs #324
Before this change complete_field_tokens split cited records on
brackets as well as whitespace, so a bare bracket inside a CCM
body truncated the recorded value and a declared key that was a
strict prefix of it was admitted. Source-local observations were
also trusted blindly, so observations aliasing keyed transaction
records could launder a finding that pools two unrelated runs.

Tokenize only the record body, delimited by the LOG prefix and
the full ]LOG]!> terminator, and split it on whitespace alone:
whitespace and the body edges are the only token boundaries, so
a value bounded by the genuine terminator still matches while
bracket-suffixed junk does not. Reject any sourceLocalObservation
whose citation equals any transaction evidence, ordering, or
terminal reference; observations exist only for records that
could not be keyed, and no shipped scenario aliases. Also sort
both sides of the joinFields comparison so declaration order
cannot fail a correct set, mirroring forbiddenJoinFields.

Refs #324
@adamgell

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@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
`@crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/manifest.json`:
- Line 9: Update the rotated artifact source path in
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/manifest.json:9-9
by setting sanitizedSourcePath to the synthetic smsts.lo_ path while preserving
smstsLogPathEvidence as smsts.log. Mirror this corrected source path in
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/expected.json:12.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 86d844f1-c429-4e7f-846d-2738b2d84357

📥 Commits

Reviewing files that changed from the base of the PR and between a8a367c and 495a36a.

⛔ Files ignored due to path filters (20)
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/evidence/client-task-sequence-smsts/full-os/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/evidence/client-task-sequence-smsts/client/completed/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/evidence/client-task-sequence-smsts/setup/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/evidence/client-task-sequence-smsts/setup/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/evidence/client-task-sequence-smsts/full-os/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/client/completed/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/full-os/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/setup/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/winpe/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/evidence/client-task-sequence-smsts/winpe/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/evidence/client-task-sequence-smsts/unknown/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/evidence/client-task-sequence-smsts/client/root-a/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/evidence/client-task-sequence-smsts/client/root-b/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/evidence/client-task-sequence-smsts/winpe/current/smsts.log is excluded by !**/*.log
📒 Files selected for processing (37)
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/incomplete/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/incomplete/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence/client-task-sequence-smsts/client/lo/smsts.lo_
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/manifest.json
  • crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs
  • docs/sccm/preparation/issue-324-client-task-sequence-corpus.md

adamgell added 2 commits July 31, 2026 21:12
Before this change the rotated smsts.lo_ artifact declared the
active smsts.log path as its sanitized capture source, so the
fixture recorded the active-log path as the physical source of
the rotated file. Nothing failed, because the validator never
bound sanitizedSourcePath to originalBasename or rotation kind,
and its smstsLogPathEvidence equality actively forced capture
provenance to equal the in-record observation that the
specification keeps separate.

Add two failing tests: one pins the rotated artifact's capture
source to the smsts.lo_ path while keeping the in-record
observation on smsts.log, the other mutates the basename in both
directions and proves the validator accepts the mismatch.

Refs #324
Before this change the rotated smsts.lo_ artifact declared the
active smsts.log path as its sanitized capture source, so the
corpus recorded the active-log path as the physical source of
the rotated file. The validator could not catch it: nothing
bound the capture path basename to originalBasename, and the
smstsLogPathEvidence check required the declared observation to
equal the capture path, which forced the very conflation the
specification forbids when it calls an observed _SMSTSLogPath
the authoritative in-record observation and the capture path
mere provenance.

Point the rotated artifact at the smsts.lo_ path in both the
manifest and the expected output while keeping its in-record
observation on smsts.log, require every captured artifact's
capture path to name its own originalBasename, and replace the
observation equality with a directory binding so a declared
observation must be physically present in these bytes and live
beside the artifact it was captured from. Compare the rotated
fragment against its reconstruction by directory, since only
its basename may differ.

Refs #324
@adamgell

adamgell commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

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

🧹 Nitpick comments (1)
crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs (1)

1351-1362: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Apply complete-token matching to phase, state, and terminal markers. The validator enforces complete whitespace-bounded tokens for exact key fields through complete_field_tokens, but it falls back to raw substring contains for the phase, state, and terminal assertions. A recorded value that starts with the declared value therefore satisfies the check. phase=installClient matches a record containing phase=installClientExtra, and state=failed matches state=failedRetry. Reuse complete_field_tokens at both sites so one rule governs every evidence-bound field.

  • crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs#L1351-L1362: build complete_field_tokens(record_text) once per cited record, then require phase={phase} and state={state} as complete tokens.
  • crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs#L1647-L1659: build complete_field_tokens(&terminal_text), then require terminal=true, state={terminal_state}, and phase={phase} as complete tokens.

Add two fail-closed mutations that append a suffix to the recorded phase and state values, and confirm validate_contract rejects both.

🤖 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/sccm_client_task_sequence_fixture_contract.rs`
around lines 1351 - 1362, Replace raw phase/state substring checks with
complete_field_tokens in validate_contract: at
crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs:1351-1362,
build tokens once per cited record and require complete phase and state tokens;
at :1647-1659, build tokens from terminal_text and require complete
terminal=true, terminal state, and phase tokens. Add fail-closed mutations
appending suffixes to recorded phase and state values, and verify
validate_contract rejects both.
🤖 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.

Nitpick comments:
In
`@crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs`:
- Around line 1351-1362: Replace raw phase/state substring checks with
complete_field_tokens in validate_contract: at
crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs:1351-1362,
build tokens once per cited record and require complete phase and state tokens;
at :1647-1659, build tokens from terminal_text and require complete
terminal=true, terminal state, and phase tokens. Add fail-closed mutations
appending suffixes to recorded phase and state values, and verify
validate_contract rejects both.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0fed63e9-0fa6-4fa8-8b7a-11bad5b6d2d2

📥 Commits

Reviewing files that changed from the base of the PR and between a8a367c and ccda4df.

⛔ Files ignored due to path filters (20)
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/evidence/client-task-sequence-smsts/full-os/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/evidence/client-task-sequence-smsts/client/completed/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/evidence/client-task-sequence-smsts/setup/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/evidence/client-task-sequence-smsts/setup/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/evidence/client-task-sequence-smsts/full-os/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/client/completed/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/full-os/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/setup/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/winpe/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/evidence/client-task-sequence-smsts/client/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/evidence/client-task-sequence-smsts/winpe/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/evidence/client-task-sequence-smsts/unknown/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/evidence/client-task-sequence-smsts/client/root-a/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/evidence/client-task-sequence-smsts/client/root-b/current/smsts.log is excluded by !**/*.log
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/evidence/client-task-sequence-smsts/winpe/current/smsts.log is excluded by !**/*.log
📒 Files selected for processing (37)
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/incomplete/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/incomplete/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence/client-task-sequence-smsts/client/lo/smsts.lo_
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/manifest.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/expected.json
  • crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/manifest.json
  • crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs
  • docs/sccm/preparation/issue-324-client-task-sequence-corpus.md

@adamgell adamgell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Round 9 review at exact head 495a36a.

Verdict: BLOCK. Two numbered gaps, one of which voids stated claim (2).

Descent
git merge-base HEAD a8a367c prints
a8a367c, so the foundation is an
ancestor of head.

Battery, all green

  • sccm_client_task_sequence_fixture_contract: 24 passed, 0 failed
  • sccm_spine_contract: 136 passed, 0 failed
  • cmtraceopen-parser full suite: 753 passed, 0 failed
    (cargo test --workspace: 1507 passed, 0 failed)
  • cargo clippy --workspace --all-targets -- -D warnings: exit 0
  • cargo check and cargo clippy for wasm32-unknown-unknown: exit 0
  • Privacy sweep of 6629463..HEAD: clean. The JSON diff is only the
    component addition to 17 forbiddenJoinFields lists plus one
    fragmentComplete removal on the noncapture artifact.

Claim (3), sort-insensitive joinFields: CLOSED.
Reordered declaration accepted. Wrong set (component substituted),
duplicate entry, superset, and subset all rejected with "declared join
fields do not match the enforced exact key fields".

Claim (1), token boundaries: closed for every in-body case, but the
guarantee is narrower than stated. See gap 2.
Accepted: needle bounded by the genuine terminator after _SMSTSLogPath
is moved ahead of it; needle at the exact start of the body with no
leading whitespace; tab separator instead of space; CRLF line endings.
Rejected with "co-occur": a value containing ]LOG]! without the closing
angle bracket; two records on one physical line with the key only in the
second; and both round-7 probes (runContext=osd]stray,
advertisementId=LAB20305).

Claim (2), observation disjointness: NOT achieved. See gap 1.

Gap 1 (blocking). Padded evidence references defeat the new
disjointness rule and re-open the round-7 one-run closure.

The check at sccm_client_task_sequence_fixture_contract.rs:1678-1694
compares whole serde_json Value objects
(transaction_ref == &observation["evidence"]). Evidence references are
open objects and evidence_text reads only artifactId, startLine, and
endLine, so adding one ignored key evades the comparison while the
citation still resolves to the same physical record.

Probes on the unrelated-runs scenario:

  • control, unpadded alias of keyed run A evidence: REJECTED with
    "keyed transaction evidence cannot double as a source-local
    observation"
  • same alias with one extra ignored key added to the evidence object:
    ACCEPTED
  • one finding citing evidence from BOTH unrelated exact runs, laundered
    through two padded source-local observations: ACCEPTED

The third probe is exactly the shape that
finding_evidence_cannot_mix_unrelated_exact_runs (line 3035) pins, and
it passes at head. The same open-object equality is load-bearing in
cited_refs_are_source_local, binding_transactions, and the ordering and
terminal membership checks, so the entire binding chain shares this
weakness.

Suggested fix: compare the identity triple
(artifactId, startLine, endLine), or reject evidence-reference objects
that carry keys outside that triple.

Gap 2 (blocking as claimed, but pre-existing rather than a regression).
The complete_field_tokens fallback widens the token universe to the
whole raw line.

complete_field_tokens ends in .unwrap_or(record_text). When the cited
record text does not start exactly with the CCM opener, the function
silently tokenizes the entire raw line, including the
<time=... context="..." ...> trailer.

Probes on the completed scenario:

  • a single leading space with the record otherwise untouched: ACCEPTED,
    so the fallback is reachable and the framing and fragmentComplete
    rules do not catch it
  • all four exact key values removed from the body and relocated into the
    quoted context trailer attribute, with a leading space: ACCEPTED
  • the identical mutation without the leading space: REJECTED with
    "co-occur"

This is not a regression. Reimplementing the pre-495a36ae tokenizer
finds all four needles in the same exploit string, while the round-7
osd]stray probe is false at head and true pre-495a36ae, confirming the
round-7 improvement is real. The residual is that claim (1) as written
promises body bounding unconditionally, and the fallback silently
degrades it to whole-line matching.

Suggested fix: fail closed. Return an empty token set, or surface an
explicit error, when the record body cannot be delimited. The framing
check already guarantees the cited range is one complete CCM record, so
an undelimitable body is a contract violation rather than a reason to
widen.

Non-blocking observations

  • The orderingEvidence and terminalEvidence disjuncts in the new
    disjointness check are unreachable. Both are already required to be
    members of the evidence array; a probe that moves orderingEvidence out
    of the array is rejected by the membership rule first. Harmless
    redundancy, worth a comment.
  • Two observations with distinct IDs citing an identical record are
    admitted. No authority gain was found.
  • A declared value whose raw text contains an embedded terminator
    (runContext=osd]LOG]!>x) is accepted. This is consistent with the
    parser's own framing and is the same rule that makes the required
    genuine-terminator nuance pass. Not a defect.
  • A second CCM opener appearing mid-body is accepted. Defensible: the
    needle is genuinely whitespace-bounded inside the framed body.
  • The open-schema posture noted in round 7 is normally program-wide and
    not a lane blocker, but gap 1 shows it converting into a bypass of two
    closures this series explicitly claims, which is what makes it
    blocking here rather than cosmetic.

Rounds 1-8 closures, independently reconfirmed with fresh mutations
rather than the shipped assertions alone

  • exact-token prefix and suffix (runContext=xosd, runContext=osdx):
    both rejected
  • absent rotation on the noncapture artifact (fragmentComplete,
    encoding, collectionLimit, bytesCopied): all four rejected
  • boundary binding with component removed from forbiddenJoinFields:
    rejected
  • lastSuccessfulPhase ahead of the observed phase, and a bogus phase:
    both rejected
  • observation off-by-one is not over-broad: an observation citing a
    neighbouring unkeyed record is accepted, while an observation citing
    the keyed record on line 1 is rejected in the same scenario

Exact-head statement
Every command above was run in a detached worktree pinned to
495a36a. All probes were temporary and
were reverted; git status --porcelain is empty and the contract file is
byte-identical to the committed version at that head.

Controller note: this review was performed at 495a36a. Head has since advanced to ccda4df (a rotation capture-provenance RED/GREEN pair). Both gap sites were verified unchanged at ccda4df: the fallback is still at line 425 (.unwrap_or(record_text)) and the whole-Value comparison is still at line 1703 (transaction_ref == &observation["evidence"]). Both findings therefore apply to the current head as written.

adamgell added 2 commits July 31, 2026 21:28
Before this change evidence references were compared as whole
JSON values, but a reference is an open object and only
artifactId, startLine, and endLine are read when resolving it.
Adding one ignored key made two references unequal while both
still resolved to the same physical record, so a padded
observation could alias keyed evidence and a single finding
could pool both unrelated exact runs while appearing
source-local. Separately complete_field_tokens fell back to the
raw line whenever the cited text did not start exactly with the
CCM opener, exposing the time and context trailer to key
admission.

Add three failing tests: a control pair proving an unpadded
alias is rejected while a padded alias is accepted, the
cross-run laundering shape through two padded observations, and
an indented record whose relocated key fields are admitted from
its trailer. Each must fail closed.

Refs #324
Before this change evidence references were compared as whole
JSON values while only artifactId, startLine, and endLine are
read to resolve one. One ignored key therefore made two
references to the same physical record compare as different
citations, so a padded observation aliased keyed evidence and a
finding pooled both unrelated exact runs while matching only the
laundering observations. complete_field_tokens also fell back to
the raw cited line when the CCM opener or terminator was
missing, exposing the time and context trailer to key admission.

Reject any evidence reference carrying keys outside the identity
triple, and compare every citation on that triple in the
ordering, terminal, transaction-membership, observation
disjointness, and source-local paths. Return no token set when a
record body cannot be delimited and fail the citation closed,
since the framing check already proves a cited range is one
complete CCM record. Note why the ordering and terminal
disjuncts are redundant today.

Refs #324
@adamgell

adamgell commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 43 minutes.

@adamgell adamgell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Round 10 review at exact head d1d163b.
Reviewed in a detached worktree pinned to that commit; the tree was clean at
the start and at the end of the review. Foundation SHA from
git merge-base HEAD a8a367c is
a8a367c. The whole contract test file is
added by this PR, so every line discussed below is PR-owned.

Battery, exact counts, all green at d1d163b:
cargo test -p cmtraceopen-parser --test sccm_client_task_sequence_fixture_contract
29 passed, 0 failed
cargo test -p cmtraceopen-parser --test sccm_spine_contract
136 passed, 0 failed
cargo test -p cmtraceopen-parser
758 passed, 0 failed
cargo test --workspace
green
cargo clippy --workspace --all-targets -- -D warnings
no warnings, no errors
cargo check -p cmtraceopen-parser --target wasm32-unknown-unknown
clean
rustfmt --check --edition 2021 on the single changed file
exit 0

RED discipline. Restoring the source state of 531e8e8 fails exactly the three
new tests and no others (26 passed, 3 failed):
padded_evidence_references_cannot_alias_keyed_records
padded_observations_cannot_launder_cross_run_findings
undelimitable_record_bodies_fail_closed
Each failure is an expect_err on an Ok(()), which shows the pre-fix validator
accepted the padded alias, the cross-run laundering, and the relocated-key
shape rather than merely reporting a different error. Restored to d1d163b,
29 of 29 pass.

Mechanism 1, validate_evidence_reference_shapes. Verified closed.
Padded references were probed at every site an evidence reference can occupy
in a shipped expected document, plus two synthetic containers:
transactions[].evidence[] rejected: unmodeled fields
transactions[].orderingEvidence rejected: unmodeled fields
transactions[].terminalEvidence rejected: unmodeled fields
sourceLocalObservations[].evidence rejected: unmodeled fields
findings[].evidence[] rejected: unmodeled fields
logicalReconstructions[].smstsLogPathEvidence rejected: unmodeled fields
novel key, depth 6, through arrays of arrays rejected: unmodeled fields
hung off correlationBoundary rejected: unmodeled fields
Coverage is total by construction because the sweep recurses every object value
and every array element from the expected root.

Evasion by omission or by type does not open a hole. Nine variants were probed
(missing endLine, missing startLine, missing artifactId, startLine as a string,
startLine as a float, negative endLine, numeric artifactId, identity nested one
level deeper, and a pure key reordering). The first eight all fail closed,
because evidence_text, manifest_artifact and collect_evidence_refs read through
the same as_str and as_u64 accessors as evidence_reference_identity, so a
reference that escapes the identity extractor also cannot resolve to a physical
record. The reordering variant is accepted, which is correct: it is a
legitimate identity.

Sweep ordering is correct. validate_evidence_reference_shapes is the second
statement in validate_contract and the only earlier call, validate_manifest_and
_storage, reads the manifest and the filesystem and never touches expected. A
document with workflow, contractState and extractionProfile.status all broken
plus one padded terminalEvidence still fails with the unmodeled-fields error,
so no earlier check can be fooled first.

The characterization of same_evidence_reference as defense in depth rather than
the active catch is accurate, though the stated reason is not quite right on
this build. cargo tree shows serde_json/preserve_order is enabled under a
workspace-wide build through the tauri graph and is not enabled under
-p cmtraceopen-parser, so the map type differs between the two invocations.
Both IndexMap and BTreeMap compare JSON objects order-insensitively, so whole
value equality was never order-sensitive either way. Verified executably: whole
value equality and same_evidence_reference both return true for a reordered
identity.

Mechanism 2, complete_field_tokens returning Option. Verified closed for key
admission. Eight framing shapes were probed against the completed scenario:
opener present, terminator removed rejected by the CCM grammar check
terminator present, opener corrupted rejected by the CCM grammar check
terminator placed before the opener rejected by the CCM grammar check
leading tab before the opener rejected: not delimited by the CCM framing
leading CR before the opener rejected: not delimited by the CCM framing
empty body between valid delimiters rejected by the _SMSTSLogPath check
second opener/terminator pair with the key fields moved after the first
terminator rejected: key fields do not co-occur
CRLF line endings, record otherwise untouched accepted, which is correct
The two shapes that reach the new None branch are precisely the round 9 family.
The embedded second pair confirms that the first terminator wins, so an
injected pair cannot smuggle key tokens.

The round 7 genuine-terminator case has not regressed. After removing
_SMSTSLogPath from the WinPE record the body ends runContext=osd]LOG]!>; the
scenario still validates, complete_field_tokens still yields runContext=osd,
and no trailer field such as component= appears in the token set.

Rounds 1 through 9 were re-confirmed with ten fresh mutations, all rejected:
strict-prefix advertisementId, suffixed taskSequencePackageId, strict-suffix
runContext, lastSuccessfulPhase advanced past the observed phase, narrowed
forbiddenJoinFields, narrowed joinFields, a single finding pooling both exact
runs with unpadded references, rotated-fragment provenance renamed to the
current file, the current fragment declared as the rotated one, and a
reconstruction ordered against the rotation order.

Privacy. git diff over 6629463..HEAD and over the full PR range shows no
hostnames, user paths, drive-letter paths, IP addresses, mail addresses, SIDs,
credentials or tenant identifiers in added lines. Every fixture path is a
SYNTHETIC:// URI. The only pattern hits in the range are inside
fixture_privacy_and_scope_boundaries_are_pinned, which asserts those patterns
are absent from the corpus.

Blocking gap 1. The record trailer that the framing fix removed from key
admission is still admitted for phase, state and terminal binding.

complete_field_tokens now yields tokens only from the delimited body, but the
same loop pushes the raw record_text into cited_record_texts, and the phase and
state binding at lines 1402 to 1404 and the terminal binding at lines 1699 to
1701 use a raw substring contains over the whole physical line, including the
<time=... context="..." ...> trailer. Three mutations of the completed scenario,
each with only bytesCopied resynced in the manifest and the expected document,
were accepted while the contract continued to declare the strongest claim in
the corpus (classification success, confidence high, state succeeded, phase
complete, terminal outcome):

  1. phase=complete state=succeeded deleted from the record body and placed in
    context="phase=complete state=succeeded". Accepted. The body then states
    nothing about phase or state.
  2. Body rewritten to phase=completeX state=succeededX with the contract left
    declaring complete and succeeded. Accepted, because contains has no token
    boundary.
  3. terminal=true deleted from the body and placed in context="terminal=true".
    Accepted. Separately, a body carrying state=succeededLater satisfies the
    terminal state=succeeded check.

This is the same laundering class the last several rounds have been closing,
in the same loop, and it defeats this PR's own assertion in
adversarial_contract_mutations_fail_closed that phase must bind to cited CCM
evidence. The doc comment added to complete_field_tokens names this trailer as
the thing that must not widen admission.

Suggested fix, mechanical: bind phase, state and terminal from
complete_field_tokens applied to the delimited body of the cited record and of
the terminal record, instead of contains over the raw line, so the same body
edges and the same complete-token rule govern all three. Checked across every
shipped fixture record: phase=, state= and terminal= occur only inside the body
and only as complete whitespace-delimited tokens, so this change should require
no fixture edits.

Non-blocking observation. The identity-triple convention is enforced only
inside this test binary. crates/cmtraceopen-parser/tests/fixtures/sccm/client/
policy/contradictory-offset/expected.json ships triple-bearing objects that
carry additional keys at offsetOrderingContract.orderedEvidence[0],
offsetOrderingContract.orderedEvidence[1] and
offsetOrderingContract.nonComparableEvidence[0]. Those belong to a different
corpus with its own validator and are unaffected by this PR, but the convention
is worth stating explicitly if it is meant to become general.

Verdict: BLOCK at d1d163b. Both round 9 gaps
are closed and verified against the new mechanisms directly rather than by
replaying round 9's probes. One numbered gap remains, reproducible from the
shipped completed fixture with three independent mutations.

adamgell added 2 commits July 31, 2026 21:52
Before this change key admission read only the delimited record
body, but the phase, state, and terminal bindings still ran raw
substring searches over the whole cited physical line. The
time and context trailer that key admission excludes was
therefore still admitted for the outcome claims, and a substring
search has no token boundary, so a longer value satisfied a
shorter declared one.

Add a failing table covering six shapes against the strongest
claim in the corpus: phase and state relocated into the trailer,
terminal relocated into the trailer, and suffixed or extended
phase, state, and terminal tokens left in the body while the
contract keeps declaring success at high confidence. All six
must fail closed.

Refs #324
Before this change the phase, state, and terminal bindings ran
raw substring searches over the whole cited physical line, so
the time and context trailer that key admission already excludes
was still admitted for the outcome claims, and a substring match
let a longer recorded value satisfy a shorter declared one. The
strongest claim in the corpus survived moving phase, state, or
terminal out of the record body into the trailer.

Carry the delimited body token set forward from key admission
instead of the raw line, and take the terminal record through
the same helper, so all four bindings share one body edge and
one complete-token rule. The framing check already proves a
cited range is one complete CCM record, so an undelimitable
terminal body fails closed. No fixture changed: every shipped
record already carries these fields inside its body as complete
tokens.

Refs #324
@adamgell

adamgell commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 19 minutes.

@adamgell adamgell left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Round 11 review at exact head 63e4ad4 (RED c0486b3 / GREEN 63e4ad4).

BATTERY
focused 30 passed / 0 failed
spine 136 passed / 0 failed
parser crate 759 passed / 0 failed (351+222+8+3+3+30+1+5+136)
workspace 1513 passed / 0 failed
cargo clippy --workspace --all-targets -- -D warnings: exit 0
cargo check -p cmtraceopen-parser --target wasm32-unknown-unknown: clean
git diff --check 6629463 HEAD: clean
rustfmt --check on the changed file: clean

RED DISCIPLINE
Restoring the c0486b3 source state reproduces 29 passed / 1 failed with the
single table-driven test naming all six shapes: phase-and-state-relocated-to-
trailer, terminal-relocated-to-trailer, phase-token-suffixed, state-token-
suffixed, terminal-token-suffixed, terminal-state-token-extended. Restored to
clean afterward. The 30 rather than 32 count is correct: the six shapes belong
in one table following the existing coherent_review_mutations_fail_closed idiom.

NOVEL SHAPES
Twelve shapes beyond the shipped table, all fail closed at head:
leading-character variants on token and value for phase, state and terminal;
body-wrong/trailer-right for phase, state and terminal; phase and state split
across cited records so no single record carries both; the whole claim
relocated onto a different cited record; terminal record with a delimitable
body but state= or phase= only in the trailer. Body-right/trailer-wrong is
correctly accepted, which settles the precedence question: the body is
authoritative and the trailer is ignored rather than merged.

INDEPENDENT AUDIT
Every consumer of record text and every contains over a record line was
enumerated. The two routed sites are correct. The four exclusions are sound.

The load-bearing exclusion was verified directly rather than accepted. od -c on
the rotation-boundary lo fragment shows it opens <![LOG[, carries
_SMSTSLogPath=, and contains zero ]LOG]!> terminators. Body-bounding the
logical path citation site breaks rotation-boundary; body-bounding the
whole-file scan site breaks rotation-boundary and leading-space. Both
exclusions are necessary, and both are fail-closed in direction: an extra
_SMSTSLogPath anywhere in the bytes breaks the exact-count requirement rather
than laundering a claim.

The remaining three exclusions hold. The two evidence_text calls for
observation and finding citations discard their result and perform no text
matching. The notasksequence check scans finding object keys, not record text.
The privacy scan must remain a raw whole-file scan or it stops seeing the
trailer. No missed site was found; the post-fix grep for record_text.contains,
terminal_text.contains and _text.contains returns none.

OBSERVATION (not blocking, suggest a follow-up issue)
complete_field_tokens tokenizes with split_whitespace(), which treats tab,
NBSP (U+00A0) and form feed as separators, so a value extended past one of
those characters still satisfies a shorter declared value. This is not
introduced here: the helper predates this change and already backs key
admission, the pre-fix raw contains predicate accepted every one of these
cases as well, so post-fix admission is a strict subset of pre-fix admission,
and planting such a character in a shipped fixture trips the pinned corpus
digest (evidence_bytes 8249 against the pinned 8243, plus a digest mismatch).
Worth tightening in the helper separately rather than gating this round.

PRIOR ROUNDS
Ten fresh mutations against the rounds 1 through 10 closures all fail closed:
extended key value, prefixed key token, key relocated to trailer,
bracket-bounded key prefix, removed body terminator, terminal evidence not
key-bound, widened evidence range, swapped rotation basename, inadmissible
lastSuccessfulPhase, dropped timestamp precision.

PRIVACY
6629463..HEAD changes no evidence bytes. All added lines are ASCII. Only the
synthetic 72400000-0000-0000-0000-000000000005 GUID appears. No host paths,
emails, domains, credentials or secrets.

VERDICT: PASS at exact head 63e4ad4. Both round-10 gaps are closed, the class
audit is accurate, and the worktree was verified clean at start and end.

@adamgell
adamgell marked this pull request as ready for review August 1, 2026 13:19
Copilot AI review requested due to automatic review settings August 1, 2026 13:19
@adamgell
adamgell merged commit 2dd2e4e into codex/parser-family-skeleton Aug 1, 2026
1 check passed

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

Prepares a fully synthetic SCCM client Task Sequence corpus (issue #324) and a Rust “contract test” that validates identity, provenance, relocation/rotation semantics, and fail-closed behavior from cited CCM evidence, without introducing any production reducer or intake changes.

Changes:

  • Added a 17-scenario synthetic SMSTS corpus with per-scenario manifest.json/expected.json and evidence files (including rotation fragments).
  • Added a validator-backed Rust contract test that derives/validates coverage, exact-key co-occurrence, relocation ordering, timestamp provenance, and conservative outcome semantics (plus adversarial mutation tests).
  • Added a preparation/spec document describing the corpus scope, boundaries, and replay commands.

Reviewed changes

Copilot reviewed 36 out of 57 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
docs/sccm/preparation/issue-324-client-task-sequence-corpus.md Documents corpus scope/boundaries, scenario matrix, and replay gates.
crates/cmtraceopen-parser/tests/sccm_client_task_sequence_fixture_contract.rs Contract test and validator enforcing corpus invariants and fail-closed mutations.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/manifest.json WinPE scenario manifest metadata/provenance.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/expected.json WinPE expected contract output and citations.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/winpe/evidence/client-task-sequence-smsts/winpe/current/smsts.log WinPE synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/manifest.json Same-timestamp unrelated runs manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/expected.json Expected separation of unrelated executions with identical timestamps.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/evidence/client-task-sequence-smsts/client/root-a/current/smsts.log Synthetic evidence for unrelated run A.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unrelated-runs/evidence/client-task-sequence-smsts/client/root-b/current/smsts.log Synthetic evidence for unrelated run B.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/manifest.json Unknown profile/version manifest for fail-closed behavior.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/expected.json Expected source-local-only handling for unknown profile/version.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/unknown-profile/evidence/client-task-sequence-smsts/unknown/current/smsts.log Unknown-version synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/manifest.json Terminal preflight failure manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/expected.json Expected confirmed terminal preflight failure semantics.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/terminal-preflight/evidence/client-task-sequence-smsts/winpe/current/smsts.log Terminal preflight synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/manifest.json Terminal software-install failure manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/expected.json Expected confirmed terminal software-install failure semantics.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/software-install-failure/evidence/client-task-sequence-smsts/client/current/smsts.log Software-install failure synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/manifest.json Rotation-boundary manifest with split physical fragments.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/expected.json Expected partial coverage + controlled logical reconstruction metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence/client-task-sequence-smsts/client/lo/smsts.lo_ Prefix rotation fragment evidence (partial).
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/rotation-boundary/evidence/client-task-sequence-smsts/client/current/smsts.log Suffix rotation fragment evidence (partial).
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/manifest.json Multi-stage relocation manifest (winpe→setup→fullOs→client).
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/expected.json Expected relocation ordering and terminal completion semantics.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/winpe/current/smsts.log Relocated-fragments WinPE synthetic evidence.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/setup/current/smsts.log Relocated-fragments setup synthetic evidence.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/full-os/current/smsts.log Relocated-fragments full OS synthetic evidence.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/relocated-fragments/evidence/client-task-sequence-smsts/client/completed/smsts.log Relocated-fragments client synthetic evidence.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/manifest.json Reboot-continuation manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/expected.json Expected deferred/blocked semantics for reboot continuation.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/reboot-continuation/evidence/client-task-sequence-smsts/client/current/smsts.log Reboot-continuation synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/manifest.json Pre-client (full OS) manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/expected.json Expected deferred semantics and next-artifact request for pre-client stage.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/pre-client/evidence/client-task-sequence-smsts/full-os/current/smsts.log Pre-client synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/manifest.json Post-format (setup) manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/expected.json Expected in-progress semantics and next-artifact request for relocation.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/post-format/evidence/client-task-sequence-smsts/setup/current/smsts.log Post-format synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/manifest.json Invalid-offset manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/expected.json Expected ordering-unknown semantics and Low confidence ceiling when offset invalid.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/invalid-offset/evidence/client-task-sequence-smsts/client/current/smsts.log Invalid-offset synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/incomplete/manifest.json Incomplete scenario manifest with absent artifact.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/incomplete/expected.json Expected coverage-only output and bounded request for missing SMSTS evidence.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/manifest.json Disk/image failure manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/expected.json Expected confirmed terminal disk/image failure semantics.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/disk-image-failure/evidence/client-task-sequence-smsts/setup/current/smsts.log Disk/image failure synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/manifest.json Completed scenario manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/expected.json Expected terminal success semantics for completed run.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/completed/evidence/client-task-sequence-smsts/client/completed/smsts.log Completed synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/manifest.json Complete-looking but unkeyed manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/expected.json Expected source-local-only semantics when exact key missing.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/complete-looking-unkeyed/evidence/client-task-sequence-smsts/client/current/smsts.log Complete-looking unkeyed synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/manifest.json Client-installed (nonterminal) manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/expected.json Expected in-progress semantics and bounded next-artifact request.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-installed/evidence/client-task-sequence-smsts/client/current/smsts.log Client-installed synthetic CCM evidence line.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/manifest.json Client-install failure manifest metadata.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/expected.json Expected confirmed terminal client-install failure semantics.
crates/cmtraceopen-parser/tests/fixtures/sccm/client/task_sequence/client-install-failure/evidence/client-task-sequence-smsts/full-os/current/smsts.log Client-install failure synthetic CCM evidence line.

Comment on lines +1252 to +1264
let declared_scope = expected["correlationBoundary"]["scope"]
.as_str()
.ok_or_else(|| format!("{scenario}: correlation scope is not a string"))?;
let mut declared_join_fields = string_array(&expected["correlationBoundary"]["joinFields"])?;
declared_join_fields.sort();
let mut declared_forbidden_fields =
string_array(&expected["correlationBoundary"]["forbiddenJoinFields"])?;
declared_forbidden_fields.sort();
if declared_forbidden_fields != FORBIDDEN_JOIN_FIELDS.map(str::to_owned) {
return Err(format!(
"{scenario}: declared forbidden join fields do not match the enforced list"
));
}
adamgell added a commit that referenced this pull request Aug 4, 2026
Before this change an absent or access-denied artifact could carry
encoding, collectionLimit, or truncated metadata and still validate
clean because artifact_provenance_projection silently nulled the
fields instead of the validator rejecting them, letting noncapture
artifacts retain stale physical provenance. Add a test proving each
field is rejected on an absent artifact in the incomplete scenario
and on the access-denied artifact, the class that blocked sibling
lanes #324 and #352.

Refs #323
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request parser Log parser related sccm SCCM/ConfigMgr related test Testing related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants