v0.13.0 — contract honesty: body-field-drift, baseURL keying, silent no-op sweep
Highlights
- New cross-layer rule:
cross-layer/body-field-drift— a frontend request-body literal is checked against the backend@Body()DTO's declared fields on every joined route; mismatches (a body key the DTO does not declare, a missing required field, a missing wrapper key) are reported. Never-guess tone: optional-field omission and backend whitelist-stripping are NOT flagged — only witnessed literal drift. axios.defaults.baseURLpath-prefix keying — a literalaxios.defaults.baseURL = "/api"(or a host-carrying base with a path part) now prepends its path to that client's consume keys before the cross-layer join. Findings will move: pairs that agree on/apion both sides gain real joins; pairs whose backend does not carry the prefix now honestly report prefix drift instead of accidentally joining. Scope: literal bases only — interceptors, wrappers, non-literal constants and generated clients remain adapter-injection territory.
Behavior changes to expect
- Cache recompute (one-time): cache schema bumped v18 → v20 (body-shape capture + client-base keying changed artifact payloads). The first run after upgrading re-extracts everything.
- New warnings for silent config no-ops — config entries that previously did nothing quietly now say so: unknown rule ids in severity overrides and suppressions (joining the existing disabled-rules warning). Each warning names the actual config dialect (
rules: { "<id>": ... }/packs.disabled) and the embedder field, so the advice is actionable in both dialects. - Reserved sentinel kinds are now dropped with a warning in both envelope modes — an external producer emitting the engine-internal
nest-global-prefix/client-base-prefixio kinds gets one aggregate warning per envelope/overlay. In adapter-overlay mode this is also a behavior fix: previously an overlay-emittednest-global-prefixwould re-prefix the whole tree's routes. --jsonstdout is clean again — the "Wrote N reports…" notice moved to stderr (it polluted parseable stdout in v0.12.0).--helpno longer claims "zero-config" (a config file is required;zzop initscaffolds it) and now documents exit codes — scoped honestly: for analysis runs,failOndefaults to"warn"and a first run exiting 1 on findings is expected;zzop adapter validateignoresfailOn(its exit 1 means the envelope failed structural validation).
Docs corrections (act if you copied old examples)
- Every
rules:example in older docs used bare DSL ids ("no-explicit-any","n-plus-one","toctou") — those entries were silent no-ops. The engine matches exactpack/ruleids:typescript/no-explicit-any,sql/nplus1,sql/race-condition-toctou. All examples are corrected, a CI guard now validates doc example ids against the catalog, and the new unknown-id warnings will flag stale entries in your config at run time. envelope.schema.jsonregenerated field-for-field against the Rust types (it was one release stale: missing body shapes,loop_spans,is_entry,client; wrong required-ness on fourOptionfields;sourceSymbolcasing) and is now machine-pinned by a bidirectional parity test (names, required, nullability, enums).- NORMALIZED_AST: casing contract, reserved-kinds section, absolute-URL (
://) verbatim rule, key-normalization crosslinks. ARCHITECTURE: join-integrity gates (cross-tree ambiguity is not auto-linked;://routes to externalConsumes; low-confidence joins are tagged), sentinel shims, and the user-facing baseURL keying consequence. - Report dir is
zzop-reports/zzop.<epoch>(Markdown by default, written by default);overlaysandgit.sinceare now documented config keys.
Internal quality
Docs rule-id guard, schema parity guard, marker -ok convention pin, disable-hint id-coupling pin, and the CLI unit tests (165+) are all wired into CI. A pre-tag 3-lens release audit (policy values / messages / boundaries) ran on this release; all four confirmed findings were fixed before tagging.
Full Changelog: v0.12.0...v0.13.0