Skip to content

Plan 002: Stop compiling src/event_de/ into default and downstream builds #67

Description

@jskoiz

Plan 002: Stop compiling src/event_de/ into default and downstream builds

Executor instructions: Follow this plan step by step. Run every
verification command and confirm the expected result before moving to the
next step. If anything in the "STOP conditions" section occurs, stop and
report — do not improvise. When done, update the status row for this plan
in plans/README.md — unless a reviewer dispatched you and told you they
maintain the index.

Drift check (run first): git diff --stat f252b15..HEAD -- src/lib.rs src/event_de/
NOTE: this plan was written against commit f252b15 plus uncommitted
working-tree changes
that introduced the bench-internals feature. If the
"Current state" excerpts below do not match the live files, treat it as a
STOP condition.

Status

  • Priority: P2
  • Effort: M
  • Risk: LOW
  • Depends on: plans/001-ci-cover-bench-internals-feature.md
  • Category: tech-debt
  • Planned at: commit f252b15 + uncommitted changes, 2026-06-10

Why this matters

src/event_de/ is ~3,657 lines (~2,670 excluding its unit tests) of
event-backed serde deserializer that is a benchmark-only experiment. Its sole
consumer, the __unstable_event_serde module in src/lib.rs, is gated behind
the non-default bench-internals feature — but mod event_de; itself is
declared unconditionally, so every downstream user of saneyaml compiles all of
it for nothing, under a blanket #![allow(dead_code)] that also suppresses
genuine-rot warnings inside the module. For a crate that markets a minimal
trusted surface (runtime deps locked to exactly ryu + serde by CI tests),
shipping ~2.7k lines of unreachable compiled code is both a compile-time tax
and a trust-surface inconsistency. Gating the module to
cfg(any(test, feature = "bench-internals")) removes it from user builds while
keeping its 50 unit tests running in every default cargo test.

Current state

  • src/lib.rs:27-38 — module declarations; event_de is the only internal
    module without a cfg gate that has a feature-gated consumer:
    mod ast;
    mod de;
    mod emit;
    mod error;
    mod event_de;
    mod key_identity;
    #[cfg(feature = "lossless")]
    pub mod lossless;
    mod parse;
    mod schema;
    mod ser;
    mod yaml11;
  • src/lib.rs:48-87 — the only consumer of crate::event_de, already gated:
    #[cfg(feature = "bench-internals")]
    #[doc(hidden)]
    pub mod __unstable_event_serde {
        ...
        crate::event_de::from_documents_str_with_options(input, options)
        ...
        crate::event_de::document_iter_reader_with_options(reader, options)?.collect()
    }
    Verified: grep -rn "event_de" src/ | grep -v "^src/event_de" returns only
    src/lib.rs lines 31, 66, 85. No other module references it.
  • src/event_de/mod.rs:1-3 — the blanket lint suppression and stale comment:
    #![allow(dead_code)]
    // Compiled work-in-progress: this module is exercised by unit tests before it is
    // wired into public Serde entrypoints.
  • src/event_de/mod.rs:196-197 — unit tests are a cfg(test) submodule:
    #[cfg(test)]
    mod tests;
    Baseline: cargo test --locked --lib event_de50 passed; 0 failed.
  • Helpers event_de imports from other modules (merge_policy_for_schema,
    parse_scalar_with_schema, schema_for_directives in src/parse.rs;
    check_duplicate_with_tracker_at_depth_limit in src/key_identity.rs;
    utf8_error_span in src/error.rs) are all also used by parse.rs/de.rs
    themselves, so gating event_de does not orphan them. (Verified at planning
    time: e.g. parse.rs:553/580/948 call merge_policy_for_schema.)
  • CI gates that must stay green: cargo clippy --locked --all-targets -- -D warnings, scripts/check-feature-clippy.sh (which after plan 001 includes
    --features bench-internals --all-targets), cargo test --locked,
    RUSTDOCFLAGS='-D missing_docs' cargo doc --locked --no-deps, and a
    cargo public-api diff job. event_de is private and __unstable_event_serde
    is #[doc(hidden)], so neither docs nor public API should change.

Commands you will need

Purpose Command Expected on success
Tests (default) cargo test --locked exit 0
event_de unit tests cargo test --locked --lib event_de 50 passed; 0 failed
Clippy (default) cargo clippy --locked --all-targets -- -D warnings exit 0
Feature matrix scripts/check-feature-clippy.sh exit 0
Feature tests cargo test --locked --features bench-internals --lib exit 0
Docs gate RUSTDOCFLAGS='-D missing_docs' cargo doc --locked --no-deps exit 0

Scope

In scope (the only files you should modify):

  • src/lib.rs (one attribute on the mod event_de; declaration)
  • src/event_de/mod.rs (lint attribute + the stale comment at the top)

