Skip to content

chore(deps): Bump clap from 4.6.1 to 4.6.6 - #267

Closed
dependabot[bot] wants to merge 1787 commits into
masterfrom
dependabot/cargo/clap-4.6.6
Closed

chore(deps): Bump clap from 4.6.1 to 4.6.6#267
dependabot[bot] wants to merge 1787 commits into
masterfrom
dependabot/cargo/clap-4.6.6

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 10, 2026

Copy link
Copy Markdown
Contributor

Bumps clap from 4.6.1 to 4.6.6.

Release notes

Sourced from clap's releases.

v4.6.6

[4.6.6] - 2026-08-06

Features

  • Add Command::get_overridden_usage

v4.6.5

[4.6.5] - 2026-07-31

Fixes

  • (help) Correctly mark which value_names are optional with num_args

v4.6.4

[4.6.4] - 2026-07-21

Internal

  • Update to syn v3

v4.6.3

[4.6.3] - 2026-07-20

Fixes

  • (derive) Allow "literal".function() as attribute values

v4.6.2

[4.6.2] - 2026-07-15

Fixes

  • (help) Say alias when there is only one
Changelog

Sourced from clap's changelog.

[4.6.6] - 2026-08-06

Features

  • Add Command::get_overridden_usage

[4.6.5] - 2026-07-31

Fixes

  • (help) Correctly mark which value_names are optional with num_args

[4.6.4] - 2026-07-21

Internal

  • Update to syn v3

[4.6.3] - 2026-07-20

Fixes

  • (derive) Allow "literal".function() as attribute values

[4.6.2] - 2026-07-15

Fixes

  • (help) Say alias when there is only one
Commits
  • 348cff3 chore: Release
  • d478377 docs: Update changelog
  • 04b9fbb Merge pull request #6414 from koopatroopa787/fix-bash-completion-bracket-glob
  • 7075239 Merge pull request #6422 from BaumiCoder/fix-fish-indentations
  • f90a966 fix(complete): Use spaces for indentation in fish
  • dd4997b fix(complete): Don't glob-expand bash positionals
  • 8387c81 Merge pull request #6399 from clap-rs/renovate/crate-ci-typos-1.x
  • 8141e11 chore(deps): Update compatible (dev) (#6398)
  • 8a6bd4e chore(deps): Update pre-commit hook crate-ci/typos to v1.47.0
  • 71a7213 chore(deps): Update Rust Stable to v1.96 (#6396)
  • Additional commits viewable in compare view

Dependabot compatibility score

You can trigger a rebase of this PR by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

SebastienGllmt and others added 30 commits August 1, 2026 06:57
… and two fixtures

A generated component crate that does not compile is the failure mode this whole face
exists to prevent, and every other gate is blind to it: a WIT package can resolve, encode
and validate perfectly while the glue implementing it names a trait method that does not
exist. So `component_crate_builds_for_wasm32_wasip2` generates to scratch and really builds
for the target, asserting the artifact carries the component-model preamble (layer 1) so a
core-module build cannot pass vacuously. Nested cargo, memoized per generated-crate content
hash by the gate cache; a missing target is reported as a provisioning problem naming the
`rustup target add`, never as a broken emitter.

The smoke narrows the RUST crate's `crate-type` to `rlib` in its scratch copy. That crate's
`cdylib` output exists for wasm-bindgen's `wasm32-unknown-unknown` target; asking the wasip2
linker for it is not something the component face needs (the guest consumes the rlib) and
`wasm-component-ld` crashes on it for some specs. Narrowing it keeps the gate's verdict
about the crate under test.

The two emission invariants get structural pins rather than prose: no `borrow_mut` may share
a statement with an argument's `.get::<Wit…>()`, plus a positive assertion that the recursive
fixture DOES materialize its `list<borrow<node>>` argument — without which the first
assertion could pass on glue that had stopped emitting the shape at all. Getters are pinned
to clone the field into a fresh handle, in both the scalar and the per-element form.

`tests/component-multifile` is the multi-interface shape with NO externs, which is what lets
the build smoke compile it: `tests/multifile`'s own rust crate needs a hand-written extern
re-export before it builds at all, so it can gate the projection but never the link. It is
where two `Guest` impls under one `export!`, a cross-interface `borrow` parameter and an
`own` handle minted for another interface's resource are checked at link time.

`tests/component-cycle` is the end-to-end half of the cross-scope cycle detector: two scopes
referencing each other with no type-level recursion anywhere — the case a type-level detector
would miss — asserted to generate fine on the rust face and to hard-error under `--component`.

Neither fixture dir carries a top-level `input.cddl`, so neither is visible to the corpus
axis gate, which keys on exactly that file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each is a spec a user can legitimately write whose emitted guest crate
fails to build, and none was reachable from the fixtures.

A NonEmpty TABLE parameter crosses as `list<tuple<K, V>>` like every
other despecialized collection, and the guest re-enters the invariant
through a `try_into` on the vec it collected — but `NonEmptyMap` had
only the map door, so the vec never converted. It gains the
vec-of-pairs door its `NonEmptyPairMap` twin already had, delegating to
the single map door so the empty-map refusal error stays identical on
every path.

A RECORD's `new` is fallible when a mandatory field carries a value
bound, and that verdict is reached by a different rule from the
`@newtype` wrapper's: the wrapper's rides the IR, the record's is
derived per emission. The glue consulted only the first and bound a
`Result` where the rep expects the value, so it now reads the rust
face's own rule through the mirror `emit_tests` already shares with
`records.rs`.

A type the rust face declines to give a `Deserialize` impl — an array
struct whose optional field is CBOR-ambiguous with what follows it —
still got a `from-cbor-bytes` on both sides of the macro, naming a
trait impl that does not exist. The projection now takes the
no-deserialize set as an input and drops the member, mirroring the wasm
face's own fork. That set is a GENERATION-time verdict, so it arrives
from the caller: the finalization-time collision detector projects with
an empty set, which is the safe direction (dropping a member can only
remove a collision), and `api::wit_strings` filters the full producer
rather than shortcutting to the projection, so what the gates pin is
what the tool ships.

The first two are pinned by compilation: `tests/component-core` gains a
NonEmpty table and a value-bounded field, so the wasip2 build smoke is
the oracle. The third is pinned per-type, both halves, on a scratch
spec.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t asks what the boundary dropped

Every other component gate judges what was emitted against itself: the
four-stage validity gate resolves, encodes and validates the `.wit`, and
the wasip2 smoke compiles whatever glue implements whatever that `.wit`
declared. A member missing from BOTH halves therefore yields a package
that resolves, validates and builds, and nothing can see it. This is the
sibling of `wasm_api_parity` for that boundary, with the same
one-directional question and the same ledger-with-a-two-way-guard.

Two deltas from the wasm sibling. It parses EVERY per-scope rust file
rather than one `mod.rs`, because one WIT interface per input file is
what the component face is for. And its WIT half goes through the pinned
`wit-parser`, so what is compared is the surface the toolchain sees,
against a rust->WIT name map that is a pure function of the rust name
plus the single `new` -> `constructor` mapping. The projection does carry
the pairing, but reading it would make this an intent check where the
whole point is an output check.

The ledger opens with the `Int` value-type class — a `variant` has no
member namespace for `new_uint`/`new_nint` to land in — and `IntError`,
the rust-only error enum minted beside `Int`, which is not an IR type at
all and has nothing to be on a face that carries every failure as a
string. Both are live findings, so the resurfaced guard has something to
reconcile from the first run.

Non-vacuity is guarded three ways: a floor on the obligations compared,
a stray-key guard over both generated trees, and an axis assertion that
every fixture `component_tests` compiles or validates is differentialled
here too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ated artifact that is not rust

Two profile-limited `WHOLE_PROGRAM_CASES` rows under `--component=true`:
the single-scope type corpus and the multi-INTERFACE directory input.
They capture the whole fourth crate — its manifest, its seed-once root
and its glue — and the emitted WIT package, which is the only generated
artifact that is not rust and so had no byte-level pin anywhere.

They also extend `generated_files_start_with_header` at no cost: its
sweep is `WHOLE_PROGRAM_CASES` filtered by `is_header_stamped_path`,
which already knows about `.wit`.

Thirty new snapshot files, no existing snapshot changed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pelled as unwrap

The tier's clippy gate runs --all-targets with -D assertions_on_result_states, so
assert!(x.is_ok()) in a test is a compile failure, not a style nit. timings.json
carries the registry's new component gate rows, per the tier's own commit-it notice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… might have

The WIT face carries two `--component` refusals, and each was judging a
surface the emitted package does not have.

The cycle detector recorded a NAMED COLLECTION's own ident where the
projection resolves through it to the element. Both directions of that
disagreement invent edges: a holder of an `a::names` whose element lives
in `c` got `b -> a` instead of the `b -> c` the emitted `use` carries, and
the collection RULE — which surfaces no WIT type at all, so it owns no
interface — contributed `a -> c` on top. Either one closes a cycle in a
spec whose WIT resolves perfectly, and the resulting refusal names scopes
the package never links, which a user cannot act on. Measured on this
worktree before the fix: `a::names = [* text]` held by `b::rec` beside
`a::holder -> b::rec` was refused as "the scopes `a`, `b` reference each
other", and so was the collection-rule-only variant. The walk now resolves
through exactly as `map_named` does (with the same re-entry guard, so a
self-referential collection terminates rather than overflowing the stack)
and skips collection rules exactly as `project` does. A real cycle closed
through a collection is still refused and now names only the two scopes
the `use` graph links, which is a strictly better message.

The name-collision detector projected with an EMPTY no-deserialize set,
because at IR finalization the rust face has not yet decided which types
get a `Deserialize` impl. That superset over-reports for real: a type with
no `Deserialize` impl AND a field named `from_cbor_bytes` was rejected for
a collision between a getter and a `from-cbor-bytes` static the tool never
emits. It moves to generation time, where the verdict exists, and surfaces
through the graceful error channel `generated_files`/`export` already
carry — checked before any write, so a refusal never scatters half a tree.
The cycle detector STAYS at finalization: it needs no verdict, and a spec
with both reports the cycle first, which is correct — a cyclic package has
no resolvable WIT to hold collisions. The three pinned collision messages
are byte-identical.

Both fixes carry a negative control, because "agree with the projection"
and "consult the verdict" are each satisfiable by a detector that sees
nothing: the real cycle through a collection is still refused, and the
same `from_cbor_bytes` field on a DESERIALIZABLE type is still refused
with the pinned message.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Type and group choices were the largest excluded class on the WIT face.
They now project to a `resource` with NO constructor — there is nothing to
build without picking an arm — plus one `new-<variant>` STATIC per arm, a
`kind` discriminant returning a new `<name>-kind` enum, and one
`as-<variant>` per arm that carries data. A fixed-value arm gets a nullary
static and no getter: it has no payload for one to return, and `kind` is
already the whole answer for it.

All three families spell `<variant>` from ONE conversion of
`EnumVariant::name_as_var()`, which is also the source of the rust
`new_<variant>` the guest calls, so a drift between the WIT name and the
rust one is not expressible. The parameters mirror the rust constructor
per arm shape rather than per enum — a group-choice arm naming a record
takes that record's mandatory fields, an inlined arm takes its non-fixed
field, everything else takes the variant's own type — because the guest
calls that constructor positionally. Fallibility is carried the same way:
the rust constructor's own is projected beside the member's, which is
strictly wider (a despecialized `[+ T]` arm makes the STATIC fallible over
an INFALLIBLE rust constructor, so the glue must not `?` it).

The `kind` / `as-` arms are spelled by `enums::EnumVariantInRust`, widened
to `pub(super)` rather than re-derived. That fork is per VARIANT, not per
enum — under `--preserve-encodings` a primitive arm becomes braced while a
`Rust`-typed arm in the same enum stays a tuple — and a second derivation
would be a `match` that compiles in one posture and not the other, in
generated code the user cannot edit. The guest never names the rust
`<Name>Kind`, which exists only under `--wasm`.

The `<name>-kind` enum lives in the interface's one flat type namespace,
so it is collision-checked like any other name; that makes it the shape
the `@name` remedy can be PROVEN against. Every collision message names
`@name` as the fix and nothing proved it worked, so
`tests/component-rename` now generates only because of two `@name`s — one
moving a field off its resource's own name, one moving a group-choice arm
struct off a choice's `-kind` enum — with both un-renamed twins asserted
still refused, since a fixture that generates proves nothing about a
remedy unless what it remedies still fails.

`component_wit_excludes_a_type_choice_and_everything_that_reaches_it` is
re-pointed at the EXTERN class and renamed: choices are projected now, and
the exclude-and-record path must keep a live test rather than lose one
when its last subject ships. Item F (extern bridging) will have to point
it somewhere else again.

Verified on this worktree: `cargo test --bin cddl-codegen component` 35
passed / 0 failed, including the wasip2 build smoke over the new choices
fixture (re-run with GATE_CACHE=0 so the cell actually built); snapshot
tests 46/0 with only the new `component_choices` rows added and no
existing snapshot byte changed; `wasm_api_parity` 13/0; clippy
`--all-targets` clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s on the fact that owns it

The component face routed every boundary parameter off one bit, `validates`, which is the
UNION of three unrelated facts: a despecialized collection, a value window, and CDDL `any`.
Two defects fell out of the conflation, both invisible to every WIT gate because a bounded
setter's `result<_, string>` reads identically either way.

A bounded setter checked NOTHING while declaring itself fallible, leaving this face strictly
weaker than the wasm one, which emits the range check at the same site. And `materialize`'s
`validates && is a list` sent a merely-BOUNDED collection through the despecialization door:
for `[2*5 uint]` that resolves to `Vec<T>`'s identity `TryFrom` (`Error = Infallible`), which
compiles while checking nothing, and for an inline bounded map it named a
`TryFrom<Vec<(K, V)>> for BTreeMap` that does not exist at all — glue that did not compile.

So `WitParam` now carries `rust_type: Option<RustType>` (R3: the projection carries the rust
fact rather than the emitter re-deriving it) and the two doors read the type directly.
`wit_param_despecialized` is the narrow predicate for the `TryFrom` door; `bounds.rs` gains
`component_bounds_check_line`, which walks the SAME decision tree as `value_bounds_check_line`
through the same condition owners (`reject_cond`, `bounds_check_expr_rust_type`,
`bounds_check_expr_non_negative`, `nint_bounds_to_u64`, `float_accept_cond`, `float_literal`)
and forks only the `Err(..)` construction — a second condition spelling is the drift the bounds
machinery was consolidated to prevent.

Two spellings there were probed rather than assumed. `DeserializeFailure` implements no
`Display` (only `DeserializeError` does), so the failure is lifted through
`DeserializeError::from` before it reaches the guest's `Display`-bounded `err` helper. And the
check is emitted against the BOUNDARY value, ahead of the conversion, because a `.len()` read
off a `collect()`-bound local is E0282 — confirmed by compiling the shape — the container type
being pinned only by the assignment that follows. That is also exactly where the wasm face puts
its own check (`records.rs`, ahead of `from_wasm_boundary_clone`), so the two stay parallel.
The window is a SETTER's job alone: every other door hands its parameter to a rust constructor
that range-checks and whose `Result` the guest already unwraps.

Externs and raw-bytes types get bridging resources, so one hand-written type no longer takes
every record that reaches it out of the WIT. An extern carries the cbor seam over the
`Serialize`/`Deserialize` its contract already requires. A raw-bytes type does NOT: its
contract is `RawBytesEncoding` and nothing requires `Serialize` of it — the emitted
extern-interface self-check asserts `_assert_raw_bytes` and no `_assert_serialize`, and the
generated serializer reads it through `to_raw_bytes()`/`from_raw_bytes()` — so it carries a
`to-raw-bytes`/`from-raw-bytes` seam instead. This deviates from PLAN §4's last row, which
says every such type bridges "via the rust Serialize/Deserialize the extern contract requires";
that is true of `Extern` and false of `RawBytesType`, and a cbor bridge there would name a
trait impl that need not exist. Both halves of the raw seam are unconditional, since
`RawBytesEncoding` is one trait declaring both methods.

A generic extern BASE is skipped from the projection the way a named collection is — it names
no concrete type, so a resource over it would be a resource over nothing — keyed on
`generic_extern_base_idents()` rather than the narrower `generic_instance_bases()` the wasm
glue uses. Its INSTANCES are bridged under the instance ident and reached through the
`pub type <Instance> = <Base><Args>;` alias the rust crate emits. A bare reference to a base is
excluded WITH a reason naming the shape, and the same set is filtered out of the cycle
detector's edges so a skipped ident can close no cycle. Non-extern generic instances are
monomorphized before generation and need nothing at all — asserted by fixture, not prose.

`component_wit_excludes_an_extern_and_everything_that_reaches_it` is re-pointed at the generic
extern base, which is the class still unprojectable now: the exclude-and-record path must keep
a live test rather than lose one when its last subject is implemented.

Verification (targeted; `check.ts` was not run at any tier). `cargo test --bin cddl-codegen
component`: 39 passed, 22.4 s, including the wasip2 build smoke over the new bounds fixture and
`component_api_parity`, which reported no new asymmetry — a user-owned extern emits no rust
`pub struct`, so it owes the differential nothing. `snapshot_tests`: 46 passed, 21.5 s, and the
only snapshots written were the new `component_extern` row — no existing pin moved.
`wasm_api_parity_axes_and_pins_are_live`: pass. `cargo clippy --all-targets`: clean.
`tests/component-extern` cannot enter the build smoke (its rust crate names user-owned types,
the same reason `tests/multifile` is absent), so its glue was compiled once by hand against
written `Ext`/`Raw`/`ExternGeneric<T>` definitions: `cargo build --target wasm32-wasip2`
finished in 11.3 s with no errors, and the bounds fixture independently in 11.7 s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…es whose contract carries it

Three things land together because the third is what the second makes reachable.

**`to-canonical-cbor-bytes`.** Under `--preserve-encodings --canonical-form` every resource
carrying the cbor seam also carries the canonical re-encoding door, bridged through
`Serialize::to_canonical_cbor_bytes`. The gate is that flag pair and not a choice: the method is
declared on the `Serialize` trait, and the runtime composes `Serialize` from exactly
`serialization_preserve_force_canonical.rs` — every other posture composes a `ToCBORBytes` that
declares `to_cbor_bytes` alone, so a row emitted there would name a method the user's crate does
not have. `bytes_members` owns the row, so records, `@newtype` wrappers, choices and extern
bridges all get it from one place, and the raw-bytes bridge (which has no cbor seam at all) still
gets nothing. The glue names `Serialize` literally rather than reusing the emitter's
`to_bytes_trait()` fork: the two agree by construction here, and naming the trait that OWNS the
method is what keeps the glue honest if either moves.

**The JSON seam.** Under `--json-serde-derives`, per-resource `to-json` / `from-json` plus the free
`cbor-to-json` / `cbor-from-json` on the `any-cbor` alias, emitted as `serde_json` calls over the
serde impls the rust crate derives under the same flag. Two decisions worth the words:

- It has its OWN owner (`json_members`) rather than joining `bytes_members`, so it reaches only
  the types the tool DEFINES. Sharing the cbor owner with the extern bridge is legitimate — the
  extern contract already imposes `Serialize`/`Deserialize` and the emitted
  `extern_interface_check.rs` asserts them — but nothing imposes serde on a user-owned type, so a
  `to-json` on a bridging resource would name a trait impl that need not exist. That is the
  compile-error-in-generated-code class the `no_deserialize` fork and the raw-bytes seam split both
  exist to prevent, reached a third time. Probed rather than assumed: the emitted self-check for
  `tests/component-extern` asserts `cbor_event::se::Serialize` / `Deserialize` / `RawBytesEncoding`
  and no serde bound, and the wasm face emits no wrapper for an extern at all, so there is no
  precedent to copy.
- `to-json` is `result<string, string>`, DEVIATING from the plan's infallible `string`. The wasm
  face's own `to_json` is `Result<String, JsError>` and rendering genuinely can fail — the runtime's
  `AnyCbor` serde fragment documents a "key must be a string" failure for a non-string-keyed map,
  which reaches any type holding one. Parallel-with-documented-deltas means fallible here.

The component manifest gains `serde_json` under the same flag, set-or-REMOVE, at
`ops_for_wasm`'s version and features verbatim (`float_roundtrip` included, because `from-json`
parses through `serde_json::from_str` and has to round-trip `f64` bit-for-bit). It does NOT gain
`serde` or `serde-wasm-bindgen`: the emitted guest names neither crate, and `to_json_value` has no
WIT counterpart. The dep is a flag-conditional in-code op, so the drift-gated
`static/Cargo_component.toml` — which renders from the append-only log alone — is unchanged;
`manifest_template_drift` passes without a re-bless.

**The collision detector now walks an interface's free FUNCTIONS too.** A WIT interface's types and
its free functions share ONE flat namespace: `wit-parser` refuses `name X is defined more than once`
at RESOLVE, probed against the pinned 0.247 resolver. The interface-level check walked only
`iface.types`, so a rule converging on a synthesized door reached the user as a parse failure
against a file they did not write — the sighting this detector exists to replace. Latent for
`cbor-kind` and widened by the two doors above, so it is fixed here rather than ledgered. The three
pinned messages are unchanged; the only new text is the `the free function \`x\`` owner string.

Coverage, since a seam that names a serialization trait is a two-crate fact no WIT gate can see:
`COMPONENT_FIXTURES` gains force-canonical rows for core / choices / bounds / extern and JSON rows
for core / choices / extern, which extends the wasm-posture purity invariant and the WIT-validity
sweep to both postures by registration alone (both iterate that list). `PARITY_CASES` mirrors them;
the differential reported only the pre-existing `Int` value-type class on the two new core labels,
so serde derives and a trait method genuinely add no rust inherent surface. The wasip2 build smoke
gains one row in the posture that carries BOTH seams, and a `component_json` whole-program row pins
the emitted bytes including the manifest. No existing snapshot moved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ction rather than a rumour

The generated rust crate declares crate-type = ["cdylib", "rlib"] for the wasm face, and on
wasm32-wasip2 that cdylib can take wasm-component-ld's LLD down with a SIGSEGV. Documented on
the --component row, where a user turning the face on will meet it.

Every claim in the row was measured on this worktree under the pinned rustc 1.96.1:
tests/component-multifile/inputs reproduces the crash with the exact signature quoted, while
component-core, component-choices and component-bounds all link cleanly at exit 0 — so the row
says spec-dependent instead of implying every spec crashes. Building only the component crate
was probed and does NOT avoid it (cargo builds every crate-type a path dependency declares),
which is why the row rules that out explicitly rather than leaving it as the obvious guess.
Narrowing to ["rlib"] was then verified to build the same spec at exit 0.

The fix is documented as a consuming-workspace edit and NOT emitted: the cdylib is load-bearing
for --wasm, so a crate generated with both faces on needs it, and changing what the tool writes
is a maintainer ruling this does not take.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lly do

The message told a user to @name a top-level rule, which the comment DSL cannot
rename — a remedy that cannot be followed is worse than none. The remedy is now
renaming the rule in the spec, with the fact that makes it safe (rule names never
reach the wire) stated inline. The test pins anchor on the message prefix, which
is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The reworded remedy landed one commit ago with this pin still on the @name tail —
message and pin move together, and the previous commit shipped them apart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ere it differs

`ALL_PROFILES` grows a fourth row, `component` = `--component=true`, so every
`tests/corpus/*.cddl` fixture is exercised through the WIT projection and the
guest glue rather than only the five hand fixtures the face's own gates sweep.

`--wasm` stays at its default. The repo has already chosen that posture for this
face's whole-program snapshots; the emitted `component/wit/**` is byte-identical
between the two wasm postures for every corpus fixture, so turning wasm off buys
no coverage; and every consumer of this const hardcodes `--wasm=true` before
appending a profile's flags, where a second `--wasm` is not a last-wins override
but a clap error ("cannot be used multiple times").

The face is purely ADDITIVE — `--component=true` mints `component/**` and changes
no other emitted byte — so the corpus snapshots only `component/**` under this
profile and ASSERTS the rest byte-identical to the `default` profile's. That is
strictly stronger than a fourth copy of the rust and wasm trees: those bytes are
duplicates by construction, whereas the assertion states the invariant they would
only implicitly encode and fails the day the component face starts leaking into
the other two.

Seven consumers filter the row out BY NAME through the shared `COMPONENT_PROFILE`
constant, each with its own reason, and a liveness test fails loudly if the row is
renamed rather than letting the filters become silent no-ops. `feature_corpus_compiles`
cannot pick the row up in any case: it compiles for the HOST with hardcoded
rust/wasm `crate_subs` and no `--target`, while the component crate is a wasip2
target. Corpus-breadth component coverage therefore lands here as
`component_wit_validates_the_corpus` — the same four stages the fixture sweep uses
(resolve, encode, validate), over all 89 fixtures. It deliberately makes no
"world is non-empty" assertion: three fixtures resolve every rule through as an
alias or named collection and project an empty world, which is correct output.

Zero pins: all 89 fixtures generate, resolve, encode and validate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, not which exist

`verify.ts` writes this header, and its text now records that the `component`
row of `ALL_PROFILES` is deliberately not probed on this axis. Applying the same
two lines to the committed file keeps a `verify` run from surfacing a header-only
diff that reads as drift; nothing below the header moves, and `build_matrix.ts
--check` confirms matrix.json is unaffected (TOML comments carry no values).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sweep proved

The row explains why `--wasm` stays on, and its second reason described clap as
last-wins with a missing-crate failure downstream. `ArgAction::Set` is set-once:
a repeated `--wasm` is refused at argument parsing, which is both earlier and
louder than the failure the comment predicted. `component_profile_flags` already
carried the correct rule; the two comments now agree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gate

Every component gate so far judges emitted bytes. A `.wit` that resolves,
encodes and validates over glue that compiles is still silent about what the
boundary DOES, so this adds the gate that runs it: a real `wasm32-wasip2`
component loaded into wasmtime and driven through one `#[test]` per assertion
class — construction/read-back, byte-equality against the rust crate's own
serialization, fallible doors returning `Err` without trapping (and the
instance surviving), the three states of `option<option<T>>`, snapshot
semantics in both the return and the parameter direction, the
same-handle-as-receiver-and-argument case, and the `any-cbor` canonical
re-encode and one-item rules.

The trap TEXT is deliberately never pinned. What matters is that a trap
POISONS the instance, so "still usable afterwards" is the assertion a wording
pin would only approximate.

The host crate is nested and gate-cache memoized rather than a dev-dep:
wasmtime in the bin crate's dev-graph would tax every `local`-tier compile. It
is copied INSIDE the hashed output root before the key is taken, because every
input a cached cell reads from scratch must live there — a host crate parked
beside the tree would serve a stale PASS forever after any edit to its
assertions, and the closure audit cannot flag it. Its `bindgen!` reaches the
WIT by a relative path and the artifact by an env var, so the hashed bytes stay
run-independent, and the cached closure's extra verdict logic is versioned into
the key as an argv marker.

Measured: 81 s cold (fresh scratch root, wasmtime builds), 3 s warm
(gate-cache hit), 9 s on a cache miss with the scratch root warm — which is why
that root is checkout-hash keyed and kept rather than deleted. Those numbers put
it at `local` tier with the test not `#[ignore]`d.

The fixture is a DIRECTORY input: `tests/<dir>/input.cddl` carries a
corpus-parity registration obligation and this fixture has no wasm-parity
question to answer. Its `children` field is optional so the resource gets a
`set-children` at all, which is what makes `x.set-children([x])` expressible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s a consumer supplies

`tests/component-extern/inputs` was validity- and snapshot-gated only, so its
bridge glue was compiled by no gate at all. That is the worst place for the
gap: every OTHER build-smoke row compiles a crate the tool wrote alone, while a
bridge names a TRAIT on a type the tool does not define — so naming the wrong
one is a compile error in the CONSUMER's crate, and nothing that reads our own
output can see it.

The fixture now enters the wasip2 build smoke in two rows, each paired with
hand-written definitions of its extern types. They are appended into the
generated crate's THIN ROOT, which is where a real consumer puts them and the
only place they can go: the generator re-exports every in-crate extern with
`pub use crate::<Name>;` into `generated/**`, so a definition there collides
E0255 and that subtree is clobbered every regen. Written before the cell is
keyed, so they sit inside the hashed root rather than beside it.

Two flavors, because the CONTRACT differs by posture and that difference is the
reason the second row exists: the default posture asks an extern for
`cbor_event`'s `Serialize`, while `--preserve-encodings --canonical-form` makes
the runtime compose its own — the trait on which `to_canonical_cbor_bytes` is
declared — and the emitted `extern_interface_check.rs` asserts that one
instead. The canonical row is therefore the one that compiles the
`to-canonical-cbor-bytes` half of the extern's seam and proves the raw-bytes
bridge, whose contract is `RawBytesEncoding` and nothing more, was left alone
beside it.

Verified live rather than assumed: removing the `Deserialize` impl from the
defs reds the gate with E0277 on the extern and on the generic instance that
reaches it.

Three comments asserting the fixture could not be compiled are updated rather
than left to rot, and each now says what its own half asks that the other
cannot — the snapshot pins the trait a bridge NAMES and what the projection
EXCLUDED, neither of which a build outcome can judge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ys what that found

`feature_corpus_compiles` structurally cannot compile this face: it hardcodes
its crate list to the rust and wasm trees and runs a HOST `cargo check` with no
`--target`, which is why the `ALL_PROFILES` component row filters OUT of it
rather than flowing into it. So corpus-breadth component compilation needed its
own gate, and this is it — `cargo check --target wasm32-wasip2` per fixture.

`check` rather than `build`, probed rather than assumed: the link is already
asserted on five representative fixtures by the build smoke, and the class that
only breadth reaches — glue naming a trait, method or macro the bindings never
minted — is a type-check failure. `cargo check` expands
`wit_bindgen::generate!` and reports every one of them.

No sharding, sized from this gate's own measurement rather than
`feature_corpus_compiles`' curve: ~10 s for the first cell, which builds the
shared dependency graph, then ~0.4 s each. 140 s cold, 97 s warm — a warm run
still pays generation and the lockfile preflight per cell, which is most of what
remains. The scratch root is flocked and kept so that graph survives; per-cell
trees are freed.

The gate immediately earned itself. Nine corpus fixtures do not compile, in four
emitter classes, all in the emitted `component/src/generated/mod.rs` and all
reproducing under either `--wasm` posture: a world exporting no interface still
emits `export!(Component);`; an interface whose only types are VALUE types still
emits `impl wit_types::Guest for Component {}`; a despecialized `[+ T]` /
`{+ K => V}` in a position no component fixture reaches `.collect()`s straight
into `NonEmptyVec`/`NonEmptyMap` instead of re-entering its `TryFrom` door; and a
`@default`ed scalar's glue treats the value as a handle. They are recorded in
`EXPECTED_COMPILE_FAIL` — guarded both ways, so a fix cannot land unnoticed and a
regression cannot hide behind a neighbour's pin — rather than left in prose,
which is what makes them a worklist instead of an anecdote.

The per-cell EXPECTATION is part of the gate-cache key, so removing a pin
re-runs the cell rather than serving a PASS recorded under the old expectation.
Fixtures whose rust crate references user-supplied code are excluded through
`integration_tests::COMPILE_SKIP`, shared rather than restated so the two corpus
compile gates can never disagree about which those are.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e, not always

`wit_bindgen::generate!` mints an `export!` macro only for a world that HAS
exports, and a `Guest` trait only for an interface that has something to
implement. The glue emitted `export!(Component);` and one `impl <iface>::Guest
for Component` per interface unconditionally, so two ordinary CDDL shapes
emitted glue that could not compile for `wasm32-wasip2`: a spec whose every rule
resolves through — a plain alias, a named collection — exports no interface at
all (`cannot find macro export in this scope`), and a spec whose only projected
type is a value type — a c-style enum — exports an interface of pure type
declarations (E0405 on the `Guest` trait).

The condition is asked per interface for the impl and per package for the block.
Both halves were probed against wit-bindgen 0.57 rather than reasoned about: an
interface with a FREE FUNCTION and no resource does mint the trait, so "has a
resource" alone would have suppressed the impl this face's `any-cbor` free
functions need — one compile error traded for another.

What is left once the impls are gone has no possible caller: the guest type, its
`export!`, the `err` funnel every fallible door reports through, the
enum/`int`/`any-cbor-kind` bridges and the interface `use` aliases they are
spelled against all exist to serve a `Guest` impl. So the whole block goes with
them and the emitted file is the `generate!` invocation alone — dead code in a
file the user cannot edit is the same thing the emitter already avoids for an
unreachable match arm. The WIT surface is untouched: a world's exports live in
the component type section `generate!` emits whether or not `export!` is
invoked, and a value-only world built to a valid component either way (probed by
building one).

Pinned by three tests in the same commit, since `component_corpus_compiles` is
`full`-tier and `#[ignore]`d and nothing in `fast`/`local` would catch a
regression: the two spec shapes and their control, the per-interface granularity
of the impl half beside an interface that does get one, and the free-function
rule at the one position no CDDL spec currently reaches.

Six `EXPECTED_COMPILE_FAIL` rows removed; the gate re-ran exactly those six
cells (6 run, 80 cached, 93.9 s) and its resurfaced guard stayed silent. The six
corpus snapshots that moved are pure deletions — 120 lines, no additions, no
other fixture touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ts loop

All 89 emitted component crates are `cddl-lib-component v0.1.0`, and cargo does
not tell two of them apart across the shared target dir the gate keeps for
speed: a batch that generated every fixture first and checked afterwards was
measured serving one fixture's `Finished` — replayed warnings and all — for the
next fixture's check, which would turn a real compile failure into a silent
pass. The gate is already safe, because it generates each fixture immediately
before checking it and every cell's sources are therefore newer than the
fingerprint the previous cell wrote. Nothing said so, so a later refactor
hoisting generation out of the loop would make the sweep vacuous without
failing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e emitter and measured sizes

The sibling of wasm_differences.mdx for the component face: why the boundary is resources with
borrow-parameters and own-returns, why collections lost their wrapper classes and gained a
validate-on-consume door, and what a consumer has to know before composing against a generated
package.

Every row was taken from the emitter or from a measurement rather than from the plan, and two rows
differ from what the plan sketched: only OPTIONAL fields mint a set- setter (a mandatory field's
value is established at the constructor and nowhere else), and there is no indexed setter at all.

The size section is measured on this worktree under the pinned rustc 1.96.1, release with
opt-level = "s" and the rust crate narrowed to rlib: 275,768 B for a small single-scope spec,
338,772 B for the json fixture, and 145,020 B for a one-rule spec — so the floor is the linked CBOR
runtime, not the glue. wasm-opt is documented as refusing components outright at Binaryen 125,
with the embedded core module's -38.2%/-42.9% quoted as an upper bound and strip = true (-23.1% /
-25.8%) named as the lever that actually applies today. The 14 wasi:* import floor the phase-0
spike measured is confirmed exactly, identical across all three artifacts.

The wasip2 cdylib link crash is referenced rather than restated: it is already documented on the
--component flag row, and a second account of it would be a second thing to keep true.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…that would have caught them

Both were found while building the component face and both reproduce with --component nowhere in
sight, at master 781e6b8.

The wasm face drops to_canonical_cbor_bytes: create_base_wasm_struct builds the function and never
pushes it, so under --preserve-encodings --canonical-form the rust crate has the method and the wasm
boundary has zero occurrences of it against four of to_cbor_bytes. The entry names the testing gap
rather than the one-line fix, because the gap is the larger half: wasm_api_parity's rust-side walk
reads inherent impls only, and every member of this family exists ONLY as a trait method on the rust
side and ONLY as an inherent fn on the wasm side — so all six of them are invisible to it by the
same structural exemption, and the component face already ships the posture-conditioned assertion
the wasm face wants.

A self-referential named collection aborts the tool: foos = [* foos] plus a holder overflows the
stack at exit 134, after printing the recursion diagnostic. The owning family is the input
panic-robustness catalog, whose neighbours bracket the shape without covering it — but that catalog
runs generation in-process under catch_unwind, and an abort is not an unwind, so the fixture would
take the test binary down rather than record a row. The missing system is therefore an
out-of-process outcome lane with a fourth verdict, not a fixture.

