schema_version: 1
mode: sanitizer
ticket: DAILY-CONSAN-TINY
description: >
  Informational (non-gating) gfx950 ConSan run over a trivial single-kernel object
  (tiny_vecadd) with no LDS/atomic/barrier sites, driven via the source.consan_command
  path added in #347. Demonstrates the guardrail's fail-closed behavior when there is
  nothing analyzable: static analysis is complete but strict require-records fails
  closed (exit 86) rather than emitting a false pass. Rendered on the dashboard's
  Workload survey tab (Tab 2) as an observed-only case; it does NOT gate the nightly.
  DELIBERATE NEGATIVE CONTROL -- the exit 86 is the assertion, not a bug to fix.
  tiny_vecadd's only memory operations are ordinary global loads/stores, which ConSan
  reports as ordinary_memory_support=supported-synchronization-only and does not admit
  as detector sites, so it observes access=0/0 and applicable=false. Measured 2026-08-27:
  swapping the load-only consan_tiny_load for a driver that actually dispatches
  tiny_vecadd does NOT change the verdict -- the only difference is "1 auto report
  buffer(s)" instead of "0" in the require-records message. Making this row pass would
  require a kernel with admissible sites, which is what daily-consan-lds-dispatch.yaml
  already covers.

  ROCm/aorta#450 proposed flipping this case to consan_policy: lenient alongside
  daily-consan-gemm, on the grounds that both drive a load-only driver. Measured
  before acting -- first on gfx950 / ROCm 7.0.2.2, then re-measured inside the
  digest-pinned ROCm 10 CI image itself -- and it does not hold for THIS case on
  either: lenient leaves it error/error with zero findings, only relabelling the
  reason from combined_hook_exit_86 to "consan_coverage_incomplete: verdict
  applicable=false; no applicable code objects", at access=0/0.
  Removing RJ_CONSAN_REQUIRE_RECORDS cannot help,
  because the run is rejected by the coverage cross-check rather than by the record
  requirement -- an object with no admissible sites has nothing to be complete about.
  So this case stays strict, where its reason at least names the guardrail it is
  demonstrating. The expectation is now DECLARED in
  fixtures/expected/verdict_baselines.json as an expected_error naming
  combined_hook_exit_86, which is what stops the #450 vacuity sweep flagging it while
  still failing if this case ever errors for any other reason -- including the
  lenient reason above, which the declaration deliberately does not admit.
  Previously the intent lived only in this comment, where no check could read it.
sanitizer_plan:
  target: gfx950
  source:
    kind: kernel
    kernel:
      name: tiny_vecadd
      code_object: fixtures/isa/tiny.hsaco
      code_object_index: 0
    consan_command: fixtures/bin/consan_tiny_load
    consan_log: true
  scope:
    kind: kernel
  selection:
    requirement: top_dispatch_count
    top_n: 1
  sanitizers:
    - consan
  policy:
    # Deliberately strict, and deliberately NOT changed by #450 -- see the tail of
    # the description. lenient produces the same error with a vaguer reason here,
    # because tiny_vecadd has no ConSan-admissible sites at all.
    consan_policy: strict
    on_missing_backend: fail
  output:
    report: sanitizer_report.json