Out of scope (do NOT touch, even though they look related):

  • Deleting or refactoring anything inside src/event_de/ — the module is kept
    intentionally as the benchmark comparison path (see
    docs/EVENT_BACKED_SERDE.md); this plan only changes when it compiles.
  • src/parse.rs, src/de.rs, src/key_identity.rs, src/error.rs — shared
    helpers stay as they are; they have non-event_de users.
  • Cargo.toml, docs/**, examples/**, tests/**,
    scripts/check-feature-clippy.sh — already consistent with this change.

Git workflow

  • Branch: advisor/002-gate-event-de
  • One commit. Message style: short imperative subject matching repo history.
    Suggested: Gate event_de module behind tests and bench-internals.
  • Author/committer must be jskoiz <20649937+jskoiz@users.noreply.github.com>.
    Do not add any co-author or tool-attribution trailers.
  • Do NOT push or open a PR unless the operator instructed it.

Steps

Step 1: Gate the module declaration

In src/lib.rs, change:

mod event_de;

to:

#[cfg(any(test, feature = "bench-internals"))]
mod event_de;

any(test, ...) keeps the module compiled for unit-test builds (so the 50
tests in src/event_de/tests.rs keep running under plain cargo test) while
removing it from cargo build/downstream compilations, where only the
bench-internals feature pulls it back in.

Verify: cargo build --locked → exit 0.
Verify: cargo test --locked --lib event_de50 passed; 0 failed.

Step 2: Replace the blanket dead_code allow with an accurate, scoped one

In src/event_de/mod.rs, first try deleting line 1 (#![allow(dead_code)])
and updating the comment to describe the new reality, e.g.:

// Benchmark-only event-backed Serde path. Compiled for unit tests and under
// the `bench-internals` feature; not part of default or downstream builds.

Then run the two lint gates below. Expected outcome: under
cfg(test)-without-feature builds, items used only by the feature-gated
wrapper (from_documents_str_with_options,
document_iter_reader_with_options, and anything reachable only from them)
may now warn as dead code.

  • If there are no warnings: done, keep the allow removed.
  • If there are warnings: restore a scoped suppression instead of the blanket
    one — #![cfg_attr(not(feature = "bench-internals"), allow(dead_code))]
    with a one-line comment saying the public entrypoints are only referenced by
    the feature-gated wrapper in lib.rs. This keeps full dead-code linting
    whenever the feature is on (which CI now compiles, per plan 001).

Verify: cargo clippy --locked --all-targets -- -D warnings → exit 0.
Verify: scripts/check-feature-clippy.sh → exit 0 (this is where the
feature-enabled clippy from plan 001 proves the module is warning-free when
fully wired).

Step 3: Full gate sweep

Verify: cargo test --locked → exit 0.
Verify: cargo test --locked --features bench-internals --lib → exit 0.
Verify: RUSTDOCFLAGS='-D missing_docs' cargo doc --locked --no-deps → exit 0.

Test plan

No new tests. The regression bar is the existing suite:

  • cargo test --locked --lib event_de must still report exactly
    50 passed; 0 failed — proof the cfg gate did not silently drop the module's
    unit tests (the most likely failure mode of this change).
  • scripts/check-feature-clippy.sh must pass — proof the feature-enabled
    combination (lib + examples) still compiles.

Done criteria

Machine-checkable. ALL must hold:

  • grep -n 'cfg(any(test, feature = "bench-internals"))' src/lib.rs → one match, on the line above mod event_de;
  • grep -c '#!\[allow(dead_code)\]' src/event_de/mod.rs0 (either removed or replaced by the scoped cfg_attr form)
  • cargo test --locked exits 0
  • cargo test --locked --lib event_de reports 50 passed
  • cargo clippy --locked --all-targets -- -D warnings exits 0
  • scripts/check-feature-clippy.sh exits 0
  • git status --porcelain shows only src/lib.rs and src/event_de/mod.rs modified
  • plans/README.md status row updated

STOP conditions

Stop and report back (do not improvise) if:

  • Plan 001 is not DONE (check plans/README.md) — without feature-enabled CI
    coverage this change would make event_de rot invisible outside cargo test.
  • grep -rn "event_de" src/ | grep -v "^src/event_de" | grep -v "lib.rs"
    returns anything — a new consumer of the module appeared since planning, and
    gating would break it.
  • After Step 1, cargo test --locked --lib event_de reports fewer than 50
    tests — the gate is wrong (e.g. tests no longer compiled).
  • Step 2 produces dead-code warnings in modules other than
    src/event_de/ — that means something outside the module depended on it in
    a way planning missed.
  • Any verification fails twice after a reasonable fix attempt.

Maintenance notes

  • If event_de is ever promoted to a real public API (the original intent per
    its old comment), the cfg gate and the scoped allow are the two things to
    remove; docs/EVENT_BACKED_SERDE.md describes the promotion criteria.
  • Reviewer should scrutinize: that the gate is any(test, feature = ...) and
    not just the feature (which would silently stop running 50 unit tests in
    default CI), and that no pub use of event_de items leaked into ungated code.
  • Deferred (deliberately): deleting event_de outright. It is the in-repo
    benchmark comparison path against serde-saphyr and is documented; removal is
    a maintainer decision, not tech-debt cleanup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    improveGenerated by the improve advisor skilltech-debtTechnical debt cleanup

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions