Skip to content

diagnostics: add instruction::undecodable rule for graceful-fallback decode failures #363

Description

@prasanna-anchorage

Summary

Presets that follow the "graceful fallback, never Err" contract (PRS-464 decision #2) render a raw layout and return Ok when instruction bytes don't decode. That keeps production safe (a visualizer Err aborts the whole legacy tx in the non-diagnostics build), but it means the diagnostics build loses the only signal that a decode failed: since the visualizer returns Ok, the instruction no longer lands in DecodeInstructionsResult.errors.

Add a diagnostics-build rule — instruction::undecodable — so tooling/lint can still see "a known program's instruction couldn't be decoded" even though the user-facing payload degraded gracefully.

Background

  • Support TokenKeg as a known visualizer (instead of Unknown test) #81 introduced this for spl_token: malformed bytes now render an SPL Token (unparsed) raw layout (Ok) instead of DecodeError. Correct for production, but the diagnostics-build errors collection no longer records it.
  • The unresolved-account half is already covered: scan_instruction_diagnostics emits transaction::oob_account_index for v0/ALT indices. Only the malformed-data half is uncovered (the scan checks index bounds, not data validity).
  • This is a complement to the user-facing raw layout, not a replacement — see the discussion on Support TokenKeg as a known visualizer (instead of Unknown test) #81. Diagnostics are compiled out in production, so they cannot be the sole output for a decode failure.

Why it needs a framework change

Visualizers currently return a single AnnotatedPayloadField and do not receive LintConfig, and create_diagnostic_field is #[cfg(feature = "diagnostics")]. So a preset cannot emit a diagnostic today. Options to evaluate:

  1. Let a preset signal "undecodable" back to decode_instructions (e.g. an enum result or an annotation on the returned field), and have the diagnostics-build dispatch translate that into an instruction::undecodable diagnostic via the existing lint-config severity path.
  2. Detect it centrally: in the diagnostics build, compare the rendered field against a "raw fallback" marker and emit the diagnostic from decode_instructions.

Option 1 is more explicit; option 2 avoids touching the visualizer trait. Pick during design.

Acceptance

  • New instruction::undecodable rule wired into LintConfig severity handling (default Warn), emitted in the diagnostics build when a matched preset cannot decode an instruction's data.
  • Production (non-diagnostics) behavior unchanged: graceful raw layout, no Err.
  • Test: diagnostics build emits instruction::undecodable for malformed spl_token data; non-diagnostics build still renders the raw layout and does not abort.

References

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions