Skip to content

feat(sdk): declared-reuse ordering, strict provenance mode, evidence policy (AIC-1503, AIC-1219)#1374

Open
Arsene12358 wants to merge 14 commits into
yimingl/aic-1502-provenance-reusefrom
yimingl/aic-1503-ordering-evidence
Open

feat(sdk): declared-reuse ordering, strict provenance mode, evidence policy (AIC-1503, AIC-1219)#1374
Arsene12358 wants to merge 14 commits into
yimingl/aic-1502-provenance-reusefrom
yimingl/aic-1503-ordering-evidence

Conversation

@Arsene12358

@Arsene12358 Arsene12358 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

PR 4 of 4 — the final PR of the Collector V3: op-centric collector management project (Linear: AIC-1503 + AIC-1219), implementing design §6 ordering, §7 strict mode + diagnostics, and §9 evidence policy. Stacked on #1372; merge order #1370#1371#1372 → this.

What this does

  • The §6 reuse-ordering flip (_build_op_sources): sources per op are now primary → reuse.yaml-declared donors (any direction, file order, deduped) → same-backend nearest-earlier siblings (newer-than-requested is never admitted implicitly) → cross-backend kernel-gated fill (unchanged mechanism). The comm family is hard-excluded from all reuse regardless of declarations (rule 5 — a deliberate tightening for custom_allreduce/trtllm_alltoall/wideep_deepep_*). Each admitted source is channel-tagged and exposed as PerfDatabase.data_provenance.
  • Strict provenance mode: strict_provenance param / AIC_STRICT_PROVENANCE env (ON in CI, off for users this release). At load time, fail-closed on missing/uncovered/malformed sidecars for the requested version's dirs and declared donors; provenance: legacy warns (one-release grace); non-strict warns and degrades gracefully (including query-time resilience to malformed declarations). The database cache is keyed by the strict bool, so strict calls are deterministic.
  • Evidence policy (AIC-1219): collector/evidence_policy.yaml (thresholds; a full-fleet authored system_generations map — SM103 Ultra folded into blackwell as a policy decision — with one evidence representative per generation) + tools/perf_database/evidence_check.py, the pure deterministic resolver from the changed-ops manifest to required evidence, filtered to the SM generations the change actually touches (unmapped systems fail closed; combined reasons emit the union — evidence can't be dodged by bundling). Exception waivers (evidence_exceptions.yaml, approver + expiry) are applied by the AIC-1214 gate, not the resolver — expiry needs a clock, which would break resolver purity.

Disclosures for reviewers

  1. Strict-mode scope, two deliberate narrowings vs a literal §7.4 reading: (a) validation covers the requested version's primary dirs + declared donors — not fallback/cross-backend sibling dirs; (b) legacy-layout dirs (transition-window only; none exist in-tree) are exempt rather than raising as "table without family". Rationale for both: design §8 names the CI audit as the primary gate (it sweeps the whole tree on every data PR — all six rules green on this branch); strict mode is the per-request backstop for exactly the sources a load admits.
  2. Prediction-gate evidence, stated precisely: the ordering flip was adjudicated on tier-2 (16 curated configs) + silicon anchors (35 points): 2 divergences, both intended §6.2 behavior (undeclared forward-fill removed for historical versions), zero comm or kernel-filter surprises. Full-grid tier-1 enumeration did not run locally — tier-1 was broken by a pre-existing family-layout gap (fixed on this stack, see refactor(sdk): family-first perf-data layout with dual-read transition (AIC-1501) #1371/feat(collector): committed provenance, authored reuse, changed-op manifest, fail-closed audit (AIC-1502) #1372 comments) — so this PR's own required "AIC Prediction Regression Gate" CI run is the authoritative full-grid old-vs-new comparison; merge is contingent on it passing.
  3. For AIC-1087 consumers of data_provenance: entries mean admitted sources, not rows actually used (first-wins merge decides usage); keys are op-file basenames (gemm_perf.parquet) — two tables sharing one file share one entry; entries exist for every op the engine touches, including ops a given model never queries.
  4. l40s reuse declarations: the 12 files / 17 self-overlap entries flagged in feat(collector): committed provenance, authored reuse, changed-op manifest, fail-closed audit (AIC-1502) #1372 now carry rewritten reason fields disclosing they are mechanical migrations (missing-shape forward-fill only, not kernel-identity-reviewed). Under the new ordering they are consumed as declared donors after primary — behavior-preserving vs the legacy newest-first semantics.

Test plan

uv run pytest tests/unit -m unit -n 2 green, and again with AIC_STRICT_PROVENANCE=1 (identical results) · ordering suite (15), strict suite (32+), evidence resolver (30+) all new · real-tree audit 6/6 OK · discovery parity 10 systems / 89 pairs unchanged · gate tier-2 + silicon adjudicated with root-cause traces via data_provenance · every fix wave re-reviewed.

Closes the Collector V3 implementation: with this merged, a quarterly pin bump computes its own work list (changed_ops), the evidence resolver prices it, the audit + strict mode keep every byte provenanced, and collector-snapshot-2026-08 tags the first reproducible quarter.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added optional strict provenance validation for performance data loading, with clear failures for missing, malformed, or incomplete provenance metadata.
    • Added an evidence-checking tool that validates change manifests and produces deterministic evidence requirements and reports.
    • Added policy-based coverage for version updates, collector changes, and new test cases.
  • Documentation

    • Clarified data-source provenance, reuse channels, evidence rules, and fail-closed validation behavior.
  • Refactor

    • Improved performance data source ordering and provenance visibility across reuse and fallback paths.

@Arsene12358 Arsene12358 requested review from a team as code owners July 16, 2026 04:38
@copy-pr-bot

copy-pr-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b5c88226-b9e5-4b6f-928f-5a3f920d4d5a

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

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

@Arsene12358

Copy link
Copy Markdown
Contributor Author

Merge protocol (stacked PR): merge order #1370#1371#1372 → this. Please do not merge until #1372 has merged and GitHub auto-retargets this PR to main; I rebase the branch after each upstream squash-merge (reviewed diff unaffected).

@Arsene12358 Arsene12358 changed the title feat(sdk,collector,tools): §6 reuse ordering, strict provenance mode, evidence policy (AIC-1503, AIC-1219) feat(sdk): declared-reuse ordering, strict provenance mode, evidence policy (AIC-1503, AIC-1219) Jul 16, 2026
@github-actions github-actions Bot added the feat label Jul 16, 2026
@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1502-provenance-reuse branch from 2b73e49 to cf0dc28 Compare July 16, 2026 06:17
@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1503-ordering-evidence branch from 10d12b1 to d2bde0a Compare July 16, 2026 06:17
@Arsene12358

Copy link
Copy Markdown
Contributor Author

CI fixes pushed (head d2bde0a5, rebased onto the updated #1372 branch — cascade per the stack protocol; no functional changes to this PR's own commits):

@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1502-provenance-reuse branch from cf0dc28 to b0eb31f Compare July 16, 2026 06:31
@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1503-ordering-evidence branch from d2bde0a to 24a6de5 Compare July 16, 2026 06:31
@Arsene12358

Copy link
Copy Markdown
Contributor Author

Round 2 (head 24a6de56, cascade rebase onto #1372): unit-job fix inherited from #1371 (git installed in the test Docker stage — test_changed_ops.py/test_migrate_markers.py need a git binary). No changes to this PR's own commits.

@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1503-ordering-evidence branch from 24a6de5 to 6562580 Compare July 16, 2026 06:39
@Arsene12358

Copy link
Copy Markdown
Contributor Author

Round 3 (head 6562580c, cascade rebase onto #1372): inherits the real-repo smoke-test gate from #1372. No changes to this PR's own commits.

@Arsene12358

Copy link
Copy Markdown
Contributor Author

Round 4 (head 6b818a7d): this PR's own test_evidence_check.py had the same real-repo smoke test as changed_ops (compute_changed_ops(REPO_ROOT, HEAD, HEAD) → exit 128 in the git-less /workspace COPY). Gated identically on the git-worktree probe; the fixture-based resolver tests are unaffected (32 passed locally). I swept the whole test tree on this branch — this was the last real-repo dependency.

@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1502-provenance-reuse branch from 18e70d2 to d641c8e Compare July 16, 2026 08:28
@Arsene12358 Arsene12358 requested a review from a team as a code owner July 16, 2026 08:28
@Arsene12358 Arsene12358 requested review from AichenF and atrifex and removed request for a team July 16, 2026 08:28
@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1503-ordering-evidence branch from 6b818a7 to 42ad681 Compare July 16, 2026 08:29

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
tests/unit/sdk/database/test_database_helpers.py (1)

595-598: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise both strictness cache variants.

These tests update the tuple shape but only seed strict_provenance=False. Add (..., True) entries so clearing and unloading are verified across the new cache dimension.

Proposed test additions
         perf_database.databases_cache[("root", "system", False, False)]["backend"]["1.0.0"] = clear_db
+        perf_database.databases_cache[("root", "system", False, True)]["backend"]["1.0.0"] = clear_db
         perf_database.databases_cache[("root", "system", True, False)]["backend"]["1.0.0"] = clear_db
     keep_db = FakeDatabase()
     unload_db = FakeDatabase()
+    strict_unload_db = FakeDatabase()
@@
         perf_database.databases_cache[("root", "system", False, False)]["backend"]["1.0.0"] = unload_db
+        perf_database.databases_cache[("root", "system", False, True)]["backend"]["1.0.0"] = strict_unload_db
@@
         assert unload_db.clear_count == 1
+        assert strict_unload_db.clear_count == 1
+        assert ("root", "system", False, True) not in perf_database.databases_cache

As per path instructions, tests must “cover the changed behavior rather than only the happy path.”

Also applies to: 622-630

🤖 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 `@tests/unit/sdk/database/test_database_helpers.py` around lines 595 - 598, The
test cache setup around the performance database cases only seeds
strict_provenance=False entries. Add corresponding entries with
strict_provenance=True for the clear_db and keep_db scenarios, including the
related setup around the other referenced test section, so clearing and
unloading are exercised for both strictness variants.

Source: Path instructions

🤖 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 `@aic-core/src/aiconfigurator_core/sdk/perf_database.py`:
- Around line 687-693: Update _version_dir_data_filenames and its callers to
preserve os.listdir failures instead of treating them as an empty file list:
raise the inspection error when strict mode is enabled, and emit a warning while
continuing only in non-strict mode. Ensure the behavior also covers the related
handling at the indicated caller path.
- Line 1226: The cache update must not place an unvalidated worker-created
database under a strict-provenance key. In the worker-loading flow that assigns
`databases_cache[(systems_root, system, shared_flag,
database.strict_provenance)][backend][version]`, validate the database reference
before insertion, preserving unvalidated direct-construction behavior elsewhere.
Add a regression test covering a subsequent `get_database(...,
strict_provenance=True)` cache hit and confirming request validation still
occurs.

In `@tests/unit/sdk/test_perf_database_shared_layer.py`:
- Around line 389-390: Move the lazy database build, _gemm_lookup assertion, and
fallback warning assertions into the caplog.at_level(logging.WARNING,
logger="aiconfigurator.sdk.perf_database") block in the relevant test. Ensure
GEMM.load_data(db) executes while warning capture is active and retain the
expectation that exactly one low-fidelity fallback warning is recorded.

In `@tools/perf_database/evidence_check.py`:
- Around line 295-305: Validate touched generations before branching on reason
in the evidence-check flow: update tools/perf_database/evidence_check.py lines
295-305 so _touched_generations and unmapped-system validation run for case_plan
entries, while representative selection remains skipped only for case_plan.
Parameterize the unmapped-system regression in
tests/unit/tools/test_evidence_check.py lines 232-239 across all three reasons.
- Around line 140-151: Update the policy-loading validation around the resolved
mapping to reject any system name assigned to more than one generation. Track
systems seen while iterating raw_system_generations, raise EvidencePolicyError
identifying the conflicting system and generations, and only add entries to
resolved when ownership is unique.
- Around line 97-100: Update the thresholds.parquet_diff_median_pct validation
in the evidence policy parsing flow to reject negative values and non-finite
numbers such as NaN and infinity, while continuing to accept finite,
non-negative numeric values and reject booleans. Use the existing threshold
validation branch and an appropriate numeric-finiteness check.
- Around line 235-260: Update _parse_changed_entry to validate that every item
in tables and systems is a string, rejecting malformed entries such as [{}] and
[[]] with EvidenceManifestError before constructing ChangedEntry. Add
corresponding malformed-manifest cases to TestMalformedManifest in
tests/unit/tools/test_evidence_check.py.

---

Nitpick comments:
In `@tests/unit/sdk/database/test_database_helpers.py`:
- Around line 595-598: The test cache setup around the performance database
cases only seeds strict_provenance=False entries. Add corresponding entries with
strict_provenance=True for the clear_db and keep_db scenarios, including the
related setup around the other referenced test section, so clearing and
unloading are exercised for both strictness variants.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c1344228-7c0d-4e58-9394-ad6956bed3d1

📥 Commits

Reviewing files that changed from the base of the PR and between d641c8e and 42ad681.

📒 Files selected for processing (23)
  • .github/workflows/build-test.yml
  • aic-core/src/aiconfigurator_core/sdk/perf_database.py
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/mla/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/mla_bmm/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/quantize/trtllm/1.3.0rc15/reuse.yaml
  • collector/evidence_policy.yaml
  • docs/perf_database/collector-v3-op-centric-design.md
  • tests/unit/sdk/database/test_data_loaders.py
  • tests/unit/sdk/database/test_database_helpers.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • tests/unit/sdk/database/test_strict_mode.py
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tests/unit/tools/test_evidence_check.py
  • tools/perf_database/evidence_check.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (12)
**/*

📄 CodeRabbit inference engine (.claude/rules/repo-guide.md)

**/*: Treat this file as the only always-injected rule file; do not add new always-on rules here without human approval. New rule files must include paths: frontmatter.
When reviewing changes in a governed area, read that area's rule files first, even if path-based auto-loading does not occur during a read-only review. Rule violations are review findings even when the code works.
A task must remain within its module: collector tasks may change only collector/ and its tests, generator tasks only src/aiconfigurator/generator/ and its tests, and SDK tasks must not modify either. Cross-module contract changes require explicit human approval.

Files:

  • aic-core/src/aiconfigurator_core/systems/data/l40s/mla_bmm/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/quantize/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/vllm/0.22.0/reuse.yaml
  • collector/evidence_policy.yaml
  • tests/unit/sdk/database/test_database_helpers.py
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/trtllm/1.3.0rc15/reuse.yaml
  • tests/unit/sdk/database/test_data_loaders.py
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/mla/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/sglang/0.5.12/reuse.yaml
  • docs/perf_database/collector-v3-op-centric-design.md
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tools/perf_database/evidence_check.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • aic-core/src/aiconfigurator_core/sdk/perf_database.py
  • tests/unit/tools/test_evidence_check.py
  • tests/unit/sdk/database/test_strict_mode.py

⚙️ CodeRabbit configuration file

**/*: - Prefer applicable inline comments. When the correct fix is clear, small, and limited to the commented diff hunk, include it as a GitHub Suggested Change so the author can apply it with one click.

  • Do not use a suggested change when the fix requires broader design choices, multiple files, generated artifacts, unavailable context, or validation that cannot be inferred from the diff.
  • If a comment is not directly applicable, state the smallest concrete next step and why a one-click suggestion is not safe.

Files:

  • aic-core/src/aiconfigurator_core/systems/data/l40s/mla_bmm/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/moe/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/quantize/trtllm/1.3.0rc15/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/vllm/0.22.0/reuse.yaml
  • collector/evidence_policy.yaml
  • tests/unit/sdk/database/test_database_helpers.py
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/trtllm/1.3.0rc15/reuse.yaml
  • tests/unit/sdk/database/test_data_loaders.py
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/vllm/0.22.0/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/mla/sglang/0.5.12/reuse.yaml
  • aic-core/src/aiconfigurator_core/systems/data/l40s/attention/sglang/0.5.12/reuse.yaml
  • docs/perf_database/collector-v3-op-centric-design.md
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tools/perf_database/evidence_check.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • aic-core/src/aiconfigurator_core/sdk/perf_database.py
  • tests/unit/tools/test_evidence_check.py
  • tests/unit/sdk/database/test_strict_mode.py
{collector/**,tests/unit/collector/**}

📄 CodeRabbit inference engine (.claude/rules/collector/failure_handling.md)

{collector/**,tests/unit/collector/**}: In collector failure handling, observe failures rather than predict them: do not use a declarative expected-failure layer or automatic skips; failing groups must be fixed.
Record every worker failure automatically in the relevant error and collection-summary JSON files with classification, case parameters, exception details, and model/dtype grouping.
Reset a worker after CUDA-fatal errors only after recording the failed task.
Treat missing data points as tolerable downstream because the SDK can interpolate, extrapolate, reuse sibling-version rows, or use HYBRID empirical estimates.
For a hanging case or one that kills the node, add a dated denylist.yaml entry with a reason.
For an entirely unvalidated operation/backend pair, mark the registry OpEntry as unverified=true.
For cases not validated on a specific SM, mark the registry OpEntry with unverified_sms=(sm,).
Represent physically impossible hardware capabilities with a positive floor in capabilities.yaml; do not use it for framework-version kernel gaps.
Treat out-of-memory failures as unclassified until reproduced on a clean GPU; only a genuine OOM may be excluded by the sanctioned generation-time memory filter.
Fix proven collector-code bugs in code rather than using skips, and re-check dispatch and skip rules.
Do not encode framework-version gaps in YAML; allow them to fail and be re-tested after version changes.
Treat isolated, explained, unclustered failures as acceptable; investigate around 10% unexpected failures or sooner when failures cluster.
Treat roughly one-third failing cases or an entire failing family as a systemic collector problem; stop collection and fix the collector.
Never hide failures with broad skips, retries, generic OOM labels, reduced coverage, synthetic rows, or weakened benchmarks.
Compare failure records with the previous run for the same backend and version; prioritize only new failure groups.
Do not mechanically translate failure records in...

Files:

  • collector/evidence_policy.yaml
collector/**

📄 CodeRabbit inference engine (.claude/rules/generator/cross_module_impact.md)

Review the collector when generated configuration formats change or when generator parameter names used in benchmark configurations change.

collector/**: Keep collector-layer rules in their permitted locations: base operation YAML for sweep parameters and cited quant-mode SM limits; model case YAML for structural shapes and policies; capabilities YAML for positive hardware dtype/op minimum-SM floors; backend registries for version routes and unverified markers; collectors for dispatch, classified runtime errors, and memory-feasibility generation filters; and the denylist only for hangs or node-killing cases.
Do not silently skip queued cases in collector code. A queued case must be executed or produce a classified exception; only generation-time capability floors, registry unverified markers, and the hang denylist may prevent execution.
Use framework-selected kernel/backend dispatch for measurements. Prefer the framework builder or selector; manually pin a backend only with a pinned-version file-and-line source citation; record the actually invoked kernel in kernel_source; and re-verify pins and FIXME(kernel-limit) notes on framework version bumps.
Do not invent backend fallbacks or swap backends in exception handlers. If the framework-selected path cannot be constructed or invoked, raise a classified error. Replicate fallback chains only when the framework itself uses them, and record the actual path.
The only sanctioned in-collector filter is memory feasibility: perform it only during generation inside get_*_test_cases(), use size-versus-capacity arithmetic based on live device memory or an approved capacity fallback, never use framework-version or model-name predicates, and log dropped counts in the required format.
Keep framework kernel limits as FIXME(kernel-limit) comments at the owning collector invocation site, including the claimed limit, origin, and unverified status. Do not encode unverified limits in YAML; affected cases should fail at runtime...

Files:

  • collector/evidence_policy.yaml

⚙️ CodeRabbit configuration file

collector/**: - Enforce the collector rules from .claude/rules/collector/layer_permissions.md, failure_handling.md, and case_authoring.md.

  • Flag any silent case skip in collector code (a queued case may only execute or raise); the sole sanctioned filter is generation-time memory feasibility with counted drops.
  • Flag invented fallbacks on both ends: generation must raise on unresolvable declarations (never substitute defaults or another model's geometry); collectors must never swap in a different backend/kernel than the framework's own dispatch selects — manual pins require framework source citations.
  • Flag any reintroduction of selector/exception machinery (case_ids/contains/indices/ranges/limit/rules, sm_exceptions-style shape or version predicates) in YAML or code.
  • Capability floors (cases/capabilities.yaml) may hold hardware facts only: no shapes, no framework versions, no per-backend nesting. cases/denylist.yaml is for hang/node-killers only, dated.
  • Collector changes must stay within collector/ and tests/unit/collector/; flag producer+consumer contract changes (perf row schema, PerfFile names) unless the PR explicitly declares them.
  • Check collector changes for backend/runtime version accuracy, GPU resource assumptions, reproducible command construction, and clear failure evidence.
  • Flag changes that make support-matrix or perf-data results harder to trace back to the command, model, system, quantization, or runtime version that produced them.

Files:

  • collector/evidence_policy.yaml
collector/**/*

📄 CodeRabbit inference engine (.claude/rules/repo-guide.md)

Changes under collector/ must follow .claude/rules/collector/layer_permissions.md and failure_handling.md; case YAML work must also follow case_authoring.md. Do not apply generator rules to collector/case_generator.py.

Files:

  • collector/evidence_policy.yaml
collector/**/*.{yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Before modifying case YAML files under collector/**, read .claude/rules/collector/case_authoring.md.

Files:

  • collector/evidence_policy.yaml
.github/workflows/**

⚙️ CodeRabbit configuration file

.github/workflows/**: - Review workflow edits for least-privilege permissions, safe trigger scopes, secret exposure, fork behavior, and release/cherry-pick side effects.

  • Verify matrix jobs, artifact uploads, and scheduled support-matrix workflows still produce debuggable evidence.

Files:

  • .github/workflows/build-test.yml
tests/**/*.{py,yaml,txt,sh}

📄 CodeRabbit inference engine (.claude/rules/generator/testing.md)

Use integration tests for the full input-to-artifacts pipeline, comparing output against golden snapshots without external dependencies.

Files:

  • tests/unit/sdk/database/test_database_helpers.py
  • tests/unit/sdk/database/test_data_loaders.py
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • tests/unit/tools/test_evidence_check.py
  • tests/unit/sdk/database/test_strict_mode.py
**/*.{py,pyi}

📄 CodeRabbit inference engine (AGENTS.md)

Run ruff check . and ruff format --check . to validate Python linting and formatting.

Files:

  • tests/unit/sdk/database/test_database_helpers.py
  • tests/unit/sdk/database/test_data_loaders.py
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tools/perf_database/evidence_check.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • aic-core/src/aiconfigurator_core/sdk/perf_database.py
  • tests/unit/tools/test_evidence_check.py
  • tests/unit/sdk/database/test_strict_mode.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Run unit tests with pytest -m unit; use pytest -m "unit or build" for the build-test subset when required data is available.

Files:

  • tests/unit/sdk/database/test_database_helpers.py
  • tests/unit/sdk/database/test_data_loaders.py
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • tests/unit/tools/test_evidence_check.py
  • tests/unit/sdk/database/test_strict_mode.py
tests/**

⚙️ CodeRabbit configuration file

tests/**: - Check that tests cover the changed behavior rather than only the happy path.

  • Watch for fixtures or golden outputs that mask backend drift, support-matrix ordering changes, or CLI output regressions.

Files:

  • tests/unit/sdk/database/test_database_helpers.py
  • tests/unit/sdk/database/test_data_loaders.py
  • tests/unit/sdk/test_perf_database_shared_layer.py
  • tests/unit/sdk/database/test_reuse_ordering.py
  • tests/unit/tools/test_evidence_check.py
  • tests/unit/sdk/database/test_strict_mode.py
docs/**

⚙️ CodeRabbit configuration file

docs/**: - Check that docs match changed CLI, SDK, generator, backend, and support-matrix behavior.

  • Flag docs that describe unsupported runtimes, stale command names, or behavior not covered by tests or support-matrix evidence.

Files:

  • docs/perf_database/collector-v3-op-centric-design.md
aic-core/src/aiconfigurator_core/sdk/**

⚙️ CodeRabbit configuration file

aic-core/src/aiconfigurator_core/sdk/**: - Verify core SDK API changes remain compatible with legacy aiconfigurator.sdk imports, generator inputs, profiler data flow, and documented examples.

  • Flag upper-layer dependencies or silent schema drift introduced into the minimal core distribution.

Files:

  • aic-core/src/aiconfigurator_core/sdk/perf_database.py
🪛 ast-grep (0.44.1)
tests/unit/tools/test_evidence_check.py

[error] 479-485: Command coming from incoming request
Context: subprocess.run(
["git", "rev-parse", "--is-inside-work-tree"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
check=False,
)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🔇 Additional comments (26)
collector/evidence_policy.yaml (2)

14-79: LGTM!


4-12: 📐 Maintainability & Code Quality

No module-boundary issue here. collector/evidence_policy.yaml is a shared policy consumed by tools/perf_database/evidence_check.py, and the tests belong with that tool under tests/unit/tools/; nothing needs to move into collector/.

			> Likely an incorrect or invalid review comment.
tools/perf_database/evidence_check.py (1)

32-96: LGTM!

Also applies to: 102-128, 154-224, 264-286, 307-393

tests/unit/tools/test_evidence_check.py (1)

23-224: LGTM!

Also applies to: 242-412, 425-505

aic-core/src/aiconfigurator_core/sdk/perf_database.py (1)

650-686: LGTM!

Also applies to: 694-722, 726-839, 848-848, 873-879, 896-907, 918-928, 940-941, 974-975, 1051-1051, 1064-1065, 1075-1075, 1239-1239, 1272-1272, 1803-1911, 1964-1964, 1981-1994, 2010-2017, 2181-2308, 2326-2326, 2347-2354, 2363-2363

aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/vllm/0.22.0/reuse.yaml (1)

8-8: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/mla/sglang/0.5.12/reuse.yaml (1)

8-12: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/mla_bmm/sglang/0.5.12/reuse.yaml (1)

8-8: LGTM!

tests/unit/sdk/database/test_data_loaders.py (1)

58-58: LGTM!

docs/perf_database/collector-v3-op-centric-design.md (1)

328-333: LGTM!

Also applies to: 344-347, 415-424

aic-core/src/aiconfigurator_core/systems/data/l40s/attention/sglang/0.5.12/reuse.yaml (1)

8-12: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/moe/sglang/0.5.12/reuse.yaml (1)

8-8: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/moe/trtllm/1.3.0rc15/reuse.yaml (1)

8-8: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/moe/vllm/0.22.0/reuse.yaml (1)

8-8: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/quantize/trtllm/1.3.0rc15/reuse.yaml (1)

8-12: LGTM!

tests/unit/sdk/test_perf_database_shared_layer.py (2)

389-390: 🩺 Stability & Availability

No issue here — _write_gemm_csv creates path.parent before writing, so the new vllm/0.5 CSV is created safely.

			> Likely an incorrect or invalid review comment.

372-390: 📐 Maintainability & Code Quality

Run pytest -m unit in an environment with pytest installed.

aic-core/src/aiconfigurator_core/systems/data/l40s/attention/trtllm/1.3.0rc15/reuse.yaml (1)

8-12: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/attention/vllm/0.22.0/reuse.yaml (1)

8-12: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/sglang/0.5.12/reuse.yaml (1)

8-8: LGTM!

aic-core/src/aiconfigurator_core/systems/data/l40s/gemm/trtllm/1.3.0rc15/reuse.yaml (1)

8-8: LGTM!

tests/unit/sdk/database/test_reuse_ordering.py (2)

1-33: LGTM!

Also applies to: 35-489


34-34: 📐 Maintainability & Code Quality

Run the unit tests for both changed modules.
tests/unit/sdk/database/test_reuse_ordering.py and tests/unit/sdk/database/test_strict_mode.py still need to be exercised with pytest -m unit.

.github/workflows/build-test.yml (1)

98-100: LGTM!

tests/unit/sdk/database/test_strict_mode.py (2)

1-142: LGTM!

Also applies to: 159-600


143-157: 🗄️ Data Integrity & Integration

No issue: PerfDatabase construction intentionally skips provenance checks.

			> Likely an incorrect or invalid review comment.

Comment thread aic-core/src/aiconfigurator_core/sdk/perf_database.py
Comment thread aic-core/src/aiconfigurator_core/sdk/perf_database.py
Comment thread tests/unit/sdk/test_perf_database_shared_layer.py
Comment thread tools/perf_database/evidence_check.py Outdated
Comment on lines +97 to +100
thresholds = raw.get("thresholds")
threshold_value = thresholds.get("parquet_diff_median_pct") if isinstance(thresholds, dict) else None
if not isinstance(threshold_value, (int, float)) or isinstance(threshold_value, bool):
raise EvidencePolicyError(f"evidence policy 'thresholds.parquet_diff_median_pct' must be a number: {path}")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject negative and non-finite thresholds.

-1, NaN, and infinity currently pass validation. In particular, NaN can prevent the documented escalation comparison from ever succeeding.

Proposed fix
 import argparse
+import math
 import sys
-    if not isinstance(threshold_value, (int, float)) or isinstance(threshold_value, bool):
-        raise EvidencePolicyError(f"evidence policy 'thresholds.parquet_diff_median_pct' must be a number: {path}")
+    if (
+        not isinstance(threshold_value, (int, float))
+        or isinstance(threshold_value, bool)
+        or not math.isfinite(threshold_value)
+        or threshold_value < 0
+    ):
+        raise EvidencePolicyError(
+            f"evidence policy 'thresholds.parquet_diff_median_pct' must be a finite non-negative number: {path}"
+        )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
thresholds = raw.get("thresholds")
threshold_value = thresholds.get("parquet_diff_median_pct") if isinstance(thresholds, dict) else None
if not isinstance(threshold_value, (int, float)) or isinstance(threshold_value, bool):
raise EvidencePolicyError(f"evidence policy 'thresholds.parquet_diff_median_pct' must be a number: {path}")
thresholds = raw.get("thresholds")
threshold_value = thresholds.get("parquet_diff_median_pct") if isinstance(thresholds, dict) else None
if (
not isinstance(threshold_value, (int, float))
or isinstance(threshold_value, bool)
or not math.isfinite(threshold_value)
or threshold_value < 0
):
raise EvidencePolicyError(
f"evidence policy 'thresholds.parquet_diff_median_pct' must be a finite non-negative number: {path}"
)
🤖 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 `@tools/perf_database/evidence_check.py` around lines 97 - 100, Update the
thresholds.parquet_diff_median_pct validation in the evidence policy parsing
flow to reject negative values and non-finite numbers such as NaN and infinity,
while continuing to accept finite, non-negative numeric values and reject
booleans. Use the existing threshold validation branch and an appropriate
numeric-finiteness check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in a1f9fd6: policy load now fails closed (EvidencePolicyError) unless the threshold is finite and non-negative — -1, NaN, and inf each have a red-verified regression test.

Comment thread tools/perf_database/evidence_check.py
Comment thread tools/perf_database/evidence_check.py
Comment on lines +295 to +305
if reason == "case_plan":
evidence_systems: tuple[str, ...] = ()
else:
touched = _touched_generations(entry, policy)
missing = touched - policy.evidence_systems.keys()
if missing:
raise EvidencePolicyError(
f"changed_ops entry ({entry.framework}/{entry.family}) touches SM generation(s) "
f"{sorted(missing)} with no representative in evidence policy 'evidence_systems'"
)
evidence_systems = tuple(sorted(policy.evidence_systems[generation] for generation in touched))

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Validate system mappings for case_plan entries too.

case_plan returns before _touched_generations, so an unmapped system produces a successful report despite the documented fail-closed contract.

  • tools/perf_database/evidence_check.py#L295-L305: call _touched_generations before branching; only representative selection should be skipped for case_plan.
  • tests/unit/tools/test_evidence_check.py#L232-L239: parameterize the unmapped-system regression across all three reasons.
+    touched = _touched_generations(entry, policy)
     if reason == "case_plan":
         evidence_systems: tuple[str, ...] = ()
     else:
-        touched = _touched_generations(entry, policy)
         missing = touched - policy.evidence_systems.keys()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if reason == "case_plan":
evidence_systems: tuple[str, ...] = ()
else:
touched = _touched_generations(entry, policy)
missing = touched - policy.evidence_systems.keys()
if missing:
raise EvidencePolicyError(
f"changed_ops entry ({entry.framework}/{entry.family}) touches SM generation(s) "
f"{sorted(missing)} with no representative in evidence policy 'evidence_systems'"
)
evidence_systems = tuple(sorted(policy.evidence_systems[generation] for generation in touched))
touched = _touched_generations(entry, policy)
if reason == "case_plan":
evidence_systems: tuple[str, ...] = ()
else:
missing = touched - policy.evidence_systems.keys()
if missing:
raise EvidencePolicyError(
f"changed_ops entry ({entry.framework}/{entry.family}) touches SM generation(s) "
f"{sorted(missing)} with no representative in evidence policy 'evidence_systems'"
)
evidence_systems = tuple(sorted(policy.evidence_systems[generation] for generation in touched))
📍 Affects 2 files
  • tools/perf_database/evidence_check.py#L295-L305 (this comment)
  • tests/unit/tools/test_evidence_check.py#L232-L239
🤖 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 `@tools/perf_database/evidence_check.py` around lines 295 - 305, Validate
touched generations before branching on reason in the evidence-check flow:
update tools/perf_database/evidence_check.py lines 295-305 so
_touched_generations and unmapped-system validation run for case_plan entries,
while representative selection remains skipped only for case_plan. Parameterize
the unmapped-system regression in tests/unit/tools/test_evidence_check.py lines
232-239 across all three reasons.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed and fixed in a1f9fd6 with exactly the hoist proposed here: _touched_generations now runs before the reason branch, so unmapped systems fail closed for all three reasons; only the representative selection stays skipped for case_plan. The unmapped-system regression test is parameterized across pin_version / collector_code / case_plan (the case_plan case verified red pre-fix — it previously produced a successful report).

Arsene12358 and others added 5 commits July 16, 2026 22:55
…r fallback, comm exclusion, source diagnostics (AIC-1503)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…yout comm exception (AIC-1503)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…cy-tier grace (AIC-1503)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…ict mode (AIC-1503)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…1503)

Widened databases_cache key from 3 to 4 elements to include strict_provenance bool.
Updated hardcoded cache keys in test_database_helpers.py and added strict_provenance
attribute to DummyPerfDatabase stub in test_data_loaders.py.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
Arsene12358 and others added 9 commits July 16, 2026 22:55
Rewrites the `reason` field on the 17 l40s reuse.yaml entries (12 files)
whose declaring dir already holds native primary data for the same table
they declare a donor for. Carried in from PR3 Task 3's mechanical
SHARED_LAYER_REUSE.txt migration (all 22 l40s reuse.yaml entries shared
one generic "migrated from ..." reason); this PR's ordering flip (design
§6) makes the self-overlap distinction load-bearing, since these
declarations now only matter for missing-shape forward-fill, not whole-
table fill, and should read as such rather than implying full-file reuse.

New reason (verbatim): "self-overlap: dir holds native data for this
table; declaration covers missing-shape forward-fill only; mechanically
derived from legacy SHARED_LAYER_REUSE.txt (newest-first effective
donor); NOT kernel-identity-reviewed"

Self-overlap detected mechanically: entry's declaring dir has its own
`<table>.parquet` file alongside reuse.yaml. The other 5 entries in the
same 22-file set (pure gap-fill: encoder_attention x2, linear_attention
x2, mhc x1, mla/trtllm x2, mla/vllm x4, quantize/sglang x2, quantize/vllm
x2 -- dirs with zero native data for the declared table) are untouched.

Classification table (file -> table(s) touched):
  attention/sglang/0.5.12    context_attention_perf, generation_attention_perf
  attention/trtllm/1.3.0rc15 context_attention_perf, generation_attention_perf
  attention/vllm/0.22.0      context_attention_perf, generation_attention_perf
  gemm/sglang/0.5.12         gemm_perf
  gemm/trtllm/1.3.0rc15      gemm_perf
  gemm/vllm/0.22.0           gemm_perf
  mla/sglang/0.5.12          context_mla_perf, generation_mla_perf
  mla_bmm/sglang/0.5.12      mla_bmm_perf
  moe/sglang/0.5.12          moe_perf
  moe/trtllm/1.3.0rc15       moe_perf
  moe/vllm/0.22.0            moe_perf
  quantize/trtllm/1.3.0rc15  computescale_perf, scale_matrix_perf

PR4 T3 prediction-regression-gate adjudication (full detail in
.superpowers/sdd/pr4-task-3-report.md, not committed): the gate has no
committed snapshot/expected-file state (pure old-vs-new, recomputed each
run per design doc §2.1) -- there is no code artifact for this task to
regenerate. Ran it for real anyway (git worktree at PR3 head 0d3375e as
"old" baseline vs this branch as "new"): tier-1 (collect_static.py /
grid.py) is 100% non-functional against the real committed tree on BOTH
revisions -- a pre-existing, unrelated bug (grid.py's directory walk still
assumes the pre-family-layout <backend>/<version> tree; the real tree has
been <family>/<backend>/<version> since PR2 Task 5, commit 98bf1d9,
before PR3). Out of this task's scope to fix; recommend a follow-up
ticket. Ran tier-2 (16 curated configs) and the silicon/accuracy layer
(35 curated anchors) directly instead: tier-2 shows zero divergences;
silicon shows 2, both category (a) undeclared-forward-fill-removal for a
historical version (design §6.2, intended) -- b200_sxm/sglang/0.5.9 moe
lookup (OK -> PerfDataNotAvailableError, verified via traceback + dir
listing) and h100_sxm/sglang/0.5.6.post2 quantize (TTFT drift, verified
via PerfDatabase.data_provenance showing zero admitted sources on the new
side for computescale_perf/scale_matrix_perf, where old newest-first
merge pulled from a newer sibling). Zero divergences traced to comm
exclusion (b) or same-backend kernel_source-filter widening (c) -- not a
BLOCKED finding.

Verification: audit_collector_data.py all 6 rules OK; get_supported_databases
10 systems / 89 versions unchanged; tests/unit/sdk + tests/unit/tools -m unit
-n 2 -> 1531 passed, 1 known pre-existing torch-collection error
(test_moe_dispatch.py, unrelated).

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…C-1219)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…tions (AIC-1219)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…ed, record generation-map policy (AIC-1503, AIC-1219)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…pe, doc alignment, resolver test gap (AIC-1503)

Signed-off-by: Yiming Liu <yimingl@nvidia.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
Same container condition as the changed_ops smoke test on the base branch:
/workspace in the CI test image is a source COPY without .git, so
compute_changed_ops(REPO_ROOT, HEAD, HEAD) exits 128 there. Gate the one
real-repo integration test on the checkout being a git worktree; the
fixture-based resolver tests are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…dirs, validate strict cache hits (AIC-1503)

Three admission/strictness gaps from CodeRabbit review of PR #1374 (one
posted on #1371 but owned by this PR's admission layer), plus a test
robustness fix:

- _build_op_sources: resolve_op_data_path skips partial FAMILY dirs but
  its legacy-layout fallback returns an existing file with no partial
  check, and the primary was then admitted unconditionally. The admission
  chokepoint now refuses an existing primary whose version dir is
  partial-for-reuse (collection_meta.yaml status: partial, or legacy
  INCOMPLETE.txt), logs a warning naming the dir, and lets channels 2-4
  fill; data_provenance keeps listing admitted sources only. This can
  only ever fire for the legacy-layout fallback path -- pinned by a
  scope-guard test.

- _version_dir_data_filenames swallowed every os.listdir failure, so
  strict coverage silently accepted an unreadable version dir. A missing
  dir stays a legitimate no-files answer; any other OSError now raises
  ValueError in strict mode and warns once in non-strict, inside
  _check_strict_provenance_coverage.

- get_database returned strict cache hits before request validation,
  handing back worker-imported instances _store_loaded_database inserts
  under a strict key without ever validating. Strict cache hits now run
  _check_strict_provenance_for_request first, memoized per (sorted
  primary paths, backend) so repeated hits stay cheap; the memo clears
  with unload_database.

- test_fallback_emits_warning: the lazy GEMM.load_data (triggered by
  _gemm_lookup) emits the low-fidelity warning, so the lookup and the
  warning assertions now run inside the caplog.at_level block.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
…us generations, malformed list items (AIC-1219)

Four fail-closed gaps in the evidence resolver, from CodeRabbit review
of PR #1374:

- thresholds.parquet_diff_median_pct accepted -1, NaN, and infinity; NaN
  in particular makes the escalation comparison never succeed. Policy
  load now requires a finite non-negative number.

- a system listed under two generations in system_generations silently
  matched BOTH owning generations in _touched_generations. Policy load
  now enforces unique ownership, naming the system and both generations.

- _parse_changed_entry accepted non-string items inside tables/systems
  lists (e.g. tables: [{}]), deferring the failure to an uncaught
  TypeError in deduplication/generation lookup. Element types are now
  validated at manifest load.

- the case_plan branch in _requirement_for returned before
  _touched_generations, so an unmapped system in a case_plan-only entry
  bypassed the documented fail-closed check. The mapping validation now
  runs for every reason; only representative selection stays skipped for
  case_plan. The unmapped-system regression test is parameterized across
  all three reasons.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Yiming Liu <yimingl@nvidia.com>
@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1502-provenance-reuse branch from d641c8e to ae56b01 Compare July 16, 2026 15:33
@Arsene12358 Arsene12358 force-pushed the yimingl/aic-1503-ordering-evidence branch from 42ad681 to a1f9fd6 Compare July 16, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant