# Plot contributor validation matches the contract ``` Type: log Date: 2026-07-11 ``` ## Finding The plot contributor contract documented mechanical requirements that `PlotDefinition::validate()` did not enforce: non-blank attribution and category, ASCII player-facing strings, the `{target}` / `{persona}` placeholder whitelist, and a causal beat on every successful path. Invalid content could therefore pass the same catalog load that contributors were told was authoritative. While this repair was in flight, the parallel plot-content-pipeline change landed build-time discovery and Rust-impact classification on main. This change keeps that implementation and closes the remaining semantic-validation gap rather than replacing the newly landed catalog generator. ## Repair - Schema 1 adds an explicit `causal = true` beat marker. It counts only on a beat with typed world acts, must occur before every successful terminal ending or choice, and cannot be hidden behind an earlier terminal beat. - Validation rejects blank `author` / `category`, non-ASCII player-facing strings, unknown placeholders, unbalanced braces, empty ending narration, and unreachable beats after a terminal. - All six shipped plots mark the beat that actually clears the target's situation. The authoring contract and both checked-in skill mirrors name the same machine-checkable rule. - The environment registry now distinguishes Cargo-provided variables used by the package build script from forbidden runtime environment reads in sim library sources. - Focused tests cover each rejection path, generated-catalog correspondence, file-stem/id mismatch, and duplicate ids without freezing the catalog at six plots. The existing build-generated catalog, local lib classifier, and Tangled Rust-impact classifier ensure plot-only submissions execute these checks. ## Checks `cargo test -p misaligned-core plot::`, classifier fixtures, corpus gate, warning-free core clippy, and the canonical `./tools/check.sh --lib` gate.