The lint framework allows chain parsers to report data quality issues as structured diagnostics that are attested alongside display fields in the signed payload. This replaces silent data dropping with transparent, machine-readable reporting.Documentation Index
Fetch the complete documentation index at: https://anchoragedigital-shahankhatch-228-lint-diagnostics-refactor.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Architecture
Three categories of issues:| Category | Where it goes | Who handles it | Example |
|---|---|---|---|
| Display fields | SignablePayload.Fields | Wallet UI renders them | Network name, instruction details |
| Diagnostics | SignablePayload.Fields (as Diagnostic variant) | Attested — HSM/auditor can verify | OOB indices, empty account keys |
| Errors | DecodeInstructionsResult.errors | Consumer decides | No visualizer found |
The diagnostics Cargo feature
Diagnostic emission is gated behind a diagnostics Cargo feature on visualsign, visualsign-solana, and parser_cli. The default builds:
parser_clienablesdiagnostics(default-on); CLI users see the full diagnostic detail.parser_appandparser_grpc_serverdo not enable it. TheirSignablePayloadshape is stable for HSMs and wallets that derive a metadata digest from it.
decode_instructions returns Result<Vec<AnnotatedPayloadField>, VisualSignError> instead of a struct with separate diagnostic and error vectors. Empty account_keys and per-instruction visualizer errors abort the decode with Err; out-of-bounds indices flow through to the catch-all unknown_program visualizer with no diagnostic emission.
Paired *.diagnostics.expected fixtures only matter when the feature is on. The CI Makefile splits invocations to defeat Cargo feature unification: cargo {build,test,clippy} --workspace --exclude parser_cli covers the OFF path; -p parser_cli and -p visualsign-solana --features diagnostics --lib cover the ON path.
Adding a diagnostic to a chain parser
1. Import the builder
2. Accept LintConfig in your decode function
3. Check severity and emit
create_diagnostic_field automatically emits tracing::warn! for warn and error-level diagnostics, giving operators production log visibility without any extra code in chain parsers.
4. Emit ok-level diagnostics for rules that pass
Whenreport_all_rules is enabled, rules that find no issues still report:
5. Return results separately
visualsign.rs) appends diagnostics after all display fields.
Rule naming conventions
Rules follow thedomain::rule_name format:
transaction::oob_program_id— instruction’s program_id_index is out of bounds in account_keystransaction::oob_account_index— instruction references out-of-bounds account index in account_keystransaction::empty_account_keys— transaction has no account keysdecode::visualizer_error— a visualizer failed to decode an instruction (always-on, not configurable via LintConfig)
| Domain | Scope |
|---|---|
transaction | Raw transaction structure validity |
decode | Instruction data interpretation |
account | Account metadata and resolution |
wallet | Caller-provided data quality |
idl | IDL content and structure (Solana) |
abi | ABI content and structure (Ethereum) |
LintConfig
Controls diagnostic behavior:
Ok— rule ran and found no issuesWarn— data quality issue found, parsing continuedError— serious issue foundAllow— rule suppressed, no diagnostic emitted
Deterministic serialization
Diagnostic fields follow the same deterministic serialization rules as all otherSignablePayloadField variants:
- Alphabetical key ordering at every nesting level
- ASCII-only content
- Optional fields omitted when
None(e.g.,InstructionIndex)
Testing diagnostics
Updating fixtures and snapshots when adding rules
Adding a new rule that emits ok-level diagnostics changes the output of every transaction parse. You must update:-
CLI fixtures — regenerate the
*.display.expectedfixtures and the matching*.diagnostics.expectedfixtures by running the CLI against the fixture inputs:For JSON fixtures, filter diagnostics from the display expected file and update the diagnostics expected file separately. -
Integration test expected JSON — update
src/integration/tests/parser.rsto include the new diagnostic fields in theexpected_spJSON -
Field count assertions — tests that assert
payload.fields.len()(e.g., swig_wallet tests) need their counts updated to include the new ok-level diagnostics -
Fuzz and proptest — run
cargo test -p visualsign-solana --test fuzz_idl_parsingand--test pipeline_integrationto verify no regressions
make -C src fmt && make -C src lint && make -C src test to verify everything passes before pushing.