Each entry's reopening signal is scoped to the generalization the entry deliberately does not
propose, and is checked against its own body: one silently-missing member and one hand-found abort
shape are recorded, so "a second, found by another route" can still fire.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… when the consumer supplies its wit

A dependency reached through `--extern-import` has no WIT projection today: its types
are skipped and every consumer signature naming one is recorded as `// unexported:`.
`--component-extern-wit <dep>=<path to the dep's component/wit>` opts that dependency
into IMPORT MODE instead, so one dependency component instance can serve every consumer
and handles interchange between them.

Opt-in per dependency, because the payoff is: a dependency with no component face has no
`component/wit` to point at (a hand-written crate, a stub tree), and a mandatory flag
would make those ungeneratable under `--component`. Without the flag nothing changes at
all, which is asserted rather than assumed.

The dependency's WIT is COPIED, never re-derived — only its own run knows its
`--wit-package` id and the reasons behind its `// unexported:` rows — into
`component/wit/deps/<dep>/`, whose `deps/` level is required (a flat sibling `.wit` is
read as part of this package and fails on package identity). It is an explicit
cross-crate INPUT, the same class as `--extern-import` reading `extern-interface/<dep>/**`,
and the copy's file-class comment says so in those terms; it keeps the dependency's own
provenance banner rather than being stamped with this run's, which is why the `deps/`
subtree is exempt from the header stamper.

The copy is also where every name comes from. The consumer's `use` targets, and the
`with:` rows the guest crate's `wit_bindgen::generate!` needs, are read out of the
dependency's WIT rather than reconstructed from its cddl: `wit_bindgen` matches those
keys against the file, and a `wit/deps` tree without the co-required `with:` map panics
the macro at the consumer's build naming a key nobody wrote.

Dependency values cross the guest boundary through a CBOR bytes seam — serialize on one
side, `from_cbor_bytes` on the other — which is fallible, so every door touching a
dependency type carries `result<…, string>`. That is the honest signature: the far side
can fail on a value this crate's own serializer produced when the dependency component
and the linked dependency crate disagree about a shape, a failure class that is
compile-time within one crate. An imported resource's `borrow<t>` lowers to a plain `&T`
rather than the `TBorrow<'_>` newtype an exported one gets, so the two glue templates are
separate.

A dependency type in a REPEATED parameter position is refused at generation, naming the
cause: `list<borrow<t>>` over an imported resource is legal WIT that wit-bindgen's Rust
backend cannot lower (E0506), so emitting it would hand the user a crate that fails to
compile inside a macro expansion. A signature naming a type the dependency's WIT recorded
as `// unexported:` is refused too, quoting the dependency's own reason verbatim — it
parses (the name is in the extern-interface export) and only the WIT seam knows there is
nothing to `use`.

The config key lands with the flag so every flag stays settable from a config file; the
`deps`-edge derivation is separate work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two facts the cross-crate seam rests on are macro-expansion failures, invisible to
anything that reads the emitted bytes: `wit_bindgen::generate!` PANICS on a materialized
`wit/deps` tree with no `with:` map, and an IMPORTED resource's `borrow<t>` lowers to a
plain `&T` rather than the borrow newtype an exported one gets. A WIT that resolves,
encodes and validates says nothing about either. So the emitted consumer crate is built
for `wasm32-wasip2` against a real generated dependency — three crates sharing one
serialization runtime, which is the shape every other cross-crate consumer here uses and
the precondition the bytes seam inherits. Nested cargo, memoized by the gate cache;
28 s for the whole suite on a cold scratch root.

That build is also why the fixture dependency now splits in two. The only shape whose WIT
projection FAILS — a bare reference to a generic extern base — is also not a rust type a
crate can hold, so a single dependency cannot both be compiled and carry an
`// unexported:` row. `dep/` is compiled and excludes nothing; `dep-unexported/` is
projected and never built.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s to decide

`--component-extern-wit` needs its own `:::info` block for the same reason every flag
does (the docs-contract gate asserts one), but the block leads with the two decisions a
reader actually faces rather than with the mechanics: which of the two dependency trees
the path names — `component/wit`, not `extern-interface/<dep>` — and why the flag is
opt-in at all, which is that a dependency with no component face has nothing to point at
and must stay generatable.

The rest is what a consumer cannot discover from its own build log: the `with:` map is
co-required and its absence panics the macro in the CONSUMER's build; dependency-typed
doors are fallible because the far side's decode genuinely can fail; and the two shapes
refused at generation each name their cause, so a future toolchain fix has something to
search for.

The config-file document gains the key in its two lists — the `<k>=<v>` sub-tables and
the path-valued keys that resolve against the config file — which is where its right-hand
side belongs: the tool reads that path itself, unlike the four manifest sub-tables cargo
resolves.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…o the map closure must not wrap it

A list whose element conversion can fail lowers to a `map(..).collect::<Result<Vec<_>, String>>()`,
and the closure body differs by element shape: a map ROW is rebuilt from parts each already
unwrapped with `?`, so the tuple literal owes the closure its `Ok(..)`, while every other element's
conversion already evaluates to the `Result`. Wrapping the second in `Ok(..)` collects a
`Vec<Result<..>>` inside a `Result` — E0308 at the consuming call, in a crate the user cannot edit.
The two are told apart by the ELEMENT TYPE, because the tuple branch is the only producer of the
rebuilt form.

Both directions carried it, so both are fixed together: a parameter of `[* any]` and a getter over
one are the same conversion mirrored.

The reason it survived is that no COMPILED fixture carried the shape. `component-core`'s `meta: any`
is the same fallible conversion in a NON-REPEATED position, where the question never arises, and
every repeated fallible element the corpus reached was a map row. So the fixture grows a `[* any]`
row rather than the suite growing an assertion about emitted text: this is a type error, and the
wasip2 build gates are what see one. Confirmed by reverting the fix under the new row — both build
gates fail.

The corpus snapshots move with the fixture: a twelfth field, its `AnyList` collection wrapper and
the serialization of both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ugh an accumulator, not a borrow in a list

`borrow<imported-resource>` is usable ONLY in a non-repeated parameter position. `list<borrow<t>>`,
`list<option<borrow<t>>>` and `list<tuple<k, borrow<t>>>` are all legal WIT whose Rust lowering is
E0506: wit-bindgen hoists one handle binding out of the lowering loop and reassigns it on every
iteration while a reference to it is retained. Measured unfixed from the pinned 0.57.1 through
0.60.0, the newest release, which is why the pin stays where it is.

So the borrow moves one level UP, out of the repeated position. Every parameter the ownership rule
would spell `list<borrow<t>>` is spelled `borrow<t-list>`, where `t-list` is a consumer-exported
accumulator the caller fills one element at a time; a map-shaped one takes `insert(k, v)` instead of
`push(v)`. Both fillers are where the CBOR seam runs — once per element — so the consuming
constructor or setter clones a SETTLED collection and is infallible, which is the honest signature
rather than a fallibility spread over a door that can no longer fail.

The alternatives lost on merit: `list<own t>` would consume the caller's handles at the ABI
boundary, the exact bug class the borrow rule exists to prevent, and `list<list<u8>>` would trade a
typed surface for nested bytes. The cause is named at every place the shape is emitted — the `.wit`
resource, the guest rep's doc comment and the projection's own docs — because a future toolchain fix
needs a stated trigger to revisit this.

RETURNS are untouched. Minting fresh handles is what a return does, so a collection getter keeps
`list<own t>`, which lowers cleanly; own-crate collection parameters keep `list<borrow<t>>` for the
same reason, since an exported resource's borrow was never the problem.

The rewrite is total rather than case-by-case: a `list` carrying a dependency handle at ANY depth is
replaced, and the replacement hoists its own element first, so a nested collection of dependency
types becomes an accumulator of accumulators rather than reintroducing the repeated borrow one level
down. One accumulator per distinct element SHAPE per interface — named after that shape, so two maps
sharing a dependency-typed key and differing in their value get two carriers rather than one name
with two incompatible `insert` signatures.

That name is derived, so it appears nowhere in the spec, and a rule converging on it is a collision
the user cannot see coming. It goes through the existing three-level detector — already one walk
over the projection — with the one thing the shared text cannot supply: what minted the name.

The re-entrancy invariant is unweakened. A filler materializes its element to an owned rust value in
its own statement before borrowing the accumulator mutably, and the consuming door does the same
with the settled collection, so no two guards are ever live.

Compiled, not only read: the shape's whole reason for existing is invisible to every WIT-level
oracle — a package spelling the collection directly resolves, encodes and validates just as happily
— so the cross-crate gate now builds BOTH consumers for `wasm32-wasip2`, the scalar one and the
collection one, off one dependency in one workspace. The dependency gains `@used_as_key` on `token`
because a consumer uses it as a map key: key-demand is a property only the dependency's own run can
satisfy, and the inference that would have derived it cannot see across the crate boundary.

This replaces the generation-time refusal that stood in for the shape, and deletes its pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…efused before anything is written

A dependency-typed value crossing the component boundary is serialized by one crate and
deserialized by the other, so the crossing preserves the value only while the two agree
about what CBOR they write and accept. A mismatch fails nothing — not generation, not the
build, not composition — it silently re-encodes on every crossing, which is the failure
class that costs the most to find. Config mode sees both ends of a `deps` edge, so it
refuses; a hand-written invocation sees one crate at a time and can only document the
obligation.

Scoped to edges that CARRY the seam: this crate emits a component and the dependency is in
import mode. On every other `deps` edge the dependency's types are reached by ordinary rust
linkage, so no bytes are produced at a boundary and none are parsed there — there is no
crossing to re-encode, and a message that explains itself in terms of crossings would be
attached to an edge that has none. Widening it would also newly reject configs that
generate correctly today. If posture skew across a plain `--extern-import` edge is a
problem too, it is a different one with a different mechanism and a different remedy, and
folding it under a component-flavored message would hide it rather than report it.

The axes are `RuntimeFlavor::equality_axes`, not a list of the seam's own, because it is
the same question at a second level: `[runtime]` asks which flags make two crates'
serialization contracts non-interchangeable in SOURCE, the seam asks it of BYTES. Each of
the three has a stake in both — the two encoding axes change what comes out, the depth
limit changes what is accepted, so a crossing the producer considers well-formed is one the
consumer rejects. A sibling list would be a second copy of a fact that changes, and a
fourth axis minted for the runtime would silently not reach it.

The seam predicate is shared with the graph derivation rather than restated, so the check
and the flags that create the seam cannot disagree about which edges have one — including
the case a derivation cannot produce, a hand-written `component-extern-wit` entry naming a
dependency whose own `component` is off.

Run over every crate rather than the selection, so a subset run rejects what a full run
rejects: whether an edge can mean anything is a property of the config.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ves its own two flags

The cross-crate values the component face needs are ones the config already holds, which is
the rule every other `deps` derivation follows: hand-maintaining them means two invocations
that must agree about a third crate's `output` and `lib-name`, and nothing checks that they
do.

`--component-extern-wit` takes the `--extern-wrapper-index` PATH FRAME, not the
`--extern-import` one, and the difference is invisible until somebody turns `--package-json`
on: the dependency's WIT lives INSIDE its component crate, so it moves one level down with
the nesting, while the extern-interface export it sits beside is emitted in every mode and
does not move. Both frames spell the same string in the unnested layout, so the wrong one is
right until it is catastrophically not — which is why the nesting test pins this value.

`--component-dep` names the dependency's RUST package. The guest glue holds a
dependency-typed value natively and converts it across the bytes seam, so that is the crate
the component manifest has to reach; the dependency's own component crate is wired by the
composer at the component level and never by cargo. That is the whole asymmetry with the
wasm manifest, which derives two packages per edge because its pass also emits
`use <dep>_wasm::…`.

Both are gated on the SEAM rather than on either crate's `component` alone, through the same
predicate the posture check uses, so the flags that CREATE a seam and the rule that refuses an
unsound one cannot disagree about which edges have one. A dependency with no component face
has no `component/wit` to point at and its types stay excluded from the projection, so neither
flag would name anything; where both sides do have one there is nothing to decide, since
import mode is the only shape in which such an edge means anything on this face.

The acceptance gate covers them by carrying the face rather than by asserting about it: the
fixture's `deps` edge now has `component` on both ends, and its consumer spec names a
dependency type in a collection, so the byte-identical comparison runs over an emitted
component crate whose WIT imports the dependency and whose glue routes both the scalar and
the accumulator shapes.

`COMPONENT_PACKAGE_SUFFIX` keeps its `#[allow(dead_code)]`, and the comment that promised
this derivation would read it is replaced by the reason nothing does: no derivation predicts
a dependency's component package, because nothing depends on one. It gains the reader it
should have had instead — the drift gate that holds a suffix constant against the manifest
template that emits it — so the one suffix with no derivation behind it is no longer the one
suffix nothing asserts against.

Also corrects the flag reference, which still described a dependency-typed collection
parameter as refused at generation; the accumulator replaced that refusal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SebastienGllmt and others added 21 commits August 5, 2026 02:51
…sidual

The entry was the layer's own spec — both variant families, the cheaper static
floor, the `@used_as_key` shaping note — and the layer is built
(`regen_over_prior_output_corpus` + its compile sibling, `7b21547d`), so the
spec text goes and what is genuinely future-facing stays.

That residual is the sweep's ONE emission profile. It generates `--wasm=true`
and nothing else, which is the profile both known trap instances lived in;
`--preserve-encodings` emits a whole file the sweep never sees
(`cbor_encodings.rs`) and json adds a tree of its own. The signal is written on
the dimension the deferred cost actually grows: not "someone wants more
profiles" but a SECOND trap instance in a file the default profile does not
emit — at which point the profile that produced it is the one to add, rather
than all of them.

The recur-first FIRED-triggers list drops the entry with it, since its trigger
is no longer an unbuilt work item.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
A cache-hit run of `regen_over_prior_output_corpus_compiles` still pays the
per-cell generation, the replace-block injection and the lockfile preflight, so
"159 s" alone reads as the price of a re-run when it is the price of a cold
scratch root. Measured ~90 s fully cache-hit (88 of 88 cells), on the same terms
its `component_corpus_compiles` neighbour states both numbers.

The `fast`-tier wall in tests/timings.json moved on its own sliding-window rule
during these runs; the digest and the spans derived from it are one commit, per
tests/README.md § "Measured gate durations".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
The sweep's first cut generated one profile, and the profile it did not generate
emits a FILE it does not: `cbor_encodings.rs`, one struct per rule that carries
encodings. A per-rule surface is precisely where a comment on a deletable row
would live, and nothing else looks for one there — so the cheapest legs (one
extra generation per fixture each) now sweep the default and preserve profiles
both. The edit leg stays on the default: a replace block costs three generations,
and its compile gate nested cargo per fixture.

Measured 55 s, up from 40 s, which keeps the gate at `local` with room. Counts
roughly double where they should: 1320 files scanned (was 577), 177 deletion
cells (was 89), 12 of them deleting a `@used_as_key` rule (was 6); the floors
follow. Green on the new surface — no trap in `cbor_encodings.rs`.

A secondary profile's GENERATION verdict is deliberately not this gate's to own.
`feature_corpus_compiles` gates that both ways through
`EXPECTED_GENERATION_FAIL`, where a listed pair that starts generating fails as
a stale pin; here a fixture that will not generate under preserve is a recorded
SKIP (today, `dsl_ignore`), so the ownership stays single.

The roadmap residual narrows with it: two profiles of four, and the edit leg's
one, with the trigger re-aimed at a sentinel in a file NEITHER swept profile
emits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…ll tier's wall follows

The cycle's new full-tier gate `regen_over_prior_output_corpus` records a warm median
of 55.0s (n=3) — its first, so the span that reported it as unmeasured now names a
number. The tier's own wall moves 33m4s -> 40m43s (n=16): the gate is new work in the
tier rather than a slowdown of existing work, and the per-gate medians either held or
moved within noise.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…e rest row's key domain become cells

Twelve `[[contain]]` cells, no new fixtures: each sub-batch's regression defense already lives
generator-side, and a cell's `example` IS its probe input.

- The `any`-arm POSITION axis (role.choice-member): a non-last bare `any` (unsupported, PERMANENT
  by decision — a green flip is a regression, per README § "Gotchas"), the last-position bare arm,
  and a tagged `#6.n(any)` in a non-last position. Position and tagging are the two axes that flip
  the verdict, and now each is a cell rather than a sentence.
- The fixed-value KINDs the enumeration still owed: a nint constant and a tag-wrapped fixed form as
  ARRAY-rep group-choice arms, a type choice whose fixed arms share a CBOR major type, and the nint
  MEMBER cell. Every one spells its DISPATCH PATH from the emitted deserialize — type-match for the
  two arm kinds, brute-force try-each-arm for `true / null / tstr` and for a last-position bare
  `any` — because the two sites emit independently and a kind proven on one certifies nothing about
  the other.
- The rest row's KEY-DOMAIN axis (role.occurrence-target): named-rule, `bytes` and `nint` domains
  supported, the float-containing and null-admitting domains rejected. The generator's boundary
  moved along this axis in 2026-08; until now no cell could state where it sits, so a consumer had
  no way to ask.

Probed at HEAD before authoring: the seven supported shapes generate, compile and round-trip under
the default and `--preserve-encodings` profiles, generate under the json flags, and their `--wasm`
crates check clean; the three rejected shapes exit 1 with the messages their generator-side pins
assert. Both oracles accept all twelve examples. No panic, no silent-wrong.

The source entries prune with the delivery: the `any`-arm entry and the rest-row key-domain entry
retire whole; the fixed-value KINDs entry narrows to its one residual, the FLOAT kind in both
positions. The arm-classification entry stays — enumerating arm positions is not the same act as
getting their rejection evidence, and its signal is still an arm-position reject vector.

Verdicts land on the next evidence mint; the new cells render `?` in the grid until then.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
… a new oracle gap

The cycle-13 registration chain over 0fb4fd1's cells, everything downstream of the two full
verify.ts passes:

- Evidence: all 12 verdicts minted exactly as the pre-probes predicted — 9 supported (round-trips,
  wasm round-trips, json+preserve emission green), 3 graceful refusals, both oracles corroborating
  every example. Eight supported rows carry fresh decode-foreign vectors; the nint member cell adds
  the hand constraint pair (accept 8120 / reject 8121, "Expected fixed value -1 found -2" verbatim
  from the decoder), taking the fixed-value MEMBER family to 16 cells and the enforcement spans to
  69 vectors over 49 rows.
- The projections follow: reject-catalog snap (+3 rows, all error (graceful)), matrix_supported
  (+9) / matrix_reject (+3) fixtures, COVERAGE.md (the occurrence-target memberkey.type1 and
  prelude.any grid cells resolve ? -> half-supported), the generated Limitations block, and the
  status-header spans (286 annotations).
- The arm-classification entry's reopening signal did NOT fire, now verified rather than reasoned:
  21 arm-role catalog rows post-mint, zero reject vectors, zero class= — the mint writes accepts
  and re-certifies pre-existing hand pins only, and the one hand vector added here sits on a MEMBER
  role. The floor-scope pins for the three new choice rows record their own limits, including the
  same-major blind spot ({3,7} satisfiable by one major-7 accept when true and null share the
  major); ruled comment-sufficient — the decode-foreign floor is corroboration-side by the
  catalog's contract, and per-arm evidence is execution-gated in the emitted round-trip (the row
  carries f5 AND f6 regardless).
- The tagged-any cell's note stops claiming a pin that never executed the shape: the two robustness
  fixtures spell the BARE arm only, and the pins that DO execute #6.n(any) non-last are named
  instead (tagged_any_arm_allowed_in_any_position; choice_tagged_any in tests/any-positions).
- The named_key row minted pinned_reason-vectorless: gap #11 exactly (named-rule key domain, every
  candidate ruby=0 rust=1), now recorded as that gap's first MATRIX resident with its inline-key
  siblings as the controlled pair. Separating the pair surfaced a NEW oracle gap — #13,
  string-typed rest-row keys in a MIXED map demand an entry (* read as +): {1: 692} fails
  "map requires entry key of type bytes" against { 1: uint, * bytes => any } while uint/nint
  domains pass, the rest-entry-bearing instance passes, and the pure table keeps its empty-map
  pass; ruby accepts throughout. Differential grid and upstream-report sketch in
  draft/rust-cddl-string-key-mixed-map-rest-occurrence-gap.md; catalog cost is bytes_key's two
  zero-rest-entry accept candidates, dropped by the two-oracle gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
query_q4_directional's EXPECTED_ENFORCE_YES is the deliberate-addition fence for the enforce=yes
green set; the nint member cell joined that set when its hand constraint vector landed, so the pin
gains the id. Caught by the fast tier on the evidence commit — the README's 15 -> 16 prose count
moved with the vector, but this pin is the mechanical half of the same fact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
… compiled

`fuzz_compile_rot` proves the byte-fuzzer's targets still COMPILE; nothing ever ran them, so a
panic that only a live libFuzzer input triggers sat outside every tier. `fuzz_bounded_run` (full
tier, registered after the compile-rot gate) runs both targets sequentially over the local corpus
for `FUZZ_BUDGET_S` seconds each (default 120) at `-rss_limit_mb=2048`, and fails naming the
libFuzzer artifact to replay. One process at a time: the peak the tier must bound is one
libFuzzer RSS plus the cargo build that precedes it, and no factor scales with core count.

Three deliberate properties, each recorded at the gate:
- NOT gate-cached. A randomized exploration is not a pure function of the tree's bytes, so a
  content-hash hit would skip the only thing the gate does. Nothing else records the exemption:
  the closure audit traces ONE cached cell (`CLOSURE_AUDIT_GATE`) and enumerates no gate set.
- Missing nightly / cargo-fuzz is a FAIL naming the install commands, never a skip — the gate is
  full-only, and a silent skip in the tier that ships the guarantee voids it (`runNoStdCheck`'s
  posture); there is no softer tier for it to be in, hence no softening arm.
- No `requires:` edge on `fuzz_compile_rot`. `ensureFuzzGenerated` is shared, so either gate
  provisions `fuzz/generated` itself and `--only fuzz_bounded_run` asserts exactly what a whole
  tier run does rather than passing vacuously.

