Skip to content

refactor(payload): annotate intentional-panic .expect() sites#1891

Draft
goxberry wants to merge 1 commit into
goxberry/expect-cleanup-payload-local-invariantsfrom
goxberry/expect-cleanup-payload-handle-contracts
Draft

refactor(payload): annotate intentional-panic .expect() sites#1891
goxberry wants to merge 1 commit into
goxberry/expect-cleanup-payload-local-invariantsfrom
goxberry/expect-cleanup-payload-handle-contracts

Conversation

@goxberry
Copy link
Copy Markdown
Contributor

@goxberry goxberry commented May 22, 2026

What does this PR do?

Annotates 11 functions in lading_payload that contain intentional-panic .expect() calls with #[expect(clippy::expect_used, reason = "...")]. The .expect() calls themselves are unchanged — they document a contract and panicking is the intended response.

Annotated functions and the contract each preserves

Function Why the panic is intentional
block::Cache::read_at Doc comment already declares: "Function will panic if reads are larger than machine word bytes wide." The internal usize::try_from(u64) calls are that contract.
RandomStringPool::using_handle Handle has two variants (PosAndLength, Index); only PosAndLength is valid here. A cross-variant handle is a cross-pool misuse — a programming error.
StringListPool::using_handle Symmetric: only Index is valid here.
Display::fmt for Event (dogstatsd/event.rs), ServiceCheck (dogstatsd/service_check.rs), Count, Gauge, Timer, Dist, Set, Histogram (all in dogstatsd/metric.rs) Tag keys/values are stored as opaque handles into self.pools.tag_name / self.pools.tag_value. The handles were issued by those exact pools at the metric/event/service-check construction site, so the lookup cannot fail unless an internal invariant has been violated.

Why #[expect] and not unreachable!() or panic!()

For these sites the .expect() message is the contract, and the panic is the intended behavior. Converting to unreachable!() would lose the documented contract text; converting to panic!("...") would just sidestep the lint while saying the same thing more loudly. #[expect(clippy::expect_used, reason = "...")] keeps the code untouched and records, at the source, why the lint allows it. If a future change makes the lint stop firing inside the function (e.g., all .expect() calls get removed), #[expect] itself warns and the annotation can be deleted.

The reason strings are tight per-site descriptions; they're not boilerplate.

Motivation

Fifth per-crate cleanup PR in the stack started by #1882. Remaining sub-stack:

  • Group D (next): real bug fix at block.rs:123 — the arbitrary::Arbitrary impl for Block calls NonZeroU32::new(total_bytes).expect(...) where total_bytes = u32::arbitrary(u)? can legitimately be 0. Fix: convert to arbitrary::Error::IncorrectFormat so the fuzzer rejects zero-byte inputs.
  • Final: Cat-2 (function-signature changes) for ~33 remaining sites + drop the lading_payload quarantine.

Related issues

Stacked on #1890.

Additional Notes

  • cargo build --all-targets --all-features
  • cargo clippy --all-targets --all-features
  • cargo test -p lading-payload --lib ✓ (244 passed)
  • Diff: 7 files, +52 −0 (only attribute additions).

Copy link
Copy Markdown
Contributor Author

goxberry commented May 22, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@datadog-prod-us1-5

This comment has been minimized.

Eleven functions in `lading_payload` contain `.expect()` calls that are
the function's documented contract: violating the precondition is a
programming error, and panicking is the intended response. Each such
function gets `#[expect(clippy::expect_used, reason = "...")]` so the
workspace-level lint is bypassed at the source with an explicit reason.

Covered functions and the invariant each preserves:

- `block::Cache::read_at` — documents in its doc comment that it panics
  if reads exceed machine-word bytes; the `usize::try_from(u64)` calls
  inside are the documented contract.
- `RandomStringPool::using_handle` and `StringListPool::using_handle` —
  the `Handle` enum has two variants, one per pool; a handle of the
  wrong variant is a programming error (cross-pool misuse).
- `Display::fmt` impls for `Event` (in `dogstatsd/event.rs`),
  `ServiceCheck` (in `dogstatsd/service_check.rs`), and `Count`, `Gauge`,
  `Timer`, `Dist`, `Set`, `Histogram` (all in `dogstatsd/metric.rs`) —
  each formats tag keys/values by handle-table lookup against
  `self.pools`, which issued those handles at construction time; a miss
  indicates an internal invariant violation.

The `.expect()` calls themselves are unchanged. No runtime behavior
change. Same stack as #1882#1890.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants