--- name: compiler-codegen description: "Rust compiler pipeline, template codegen (VDOM/IDE), CodeTransform, cached directives, strict slots, IDE error recovery, style preprocessing, CompileTarget, compiler authority/policy/demand/admission" --- # Compiler & Codegen Compiler authority, policy, demand, and admission: **normative** text is the `compiler-architecture.md` contract, a DAG asset owned by the TAMA controller (not a file in this repository). The skill file [`references/authority-policy-demand.md`](references/authority-policy-demand.md) is an operational pointer only. The combined carrier-compiler registry remains a live migration seam, not the ratified owner. `DefaultCompilationContractId` is 1:1 with live `ProductKind` (no `facts` dump). `compile_bundle` is a combined product pass, not a third bus. Cheap Default facts are `FrameworkSemanticAuthority` over admitted parse only. ## Rust Compiler Architecture AST-based pipeline. `compile()` orchestrator drives a linear 5-phase pipeline: ``` Vue SFC Source | [Tokenizer] byte-level SFC tokenization (tokenizer/byte.rs) | [Parser] builds arena-based template AST + extracts script/style blocks (parser/) | [Style] typed Vue/Svelte rewrite planning over StyleSyntaxIr | [Script] macro expansion, binding extraction, component wrapper (script/) | [Template] render function codegen -- VDOM or Vapor backends (template/) | [Compile] orchestrates the above, applies CodeTransform, emits output (compile.rs) ``` **Module overview:** ``` compile.rs # Pipeline orchestrator, options, result types tokenizer/ +-- byte.rs # Zero-copy byte-level SFC tokenizer (production) +-- helpers.rs # Tokenizer utility functions +-- types.rs # Event, QuoteType parser/ +-- mod.rs # Syntax state machine (tokenizer events -> AST) +-- types.rs # RootNodeScript, RootNodeStyle, RootNodeTemplate ast/ +-- mod.rs # TemplateAst (flat arena with O(1) navigation) +-- builder.rs # TemplateAstBuilder (incremental AST construction) +-- types.rs # AstNode, ElementNode, NodeId, pre-computed flags script/ +-- mod.rs # generate_script() entry point +-- process.rs # Script setup processing, companion script merging +-- macros.rs # defineProps/Emits/Model/Slots/Expose/Options +-- css_vars.rs # _useCssVars() injection for v-bind() in styles template/ +-- oxc/ # OXC expression parsing for template bindings | +-- mod.rs # parse_template_expressions() | +-- scope.rs # LexicalScopes frames, LexicalScopeId handles, ActiveScope | +-- types.rs # OxcParsedAst, OxcParsedElement, OxcParsedExpression +-- code_gen/ # Render function codegen +-- mod.rs # generate_template() entry point +-- walker.rs # DFS tree walker (shared by all backends) +-- types.rs # TemplateCodeGen trait, CodeGenOutput +-- binding.rs # BindingResolver (_ctx./$setup. prefix resolution) +-- shared/ # Shared codegen helpers +-- vdom/ # VDOM render function output (_createElementVNode, etc.) +-- vapor/ # Vapor mode output (_template, _renderEffect, etc.) ide/ # IDE codegen: TSX or JSX+JSDoc (for LSP/TSGO type checking) +-- mod.rs # generate_ide_template() -- Vue template -> valid JSX; IdeScriptOptions, IdeTemplateOptions +-- script.rs # generate_ide_script() -- script block -> TS or JS+JSDoc wrapper +-- script_recover.rs # Token scanner for macro binding recovery from broken script tails +-- condition.rs # v-if/v-else-if/v-else condition chain codegen +-- template/ +-- mod.rs # walk_element/walk_node, cached directive removal, ref conversion +-- directives.rs # v-if -> ternary, v-for -> .map(), v-show -> style +-- props.rs # :prop -> prop={}, @event -> onEvent={}, v-bind spread style_planner.rs # Vue authored-v-bind, CSS Modules, and plain-CSS scoping stages css/ +-- mod.rs # legacy processStyle/CSS-modules compatibility surface +-- prepass.rs # retained until the NAPI/provider cutover +-- scoped.rs # retained until the NAPI/provider cutover +-- modules.rs # CSS Modules: hash class names +-- walk.rs # String-level CSS selector walking +-- types.rs # ProcessStyleOptions, ProcessStyleResult code_transform/ +-- code_transform.rs # Chunk-based deferred mutation engine (MagicString equivalent) +-- chunk.rs # Chunk types (Original, Overwritten, Inserted, InsertedMapped) +-- source_map.rs # Source map generation from chunk positions utils/ +-- oxc/ # OXC parser utilities | +-- bindings/ # Expression binding extraction | +-- vue/ # Vue-specific OXC helpers (macro syntax, v-for, v-slot) +-- vue/ # Vue runtime helpers (tag detection, patch flags) ``` ## Arena-Based Template AST Parser builds a flat `Vec` arena with O(1) navigation: ```rust pub struct TemplateAst { nodes: Vec, // flat arena root: RootNodeTemplate, } pub struct AstNode { kind: AstNodeKind, // Element | Text | Comment | Interpolation parent: Option, // O(1) parent lookup index_in_parent: usize, // O(1) sibling lookup } ``` `ElementNode` pre-computes metadata during parsing to avoid re-scanning in codegen: - `tag_type`: Element / Component / SlotOutlet / Template - `prop_flag`: Bitset of prop characteristics (has class, style, spread, etc.) - `children_flag`: Bitset of children characteristics (has text, elements, v-if, etc.) - `children_mode`: Enum for codegen branching (Empty, TextOnly, SingleElement, Mixed, etc.) - Cached directives: `v_condition`, `v_for`, `v_slot`, `v_once`, `v_ref` ## Template Lexical Scopes (`template/oxc/scope.rs`) `parse_template_expressions` is the ONE producer of template lexical scope, built in its existing forward pass over the node arena: - Each `v-for` alias list and each `v-slot` parameter list opens one persistent frame in `OxcParsedAst::scopes` (`LexicalScopes`) holding ONLY the names that list declares, linked to its enclosing frame. A list that declares nothing opens no frame. - Every node gets a `LexicalScopeId` handle: `OxcParsedAst::children_scope(id)` is what the node's children see; `scope_of(id, ast)` (the parent's children scope) is what the node itself sits in; `OxcParsedElement::props_scope` is the element's props / dynamic slot name / `v-slot` value scope (own `v-for` aliases visible, own slot params NOT). `ide_recovery_scope` on a broken IDE expression is a handle too. - While parsing, expressions resolve names through `ActiveScope`, a multiset the pass moves between frames incrementally (leave/enter only the frames that differ). `BindingContext::within` and the `v-for` / `v-slot` binding helpers read it in place through `verter_parser`'s `EnclosingScope` trait. Receiving rules: query names through a handle (`LexicalScopes::declares`, `declares_completion_of`, `own_names`) or the shared `EnclosingScope`; never flatten a handle's inherited names into a per-element / per-expression list, never copy a parent's aliases into a nested `v-for` scope, and never walk ancestors to rediscover a node's scope. Exact lexical identity and order are the frames' (source order within a frame, innermost frame first along a chain). ## CodeTransform (Deferred Mutations) All codegen phases use `CodeTransform` -- a chunk-based deferred mutation engine: ```rust let mut ct = CodeTransform::new(input, &allocator); ct.overwrite(start, end, replacement); // deferred ct.prepend_left(pos, content); // deferred let output = ct.build_string(); // single-pass concatenation ``` Key features: - `cursor_hint`: Accelerates forward-progressing access patterns to amortized O(1) - `output_delta`: Incremental length tracking avoids full scan - Pre-allocated chunk capacity: `source_len / 13` (empirically tuned) ## CodeTransform Is the Single Source of Truth (CRITICAL) **All modifications to generated code MUST go through `CodeTransform` operations** (`overwrite`, `prepend_left`, `append_left`, `move_with_suffix`, etc.). Never apply string replacements, regex transforms, or manual splicing to the output of `build_string()` or to content produced by a `CodeTransform`. Post-hoc string manipulation breaks sourcemap accuracy: `CodeTransform` generates source maps by tracking chunks (Original, Inserted, Moved, Overwritten). Modifying the string after the transform makes byte offsets in the source map no longer match the content, causing position mismatches in the LSP (e.g. hover landing on the wrong token, go-to-definition jumping to wrong locations). **Correct:** Use `ct.prepend_left(pos, ".ts")` to insert text at a known position -- chunk list and source map stay consistent. **Wrong:** Call `content.replace(".vue'", ".vue.ts'")` on the built string -- the source map still reflects the pre-replace byte offsets. The rule has NO scoped exceptions: the Svelte scoped-CSS renderer (`crates/verter_compiler/src/svelte/runtime/css/render.rs`) edits the original component source through the shared `CodeTransform`'s checked (`try_*`) operations -- whose insertion-affinity chunk model carries the `magic-string` semantics the official `svelte@5.56.10` `render_stylesheet` depends on (content-only `try_update` preserving the replaced range's first-chunk boundary insertions, left/right insertion affinity with per-affinity stacking, `try_remove` clearing interior insertions; pinned by `code_transform/edit_semantics_tests.rs`) -- and generates the css source map (`css.map`) from the SAME transform that built `css.code`. The guard `svelte_css_renderer_uses_code_transform` (`crates/verter_compiler/tests/`) asserts the renderer stays on the shared transform and bans any private edit buffer from the css matcher/render tree. ## Compile artifact schema `assembly::CompileArtifactSet` owns the immutable terminal schema for already-produced compiler artifacts. Its constructor validates facts only; it does not parse, compile, assemble, or publish. Artifact rows keep the caller-supplied contribution/plan order (identity bytes are not an ordering key); terminal JSON still sorts artifacts by id so the wire stays identity-canonical. `CompileArtifact` inputs are mutable builders, while a validated set exposes immutable accessors and is the only schema container implementing `Serialize`. Artifact lineage is the canonical tuple `(SourceUnitId, ProductKind, LanguageId, producer-owned slot name)`. Revision, source content, output availability, and provenance are neighbouring facts. Each artifact names its primary source unit, an `InputBasisId`, a producer `ResultContractId`, and all contributing units. Typed artifact relations must target another artifact in the same set. Duplicate artifact/source identities, missing references, and inconsistent revisions of one source fail closed. Empty available text differs from unavailable content. `ArtifactSourceUnit` binds each input to its registered SFC-absolute byte `Span`; external inputs carry their own source identity and absolute extent. `QualifiedArtifactMap` distinguishes source-projection and runtime-source-map families, names its generated artifact and nonempty input-space set, and carries the exact generated `ContentId` and observed `InputBasisId` so maps from older output bytes or inputs fail closed even when artifact lineage is unchanged. It carries typed generated ranges separately from authored `Span`s. Map sources must be part of artifact provenance; ranges must fit their spaces, generated endpoints must be UTF-8 boundaries, and ambiguous overlapping generated mappings fail. Unmapped generated text has no authored segment. An absent family is not an implicit identity map. These mappings describe authored anchors and do not assert byte-for-byte fidelity or interpolate between differently sized ranges. Terminal JSON uses schema version 1, explicit `utf8-bytes` coordinates, hex-encoded full canonical identities, sorted objects/sets and generated-order segments. JSON/V3/LSP adapters own UTF-16 conversion using source documents. The schema does not replace the live `ArtifactSet` publication boundary or `VerterCompileResult` routes. Vue custom-block parsing (`compile/mod.rs`, `extract_block_ranges` / the `unknown_nodes()` walk) retains one `VerterCustomBlock` per source block: `block_type`, `content`, `attrs` (exact authored order — attrs are never sorted or deduped, since `CustomBlockDescriptorId::mint` hashes them in order), `region` (SFC-absolute; a self-closing tag with no content span anchors at `tag_open.end`, a zero-length region), `source_order`, `lang`, `src` (matched by exact attribute name, as Vue's `createBlock` does), and `source_content` — the `ContentId` of the bytes the facts were read from, hashed once per compile and only when a custom block exists. The facts travel opaquely on `RuntimeCompileOutput.custom_block_facts` to the Vue bridge, which mints `CustomBlockDescriptor`s from them directly — no re-parse, no re-scan of source text — and refuses facts whose `source_content` differs from the registered carrier bytes. `assembly::StagedCompileArtifacts` is the request's ONE handoff from a framework host-integration backend into session lifecycle/publication code: a validated `CompileArtifactSet`, the `ArtifactId` of the runtime-module artifact inside it, the `FragmentDialect` those bytes are written in, and the runtime source map produced with them. `stage` is the only mint site and refuses a root the set does not contain (`UnknownRootArtifact`) or one that produced no content (`UnavailableRootArtifact`); an empty map payload stages as absent. `vue_main_compile_artifacts` and `svelte_main_compile_artifacts` return it, and it is what `RuntimeCompileOutput.main` carries — the module bytes live ON the staged root artifact, so a published body without its typed set is not representable and no consumer re-derives the module's language or locates its artifact by name. ## Multi-unit carrier lowering Runtime and IDE output blocks carry a `RuntimeOutputDescriptor` naming the generated destination space, emitted content artifact, declared input spaces, raw map, and honest `Exact`/`Approximate` fidelity. A separately lowered template receives `TemplateBindingMetadata` from its script pass (bindings, `has_script`, const props, and ref-bindable imports), matching Vue's official `bindingMetadata` mechanism. When an output genuinely merges spaces, each source is parsed and lowered independently. The compiler exposes typed generated-template holes/chunks, and `framework_common/generated_chunk.rs` assembles those generated bytes while rebuilding a multi-source V3 map. Do not concatenate authored inputs, synthesize carrier markup, or reparse a fabricated whole carrier. A missing chunk boundary or uncomposable map is a typed unavailable result. Generated-hole geometry is registered through `CodeTransform` chunk identity and resolved during the authoritative chunk walk. Never locate a generated hole by scanning built output for marker text; authored source may contain identical text. Current Vue capability gates: - Style analysis publishes carrier-absolute CSS/v-bind spans only for native carrier content. External or validated-supplied style bytes keep their availability/provenance but publish `css: None` and no located rows until LSP consumers understand the declared source space. Native SCSS/Sass/Less/Stylus does not mint an optional supplied-output request. - Runtime lowering supports external/validated-supplied templates with transferred carrier script metadata, projected setup script with a carrier template, and the validated supplied-inline template topology. Projected plain script and simultaneous projected plain+setup remain `BlockContentRuntimeUnavailable`. - IDE lowering supports native carriers and external/validated-supplied templates with composed maps when the carrier has no script, a setup script, or both plain and setup scripts. An external/validated-supplied template with only a carrier plain script remains `BlockContentIdeUnavailable` because its registered template hole is mid-module. Any projected plain or setup script also remains `BlockContentIdeUnavailable`, including the simultaneous case. - Every lifted IDE class must pass the real TypeScript syntax gate; the gate must prove tsc analyzed the emitted file and may tolerate only missing-module/intrinsic-environment diagnostics TS2307 and TS7026. Every lifted runtime class must pass `node --check`, with both gates carrying invalid-output and non-execution controls. A compiler `Ok` result alone is not proof of capability. ### Vue component resolution projection `VueProjectionBackend::component_resolution` combines the admitted `ProjectionPlan`, component-use witnesses, `ScriptProjectionFacts` binding inventory and the parse-selected custom-element prefixes. Configured custom elements do not enter component resolution. `ComponentResolutionObservation` distinguishes local/namespace, filename-recursive, global and dynamic uses without answering their types in Rust. Global names use the existing script fallback emitter, including its navigation probe; missing PascalCase members remain `unknown`. Non-Pascal authored tags retain the existing `GlobalComponentKebabType` route, and any Pascal-authored occurrence upgrades the shared fallback to Pascal intent. `DynamicComponentUseContract` checks a pure `:is="choice.component"` plus `v-bind="choice.props"` pair over each arm of `choice`. A branch containing a constructor union must satisfy every possible constructor; a mismatched or `never` arm is refused. Other dynamic expressions keep the ordinary component-use witness. Resolution specialization includes the plan snapshot and binding route alongside the witness key, so source shifts and binding changes invalidate the observation. The product is dormant until the Vue checking composer adopts it; TypeScript remains the type authority. ### Svelte IDE structural projection Svelte block projectors consume parser-owned structural spans. In particular, `{#snippet ...}` uses `SvelteBlock.head_span`, whose end is the grammar-balanced outer brace; downstream code must not rediscover the head with a first-`}` scan because destructured/defaulted parameters can contain nested braces. Element-owned snippets lower into a lexical IIFE so same-name snippets in sibling elements do not collide and forward, mutual, and recursive references remain valid. Unchanged snippet names, parameter lists, and bodies move as original `CodeTransform` chunks; only punctuation, annotations, or parameter text that genuinely requires a store/await-default rewrite is synthetic. Private component-call checks may map only byte-identical authored tokens. Synthetic scaffolding, quoted/escaped property spellings, rewritten spreads, and transformed directive names stay unmapped. Legacy intrinsic `on:event|modifier={handler}` projects to the lowercase Svelte DOM attribute (`onevent={handler}`); modifiers are runtime listener behavior and never survive as TSX attribute syntax. The Svelte IDE carrier's public facade inlines the syntactic `$props()` annotation directly into `Component`. Facade scaffolding stays unmapped; a byte-identical annotation is emitted as one mapped insertion per authored line because V3 source-map state does not carry across generated newlines. This lets tsgo definitions on a public prop land on the authored annotation member without assigning provenance to synthetic facade text. The higher-layer Svelte public-API projector prefers the resolved semantic contract when available (captured syntax is the fallback) and records prop-name anchors from typed local declaration origins, so tsserver targets in `.svelte.verter.ts` map through that surface's own source map to the same authored member. Vue IDE self-instance declarations reference the public API as `InstanceType` (and the JSDoc equivalent). The relative specifier is basename-only and omits the physical `.ts` extension, avoiding `allowImportingTsExtensions` diagnostics while resolving the exact virtual `.verter.ts` surface. Do not use `InstanceType`: `import(...)` there is not a value query and forces the old `@ts-ignore` workaround. ## Binding Metadata Flow 1. `script/process.rs` parses `` overwrite) — close the brackets the user left open so the generated scaffolding starts cleanly. A delimiter that requires a non-empty body but was left empty (a grouping/arrow-body paren `const x = (`, a computed-member bracket `foo[`) gets a placeholder operand BEFORE its closer (`undefined)`, `undefined]`); call args `foo()`, array literals `[]`, and blocks/objects `{}` are valid empty and get a bare closer. **Top-level fact gate.** Recovered facts are gated to bracket depth 0, mirroring the clean top-level parser's `block_depth == 0` rule. A block-local declaration (`function f(){ const inner = 1; }`) is NEVER recovered as a setup binding/import; only the whole-source holes/closers fire inside nested scopes. **Recovered macro = clean-lowering parity.** A recovered `defineProps`/`withDefaults` binding is registered `Props` AND emits the same `const __props = ;` alias as clean macro lowering, so a template `props.x` (lowered to `__props.x`) resolves instead of dangling against a `__props` that was never declared. The user's body STAYS inside the `___VERTER___TemplateBindingFN` wrapper in both cases; the broken-tail member access (`count.`) keeps hover/completion/go-to-definition working for declarations above the cursor. **No synthesize-then-reparse.** Synthetic recovery chunks are output-only and unmapped; they are NEVER bindings, macros, imports, or any other source fact. Recovery metadata comes only from the original clean OXC AST or from original-span token recovery over the real source — a reparsed synthetic view is never an authority. Guard: `crates/verter_compiler/tests/cases/ide_script_recovery_guard.rs` (scans `ide/script/setup.rs` for the deleted dual-recovery identifiers and the synthesize-then-reparse anti-pattern), plus `crates/verter_compiler/tests/cases/repro_member_access_ide_codegen.rs` (recovery shapes + clean-path preservation) and the negative-metadata tests in `script_recover.rs`. ## Style Rewrite Stages Framework style rewrites use `verter_css_syntax::StyleSyntaxIr` and are deliberately split. Public bump-backed CSS syntax nodes (`StyleBlock`, `StyleRule`, `SelectorCompound`, …) are borrowed from that IR and are not independently `Clone`/`Copy`; clone the IR (`Arc`) when an owned handle is needed. 1. `transform_vue_v_bind(AuthoredStyleInput)` is the production v-bind-only entry: it runs on authored CSS, SCSS, indented Sass, Less, or Stylus and returns the same dialect. It never preprocesses or evaluates. 2. CSS Modules hashing and the original-to-hashed mapping from typed selector spans are a cascade stage over the shared IR, not a public parse/materialize entry. 3. Scoped-selector rewriting runs only on plain CSS after preprocessing. `PlainCssInput::try_new` typed-refuses every non-CSS dialect before that cascade stage is admitted. There is no shipped isolated parse/materialize entry for this stage. 4. Svelte owns a separate plain-CSS consumer for `:global`, selector matching/pruning, scope insertion, and keyframe rewriting. Authored preprocessor dialects are typed-refused unless the host supplied a completed external preprocessing result for the block: the host hands it over once as a `SvelteSuppliedStyle` (produced bytes, producer, the host-minted source-space/artifact identity of those bytes, the host's parse of them, and the content identity of the authored bytes it validated — all read off the projection the block-content capture fence stamped, never re-derived from the live carrier), `bind_svelte_style_continuations` (`svelte/carrier.rs`) binds it to its block through `ExternalStyleContinuation::admit`, and the admitted continuation's produced bytes are then the block's only body for every stage (official-reject css probe, analysis, matcher, render) via `AdmittedStyleIrs`. A result that cannot be bound (stale basis, missing basis, unknown authored dialect, no block at its slot, boundary refusal) refuses the compile with `svelte-runtime-style-continuation-refused`; it never falls back to the authored block. Svelte's external css artifact publishes as a stage-qualified `QualifiedRuntimeStyle` (`RuntimeCompileOutput.qualified_styles` / `DirectCompileOutput.qualified_styles`), declared over the byte space the render consumed: the carrier source for an authored block, and for a continued block the HOST-minted space/artifact pair carried on `BoundStyleContinuation` — never a carrier space minted over the produced bytes, which would name an identity the host's own produced-to-authored map cannot be joined to. That host map (`SvelteSuppliedStyle.source_map` → `BoundStyleContinuation.source_map`) is transported with the continuation, and a continued block's css map is published chained through it (`chain_generated_map_json`, as for a supplied Vue block) — or absent when the host holds no map or the chain cannot be built — never the bare render map, whose produced-space positions would be labelled with the carrier file. The diagnostics the producing tool reported (`SvelteSuppliedStyle.diagnostics`, projected from the admitted override at the severity the tool stated, addressing the authored stage with no fabricated position) ride the continuation's result and then the published style's result in production order; they are never replaced by an empty list at the boundary. Only complete trusted nodes publish edits. Rewrite uncertainty fails closed; style-liveness uncertainty fails open. Every emitted edit and its source map comes from the same `CodeTransform`. Supplied or external inputs retain their host-minted source-space/artifact identity in `RuntimeOutputDescriptor`; carrier-absolute positions are never fabricated. The sealed `applyBlockOverrides()` handoff remains the input channel for caller-preprocessed content. External/supplied semantic analysis continues to publish `css: None` until its source-space-aware analysis consumer lands; compiler rewrite code must not route around that gate. ### Stage-Qualified Style Identity `verter_css_syntax::stage` owns the vocabulary every style consumer shares: `StyleStage` (`Authored` / `Preprocessed` / `FrameworkRewritten`), `StyleProducer` (`Verter` / `External(ExternalStyleProducer)` / `ExternalAnonymous`), `StyleDiagnostic` (a message plus a span qualified by the stage whose space it addresses), `StyleDependency` (the parse-minted inclusion inventory), and `QualifiedStyleResult` (bytes + stage + dialect + producer + diagnostics). A diagnostic's `stage` always names the space its span is IN, never the authority that reported it. There is deliberately no authority or severity axis on `StyleDiagnostic`: every style diagnostic a live route produces is a rewrite refusing, and a refusal is an error. A closed taxonomy whose other members name routes that do not exist claims a generality the pipeline does not have — the route that needs one adds it together with its producer. - `VueStyleCascadeOutcome.result` is that carrier, and `outcome.code()` is the only way to the bytes. A run that changed nothing stays at its input stage; a run that produced output is `FrameworkRewritten` and keeps its input dialect (only preprocessing fixes the dialect to CSS). - **A refusal's stage is the cascade input space, and there is no per-stage space to record.** Shared planning hands every compatible stage the same input IR and merges their plans into one terminal `CodeTransform`, so no stage ever inspects bytes another stage rewrote. `finish_vue_style_cascade` therefore projects every diagnostic at `input.stage()` — a single answer, not a per-stage table. Later Vue rewrite refusals are `Authored` (or admitted `Preprocessed`) and token-precise; they are not `FrameworkRewritten` and do not use a rewritten-space span. A refusing plain-CSS-only stage still clears the output after reporting. - **A cleared output is a refusal, not a rewrite that emitted nothing.** The runner's output state is the three-way `CascadeOutput` (`Passthrough` / `Rewritten` / `ClearedByRefusal`), and a wiped output mints `QualifiedStyleResult::refused(...)` — `is_refused()` true, no bytes, and no claim that a rewrite produced them. Deriving "was this rewritten?" from "are there owned bytes?" labelled those zero bytes `FrameworkRewritten` + `StyleProducer::Verter`. `cascade_output_is_publishable` reads `result.is_refused()`, not `code().is_empty()` and not the failing stage's identity. An authored-`v-bind()` rewrite failure that left the input intact is not a refusal. **A parse miss is recorded once, by the parse that ran, and clears only a request whose meaning depended on a rewrite it could not plan**: with `module` or `scoped` set, unrewritten bytes would ship unhashed class names or component styles applied document-wide, so the output is cleared; with neither, the only work was `v-bind()` lowering, nothing was rewritten, and the authored bytes publish beside the diagnostic. That second case is byte-for-byte the answer `run_vue_style_authored_only` gives, and it is the same answer by construction rather than by agreement: `RuntimeStyleProcessing::AuthoredOnly` and a `Complete` request with neither attribute are the same request, so `run_vue_style_authored_only` IS `run_vue_style_cascade(input, scope_id, false, false, …)` and holds no route of its own. It used to, and the two diverged on exactly one recorded fact — whether a parse that completed but whose `v-bind()` planning refused had surveyed the block's inclusions — which no signature could have caught. Every dialect now takes one route: the plain-CSS gate (`CssStageRequest::gated`, whose sole predicate is `PlainCssInput::try_new`) drops the CSS-only stages for a non-CSS `