The first real run is RED, and the gate is right to say so. 480 s over `from_cbor_bytes`
(1929-file seed corpus, ~7 080 exec/s, peak RSS 653 MiB) found a preserve-encodings FIDELITY
violation in `NonOverlapBasicNotBasic`: `bytes .cbor basic_arr` accepts a byte string whose
embedded CBOR does not consume the whole payload, then re-encodes only the consumed prefix.
Hand-derived 6-byte reproducer: `81 44 82 09 60 00` re-encodes as `81 43 82 09 60` — the trailing
`0x00` is dropped. Disposition is a maintainer call (a fidelity violation is tier-1 class), so
nothing is ledgered, pruned or retired here; on a corpus that has seen it, the default 120 s
budget re-finds it in ~5 s, so the full tier fails this gate until the bug is fixed.
`from_cbor_bytes_recursive` ran clean over the same 480 s: 54 768 212 execs, peak RSS 601 MiB,
no crash, no artifact.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…re-encodes to itself

`bytes .cbor T` says the byte string IS T's encoding. The embed read the payload and stopped —
bytes left over inside the byte string were accepted, and since nothing held them, the value
re-encoded to the consumed prefix ALONE. Over-acceptance on every profile, and under
`--preserve-encodings` a fidelity violation on top: an ACCEPTED input round-tripped to different
bytes, in a crate that compiled and passed every round-trip test, because round-trip tests only
ever feed encodings the serializer itself produced.

Found by the byte fuzzer's second oracle on the first bounded run of `fuzz_bounded_run` (adb165a)
— the fidelity assert, not the crash boundary. Minimal reproducer, hand-derived from the libFuzzer
artifact: `81 44 82 09 60 00` re-encoded as `81 43 82 09 60`.

The payload is now required to be exhausted, raising the SAME
`DeserializeFailure::CBOR(cbor_event::Error::TrailingData)` the top-level `from_cbor_bytes` raises
for the same fact — one spelling, so a consumer matching on trailing data at the top level matches
it here too, and the enclosing annotation still names the member.

One emission site serves every `.cbor` spelling (`generate_deserialize`'s `CBORBytes` arm), so the
rule body and the member expression were wrong together and are fixed together — both pinned by
`structural_rejects` in `tests/core/tests.rs`, red-first on the pre-fix emitter. Completeness
established over the OUTPUT rather than by grepping the emitter: all 154 embed sites across the
blessed snapshots and the exported crates reach the check at their own block level, none with an
early `return` that could bypass it.

The check follows the payload's code, which is only expressible where that code is a complete
STATEMENT; at a terminal position (a block's tail, a tuple element) the payload value is bound
first and the binding yielded. Both spellings are emitted rather than always binding, so consumers
do not get a `let x = x_payload;` rebinding that says nothing. The binding also RESTORES the check
for the c-style-enum payload sweep, whose `return Ok(variant)` would otherwise have jumped past it.

Snapshot churn is 30 files, audited by diff class: the new check, the payload binding, and rustfmt
re-indentation around them — no other emitted token moved. `docs/docs/output_format.mdx`'s
trailing-bytes paragraph said nested decoding was deliberately unaffected; that sentence was the
documented form of the bug and is now the documented form of the rule.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…gistration cost

The first full-tier run over cycle 13's cells failed decode_conformance_replay on
contain.choice-member.prelude.any.last: all ten wrong_major header mutants DECODED Ok. For this
row that is the spec's own semantics, verified before ledgering rather than assumed:

- The acceptances reach the arm the spec says accepts them: probed on the generated crate, all
  seven non-text major shapes decode to the A::Any(AnyCbor) variant — the last-position bare `any`
  catch-all under forced-backtracking dispatch — never A::Text, which would have been the tstr arm
  mis-dispatching mutated bytes and a real over-acceptance finding. The major-3 control still lands
  on A::Text (first match wins).
- No trunc_head mutant is in the failing set (all ten trunc_head tests ok in the gate's own
  output) — a trunc_head acceptance is ill-formed by construction and would be a finding always.

So (row, wrong_major) joins HEADER_MUTANT_ACCEPT_SKIP beside its feature-row precedent
(prelude.any, same class at the rule position), with the reason naming the accepting arm and the
probe. The entry is (row, label)-wide because every committed accept samples the tstr arm (the
mint's shape), so every flip lands on an any-only major — exact, not a suppression. The ledger's
stale guard retires it if the row's shape ever changes. Every future any-typed catalog row owes
this same entry on its first tier appearance; the cycle record says so.

Rides along: the backwards-compatibility note for cff8516's `.cbor` exhaustion change in
docs/docs/output_format.mdx — the acceptance change is exactly the class the docs convention
carves out for historical notes (pre-2026-08 generators accepted-and-dropped trailing payload
bytes; re-generated crates newly reject them; serializer-produced data is unaffected).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…ischarged in one sweep

Two consecutive full-tier runs each died on a DIFFERENT missed registration obligation of cycle
13's twelve cells — fail-fast surfaces one per run, so this stops discovering them serially: a
complete sweep of every leg obligation for every new cell, enumerated from the gate's own ledger
registry (every `const` decode_conformance_replay declares — PRESERVE_SKIP, EXPECTED_MISMATCH,
ENCODING_VARIANT_SKIP, DOUBLED_LOCATION_SKIP, HEADER_MUTANT_{ACCEPT,LOCATION}_SKIP,
JSON_SURFACE_SKIP, WASM_SURFACE_SKIP, the four floors), not from a keyword grep. Full table:
draft/burndown2-cycle13-registration-sweep.md.

Discharged here (run 2's failure): contain.occurrence-target.memberkey.type1.open_struct_bytes_key
joins JSON_SURFACE_SKIP. Verified to be the decided boundary, not a new shape: the error is the
strict-fail the delivered posture documents ("open struct-map rest key has no JSON member-name
image", docs/docs/output_format.mdx § "Typed key domains in JSON"), the cell's own note already
marked the row as where the flattened-rest JSON convention stops, and the § findings non-string-
map-key entry carries the decided precedent verbatim — it now also names this cell among its
surfaced-by sites. The nint sibling is deliberately NOT listed (nint has a member-name image, per
the error's own admitted list); a json failure there next run is a finding, not a registration.

Every other (cell x leg) obligation is answered concretely in the sweep table: four rows have
nothing to replay (three reject fixtures, the gap-#11-pinned named_key), and every remaining cell
x leg is either LEDGERED (any.last wrong_major, d1997e1; bytes_key json, here) or explicitly
"should work" with the reason — notably tag.any_non_last owes NO header entry because its accepts
evidence majors 3 AND 6, so every derived flip lands on a major both arms reject with a located
error.

Verified by the gate in isolation at this tree: cargo test decode_conformance_replay --ignored ->
ok, 674 s, zero failures beyond the two pre-existing derived pair-map suppressions. A third
full-tier failure in this gate on these cells would now be a real finding.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…decode replay's grows with its catalog

`fuzz_bounded_run` records 4m3s (n=3), its first — the span that reported it as
unmeasured now names a number. `corpus_decode_replay` moves 15m36s -> 18m45s (n=20):
the cycle added twelve catalog rows with real vectors, so the gate is replaying more
per run rather than replaying the same work more slowly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…t session finds them

The TDD pass over everything this cycle caught by reading, probing or burning tier runs — each
lesson filed in the system that owns its class:

- The serial-registration cost becomes a FIRED work item (TESTING_ROADMAP § Next work items,
  now item 1): decode_conformance_replay aggregates failures within a row but panics at the first
  failing ROW, so twelve new cells cost two ~40-min full-tier runs for two independent ledger
  obligations. Fix shape recorded (route per-row failures into the end-of-gate failures
  collection the stale guards already use); the cycle's sweep table stays the authoring half.
  List renumbered (positional citations are banned tree-wide, so nothing dangles).

- The `.cbor` doc sentence joins the docs-conformance decline as its FOURTH recorded instance —
  and the sharpest, because doc and behavior AGREED: "(Nested/embedded decoding — e.g. bytes
  .cbor T — is unaffected)" was a TRUE sentence about a DEFECT, which any docs-vs-behavior
  harness passes by construction. The decline is not reopened: the layer that caught it is a
  SPEC-side oracle (the fuzz fidelity leg, now standing), and the instance adds the zero-cost
  authoring rule instead — a limitation/boundary sentence in docs names its provenance (decided-
  posture record or findings entry), so an anchorless boundary reads as an undecision wearing
  decided clothes. Reopening signal for the rule: a second anchorless boundary sentence found to
  have documented a defect as intended, after the rule was in force.

- The kill-by-PID rule in AGENTS.md learns the case where its own precondition is unsatisfiable:
  when agents share one harness, ancestry attributes nothing (proven 2026-08-04 — a tier run
  nearly killed on a wrong ancestry read; the sub-agent refused on better evidence). Attribution
  is by INVOCATION RECORD (disjoint self-log name classes, the log's own banner, who issued the
  command), and shared ancestry means identify-then-coordinate, never kill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…unt inventory

The roadmap's fired work item asked for aggregation that already exists. Probed at HEAD by
reading both gates: every per-row, per-leg failure in `decode_conformance_replay` and
`corpus_decode_replay` is pushed into one `failures: Vec<String>` and panicked ONCE at the end —
no `panic!` or `assert!` sits inside either row loop (the asserts around them are the pre-loop
catalog/stale-pin registration guards and the post-loop vacuity floors, all outside the walk).
Cycle 13's two-run cost is explained by CONSUMPTION, not gate shape: run 1 failed with
26 problem(s) — 10 `any.last` header `wrong_major` + 8 `bytes_key` json + 8 the same row's wasm —
and run 2 with 16, a strict SUBSET of what run 1 had already printed. Each problem embeds its full
captured cargo-test output, so the 10 same-row header problems occupied ~1600 lines before the
second family's first line appeared, and the session discharged only the family it read.

So the residual is legibility, and that is what lands: `replay_failure_summary` groups failures by
the leading `"{row.id}: "` prefix (prefix-less stale-guard messages group under their own truncated
first line), and both final panics now head their details with the inventory —

  decode-conformance replay found 26 problem(s) across 2 source(s):
    contain.choice-member.prelude.any.last — 10
    contain.occurrence-target.memberkey.type1.open_struct_bytes_key — 16

in first-appearance (row-walk) order, so related legs stay adjacent. Display-only: no leg, no
collection and no pass/fail semantics change, and the block is reachable only on an already-failing
run. The leading texts "decode-conformance replay found" / "corpus decode-conformance replay found"
are unchanged verbatim — only the count line is extended.

`replay_failure_summary_groups_by_row` (a plain `#[test]`, no crate build) pins the helper on cycle
13's exact shape: 26 synthetic multi-line failures over two rows plus one stale-guard message → 3
groups, counts 10/16/1, first-appearance order, every summary line short and free of captured
output. Its name deliberately carries neither gate's name — check.ts runs both by SUBSTRING filter.

TESTING_ROADMAP's item is removed rather than checked off (list renumbered; positional citations are
banned tree-wide, so nothing dangles). No committed doc stated the per-row-panic claim — the
decode-direction conformance sections of tests/README.md were read end to end and describe the legs
and ledgers without asserting a failure-reporting shape, so nothing was corrected there; the
rationale now lives durably in the helper's doc comment.

Verified: `cargo test --bin cddl-codegen replay_failure_summary` green (1 passed, 1193 filtered —
the name matches exactly one test), and `bun run check.ts fast` PASS, all in-tier gates green,
wall 38.2s. The local and full tiers remain unrun and are the orchestrator's to run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…lent again

Two arms of `try_defer_wrapper` decline BEFORE any index is consulted — the
ident≠structural screen and the R3c constituent screen — so the class they mint
can carry a name a dependency's `--extern-wrapper-index` also lists, and the
defer seam has no way to see it. That is the same duplicate-`#[wasm_bindgen]`
configuration `warn_rule_declared_table_shadows_index` announces, reached by
paths that announced nothing.

The honesty check therefore lives at the one seam every LOCAL mint passes:
`warn_local_mint_shadows_index`, called from `record_collection_wrapper` and
keyed on the EMITTED ident rather than on the reason a particular arm declined.
That closes the family at once instead of chasing `return false` sites, and it
covers any future arm that declines before consulting the index. It shares
`deferred_warned` with the existing warnings, so a rule-declared table still
warns exactly once with its more specific text; it skips the
`requested_scope_override` mint by intent (a hosted wrapper's name is the
REQUESTING consumer's choice, arbitrated by the request sidecar, not this
crate's); and it is unreachable with no index flag, so flag-off byte AND stderr
identity hold — verified by generating the fixture both ways against a stashed
build.

Probed at HEAD before coding, and the recorded shape was half wrong: the
roadmap's spelling `arr_idx_foo_list = [* idx_foo_list]` never reaches R3c at
all — its structural name is `IdxFooListList`, so the ident≠structural screen
declines first — while `idx_hash_list = [* idx_hash]` over a consumer-owned
element does take R3c. Both mint a dep-indexed name silently, which is why the
fix is seam-level rather than branch-level, and both are now pinned by
`extern_wrapper_index_local_mint_under_indexed_name_warns` over the new
`inputs_nested` fixture: warning texts verbatim, the classes and their own-index
rows asserted unchanged (warn-only), the deferring sibling's unification warning
asserted to still fire beside them, and the consumer wasm `cargo check` floor.
The fixture is a new sibling dir rather than an addition to `inputs_named`,
whose `!index.contains("IdxFooList")` assertion the substring `ArrIdxFooList`
would falsify.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
… and becomes an enumeration

Every collection wrapper a spec implies has an emission MODE, and the ~20
committed pins over that space are incident-shaped: each records the exact
configuration of one past escape. What none of them gives is the grid, and the
escapes on record were never in the primary wrapper — they were in a COMPANION
(a table's synthesized keys-list, a restricted wrapper's loose `try_from`
source) or a POSITION (a named-rule reference, a non-root declaring scope) that
one mode happened not to walk.

`src/tests/wrapper_participation_tests.rs` is that enumeration.
`PARTICIPATION_TABLE` is the grid AS DATA over MODE × SHAPE × POSITION; each row
states its expected outcome (Defer / Borrow / Host / LocalWarned(<which
warning>) / LocalSilent(<why silence is correct>)) and, where an existing test
already pins it, that test — those rows are REFERENCED, never rebuilt, so the
four always-on per-mode sweeps generate exactly the rows nothing else covered.
Each row's CDDL is derived from its own axes and each owns a distinct element
ident, so one generated crate carries a whole mode and a new shape or mode is
one table row rather than a new function. `..._table_is_complete_and_live` is
the grid's own guard: rows unique, every mode covering every shape that
participates in it (the one documented gap — a table RULE cannot be requested —
spelled rather than silently absent), and every `pinned_by` resolving to a test
that still exists, so a referenced row cannot keep reading as coverage after its
pin is renamed away.

Two participation facts are ENCODED rather than assumed, and one of them earned
its keep immediately: a reject set can be HOSTED but never DEFER, so under
`--extern-wrapper-index` an indexed name is a collision only the mint-seam
backstop can announce — the row is green solely because of the previous commit.
The other is that the name-only index is flavor-SAFE by construction, which
makes a preserve table an ordinary shape row instead of a hazard cell.

Floors are `#[ignore]`d and batched per (mode, floor), gate-cached per
generated-crate content hash: `wrapper_participation_floors` runs a `cargo
check` of the standalone Local column plus a real wasm32-unknown-unknown link of
the index and workspace columns against the committed wasm-clean dep pair, GREEN
only (the RED leg is already demonstrated once by
`extern_wrapper_index_defers_to_dep`; verified non-vacuous here by regenerating
the same spec flagless, which fails that link with 20 duplicate-symbol errors).
What the link legs add is the POSITION crossing — a named-rule declaration, a
by-name reference and a non-root scope had never reached a wasm32 link.
`wrapper_participation_host_floor` checks the HOST crate a `--wrapper-requests`
run emits.

That host floor found a live defect on its first run, so it ships NARROWED and
says so: a requested NonEmpty wrapper whose loose `try_from` source is itself
co-hosted makes `requested_collections.rs` import that source from
`crate::generated`, where it is not — it is in that same file. E0432, at exit 0.
It is the co-hosted self-import class
`workspace_requests_cohosted_keys_list_no_self_import` closed for the keys-list
and left open for this second companion, and the committed request cells cannot
see it because their dep spec produces the loose source itself, which makes the
same import path correct.

The roadmap entry is retired into its two honest successors: that finding as a
DUE item carrying its reproduction, and a single-PROFILE residual whose
reopening signal is a placement decision differing between two profiles for one
row — something a consumer regenerating one spec twice can measure, which the
entry does not already record evidence for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…rofile sweep grows with the corpus

`regen_over_prior_output_corpus` records its first warm median at 1m40s (n=3).
`feature_corpus_roundtrips_nondefault_profiles` moves 7m45s -> 9m58s (n=20): the
corpus gained fixtures across the last cycles, so the sweep covers more per run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…findings ledger into the gotchas

The end-of-burndown holistic docs pass, executing the maintainer-ruled deferral recorded at cycle 11
close-out: the @custom_json can't-compile-standalone entry and its non-string-map-key sibling are
DECIDED postures — a contract boundary and a kept boundary — so § findings' own intro ("a defect or
a missing capability") mismatched them. Both are now current state in cddl-matrix/README.md
§ Gotchas, phrased as what the generator does today rather than as candidates, with the observable
that would make each a finding again stated as the boundary's own bound.

Every pointer that reached the findings entries retargets in the same change: the
JSON_SURFACE_SKIP / WASM_SURFACE_SKIP ledger citations in both replay gates (matrix and corpus),
their header comments' resident-citation contract (owning record: a decided-posture gotcha or a
findings entry), tests/README.md's json/wasm-surface-legs resident description, and the
containment-cell registration recipe's step-7 wording. The ledger instructions that route REAL
decoder gaps to § findings (ENCODING_VARIANT_SKIP and the variant-failure message) are unchanged —
that is still where defects go.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…in two stale homes

The .default / range-bound / .cbor-head control-arm aborts were converted to graceful refusals in
12c9abc, which updated current_capacities.mdx and TESTING_ROADMAP but left two other homes
describing the aborts as live — the classic finding-ledgered-in-two-homes staleness the holistic
pass exists to catch (probed at HEAD: all three robustness rows record `error (graceful)` and
KNOWN_CLOSURE_BREACH is an empty slice):

- cddl-matrix/ROADMAP.md § findings still carried the "Three control-operator arms ABORT
  (exit 101)" entry as a candidate fix. Pruned outright: the refusals are the delivered remedy,
  pinned by the robustness catalog and documented in current_capacities.mdx, so nothing future-facing
  remains.
- tests/README.md's refused-name-closure sibling paragraph still read "The pin list is NOT empty"
  over the same ten .default cells. It now records the empty-at-HEAD state and how it got there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
…r entry that owns it

The one transparent-alias wire-facts carve-out is documented in current_capacities.mdx as a
limitation with a workaround but named no tracking artifact — the anchorless-boundary-sentence
class the docs-conformance decline's fourth instance added an authoring rule for (a docs sentence
stating a limitation names its provenance). It now cites the owning findings entry by exact title,
the same citation shape the byte-string-literal limitation already uses.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JYLwxUHShu3rXopnyHjnRd
Bumps [clap](https://github.com/clap-rs/clap) from 4.6.1 to 4.6.6.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](clap-rs/clap@clap_complete-v4.6.1...clap_complete-v4.6.6)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.6.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file rust Pull requests that update rust code labels Aug 10, 2026
@dependabot @github

dependabot Bot commented on behalf of github Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting @dependabot ignore this major version or @dependabot ignore this minor version. You can also ignore all major, minor, or patch releases for a dependency by adding an ignore condition with the desired update_types to your config file.

If you change your mind, just re-open this PR and I'll resolve any conflicts on it.

@dependabot
dependabot Bot deleted the dependabot/cargo/clap-4.6.6 branch August 18, 2026 23:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant