Skip to main content

presolve_compiler/
semantic_capability.rs

1use std::fmt::Write as _;
2
3use serde::Serialize;
4
5pub const SEMANTIC_CAPABILITY_REGISTRY_SCHEMA_VERSION: u32 = 1;
6
7/// Compiler-owned classification of an authoring capability.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
9#[serde(rename_all = "snake_case")]
10pub enum SemanticCapabilityClass {
11    Native,
12    Bounded,
13    Opaque,
14    Unsupported,
15}
16
17/// Whether the compiler currently admits the named capability.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
19#[serde(rename_all = "snake_case")]
20pub enum SemanticCapabilityStatus {
21    Admitted,
22    Deferred,
23}
24
25/// One public, compiler-owned capability admission record.
26#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
27pub struct SemanticCapability {
28    pub id: &'static str,
29    pub class: SemanticCapabilityClass,
30    pub status: SemanticCapabilityStatus,
31    pub source_form: &'static str,
32    pub semantic_owner: &'static str,
33    pub type_rule: &'static str,
34    pub dependency_rule: &'static str,
35    pub resume_policy: &'static str,
36    pub artifact_impact: &'static str,
37    pub proof_fixture: &'static str,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub rejection_reason: Option<&'static str>,
40}
41
42/// Versioned public registry used to admit future compiler language families.
43#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
44pub struct SemanticCapabilityRegistry {
45    pub schema_version: u32,
46    pub capabilities: Vec<SemanticCapability>,
47}
48
49#[must_use]
50pub fn build_semantic_capability_registry() -> SemanticCapabilityRegistry {
51    SemanticCapabilityRegistry {
52        schema_version: SEMANTIC_CAPABILITY_REGISTRY_SCHEMA_VERSION,
53        capabilities: vec![
54            admitted(
55                "component",
56                SemanticCapabilityClass::Native,
57                "@component(\"tag\") class Name",
58                "component definition and instance plan",
59                "compiler-recognized component declaration",
60                "compiler-owned instance identity and composition",
61                "resumable through component artifacts",
62                "HTML, component runtime, resume artifacts",
63                "fixtures/0062-component-declarations/input/ValidComponents.tsx",
64            ),
65            admitted(
66                "component_invocation",
67                SemanticCapabilityClass::Bounded,
68                "resolved JSX component invocation with compiler-supported inputs and Slots",
69                "component invocation, composition, instance, ownership, and lifecycle products",
70                "statically resolved component target with compiler-supported composition grammar",
71                "compiler-owned invocation topology, caller/callee ownership, and instance identity",
72                "component instances, Slots, and Context bindings use existing resume identities",
73                "component runtime and resume artifacts",
74                "component_fixtures::component_composition_fixture_covers_topology_slots_caller_ownership_and_blocking",
75            ),
76            admitted(
77                "state",
78                SemanticCapabilityClass::Bounded,
79                "field = state(serializableInitializer)",
80                "component-instance State storage",
81                "compiler-supported serializable initializer",
82                "compiler-derived reads and Action writes",
83                "resumable when the value schema is supported",
84                "runtime State slots and bindings",
85                "examples/counter/src/Counter.tsx",
86            ),
87            admitted(
88                "serializable_state_replacement",
89                SemanticCapabilityClass::Bounded,
90                "field = state(recordOrArray); @action() { this.field = serializableRecordOrArray; }",
91                "component-instance State storage, Action plan, runtime field write, and resume codec",
92                "recursively serializable record or array literal at the whole-field boundary",
93                "Action-owned field replacement; no nested mutable alias or untracked write",
94                "existing State resume codec carries the complete replacement value",
95                "existing action manifest assign operand and State runtime slot",
96                "runtime_browser::serializable_record_state_replacement_executes_from_compiler_generated_runtime",
97            ),
98            admitted(
99                "static_action_parameters",
100                SemanticCapabilityClass::Bounded,
101                "@action() method(value: primitive) { this.field = value; }; onClick={() => this.method(serializableLiteral)}",
102                "Action parameter, State write, event binding, ordinary-instance plan, and runtime batch",
103                "one or more explicitly typed primitive parameters supplied by exact serializable callback literals",
104                "the compiler carries static arguments from the event declaration into the one completed Action batch; no DOM payload or closure capture is read",
105                "arguments are static manifest data; the resulting State replacement uses the existing State resume codec",
106                "template-manifest schema v5 and component-runtime schema v4 ordinary-event argument records with assign_parameter action operation",
107                "runtime_browser::static_callback_argument_updates_state_through_compiler_action_parameter",
108            ),
109            admitted(
110                "action_parameter_state_types",
111                SemanticCapabilityClass::Bounded,
112                "@action() method(value: primitive) { this.stateField = value; }",
113                "Action parameter and component-instance State type boundary",
114                "parameter and State must have the same compiler-known primitive kind, declared or inferred from the State initializer",
115                "type compatibility is checked before Action/runtime lowering; it adds no dynamic dependency",
116                "the existing compatible State slot and resume codec remain authoritative",
117                "canonical PSC1044 diagnostic; no new runtime or artifact field",
118                "tests::component_graph_rejects_action_parameter_state_type_mismatch",
119            ),
120            admitted(
121                "serializable_action_locals",
122                SemanticCapabilityClass::Bounded,
123                "@action() method() { const local = serializableLiteral; this.stateField = local; }",
124                "Action-local declaration, complete State write, and existing Action batch",
125                "one exact serializable local initializer with primitive compatibility to the target State field",
126                "the local is compile-time data only; it introduces no runtime dependency, capture, or alias",
127                "the resulting complete-State replacement uses the existing State resume codec",
128                "existing assign Action operand and runtime State write; no new artifact field",
129                "runtime_browser::serializable_action_local_updates_state_from_compiler_generated_runtime",
130            ),
131            admitted(
132                "structured_serializable_action_locals",
133                SemanticCapabilityClass::Bounded,
134                "@action() method() { const local = serializableRecordOrArray; this.stateField = local; }",
135                "Action-local declaration, complete structured State write, and existing Action batch",
136                "recursive literal shape compatible with the State initializer: exact object keys and homogeneous array element shape",
137                "the local is resolved to one compiler-issued literal operand with no runtime alias, capture, or dependency",
138                "the existing complete-State resume codec owns the structured value",
139                "existing assign Action operand; no new runtime evaluator or artifact field",
140                "runtime_browser::structured_serializable_action_local_executes_from_compiler_generated_runtime",
141            ),
142            admitted(
143                "action",
144                SemanticCapabilityClass::Bounded,
145                "@action() method()",
146                "completed Action batch",
147                "compiler-supported parameters and body",
148                "compiler-derived State writes and event activation",
149                "lazy activation and resume through emitted action records",
150                "runtime action chunks",
151                "examples/counter/src/Counter.tsx",
152            ),
153            admitted(
154                "computed",
155                SemanticCapabilityClass::Bounded,
156                "@computed() get value()",
157                "compiler-owned Computed value",
158                "getter-only supported expression subset",
159                "compiler-derived dependency graph",
160                "recomputed from resumed State; no authored cache",
161                "Computed IR and runtime artifact",
162                "fixtures/0047-computed-diamond/input/ComputedDiamond.tsx",
163            ),
164            admitted(
165                "effect",
166                SemanticCapabilityClass::Bounded,
167                "@effect() method()",
168                "terminal capability program",
169                "compiler-known capability arguments only",
170                "compiler-derived affected Action batches",
171                "not independently resumed; runs by compiler policy",
172                "effect IR and runtime capability artifact",
173                "fixtures/0053-effect-initial-runtime/input/InitialEffectRuntime.tsx",
174            ),
175            admitted(
176                "context",
177                SemanticCapabilityClass::Bounded,
178                "@context() static value; @provide(\"Owner.value\"); @consume(\"Owner.value\")",
179                "Context declaration, provider, and consumer identities",
180                "declared structural type boundary",
181                "compiler-owned visibility and provider selection",
182                "compiler-owned Context slots and resume records",
183                "Context IR and runtime artifact",
184                "fixtures/0059-context-runtime-matrix/input/ContextRuntimeMatrix.tsx",
185            ),
186            admitted(
187                "slot",
188                SemanticCapabilityClass::Bounded,
189                "@slot() content; <slot />",
190                "Slot declaration and caller-owned content",
191                "compiler-owned SlotContent marker",
192                "compiler-owned lexical owner and binding",
193                "resumable through Slot-binding records",
194                "component runtime Slot programs",
195                "fixtures/0062-component-declarations/input/ValidComponents.tsx",
196            ),
197            admitted(
198                "keyed_structural_list",
199                SemanticCapabilityClass::Bounded,
200                "compiler-supported iterable.map((item) => <element key={item.id} />)",
201                "template graph, compiler-issued keyed item identity, and structural runtime plan",
202                "explicit unique primitive key and supported item template grammar",
203                "compiler-owned iterable dependency and keyed instance lifecycle",
204                "keyed structural identity is carried by compiler artifacts and resume anchors",
205                "template/component runtime structural list records",
206                "runtime_browser::keyed_lists_reconcile_in_a_real_browser",
207            ),
208            admitted(
209                "jsx_html_attribute_aliases",
210                SemanticCapabilityClass::Bounded,
211                "className and htmlFor on compiler-supported intrinsic elements",
212                "template lowering before semantic analysis, manifests, static HTML, and runtime bindings",
213                "exact className or htmlFor spelling with a static or compiler-supported string binding",
214                "compiler-derived binding dependency after normalization to class or for",
215                "uses the existing attribute-binding State resume path",
216                "canonical HTML class/for template and runtime attribute records",
217                "template_graph::tests::normalizes_jsx_html_attribute_aliases",
218            ),
219            admitted(
220                "typed_aria_bindings",
221                SemanticCapabilityClass::Bounded,
222                "dynamic role plus aria-label/aria-describedby/aria-errormessage/aria-controls/aria-current/aria-live string or aria-invalid/aria-busy/aria-expanded/aria-pressed/aria-hidden boolean JSX attribute",
223                "template attribute binding, semantic type assignment, ordinary runtime binding, and DOM attribute update",
224                "exact compiler-known boolean or string contract for the admitted ARIA name",
225                "the attribute expression uses the existing compiler-derived State/Computed dependency path",
226                "no independent resume value; the existing binding source resumes through its owner",
227                "existing template/component runtime attribute binding records",
228                "runtime_browser::typed_aria_attribute_updates_in_a_real_browser",
229            ),
230            admitted(
231                "keyboard_action_event",
232                SemanticCapabilityClass::Bounded,
233                "onKeydown={this.actionMethod} on a compiler-supported element",
234                "template event, Action batch, ordinary-instance event record, and delegated runtime listener",
235                "exact keydown event with an existing zero-parameter compiler Action",
236                "event activates the compiler-owned Action batch only; keyboard payload fields are not projected",
237                "uses the existing Action activation and State resume path",
238                "existing template and ordinary event artifacts with event_type keydown",
239                "runtime_browser::structured_serializable_action_local_executes_from_compiler_generated_runtime",
240            ),
241            admitted(
242                "form",
243                SemanticCapabilityClass::Bounded,
244                "@form(); @field(\"form\"); @submit(\"form\")",
245                "Form, Field, validation, and submission identities",
246                "compiler-supported control and serializable field types",
247                "compiler-owned Form plans and explicit host markers",
248                "resumable through Form schema and records",
249                "Forms runtime artifact",
250                "fixtures/framework/resume-forms.tsx",
251            ),
252            admitted(
253                "module_bindings",
254                SemanticCapabilityClass::Bounded,
255                "local/relative import, export, re-export, namespace import, and local type alias",
256                "CompilationUnit, ModuleGraph, BindingTable, and local type bindings",
257                "local and relative binding forms retained by the parser",
258                "compiler-resolved module edges and named bindings",
259                "module bindings carry no independent runtime state",
260                "canonical binding-table product",
261                "binding_table::tests::resolves_relative_named_default_and_namespace_imports",
262            ),
263            deferred(
264                "advanced_types",
265                SemanticCapabilityClass::Unsupported,
266                "generic utilities, structural imported types, and checker-dependent TypeScript semantics",
267                "N1 advanced type products",
268                "no versioned compiler-owned TypeScript front-end contract yet",
269                "cannot derive canonical structural type bindings",
270                "no resume policy before admission",
271                "no artifact representation",
272                "N1-B must define advanced type semantics",
273            ),
274            admitted(
275                "semantic_package_bindings",
276                SemanticCapabilityClass::Bounded,
277                "named or default external import with a caller-supplied semantic package contract",
278                "SemanticPackageContract and BindingTable",
279                "validated schema, SHA-256 integrity, declared named/default export",
280                "declared binding only; executable use awaits its semantic-kind admission",
281                "binding itself owns no independently resumable state",
282                "canonical binding-table product records package/version/integrity/export",
283                "binding_table::tests::resolves_external_imports_only_through_semantic_package_contracts",
284            ),
285            admitted(
286                "semantic_package_pure_identity",
287                SemanticCapabilityClass::Bounded,
288                "direct call to a declared pure package export with pure_operation: identity in @computed()",
289                "SemanticPackageContract, ExpressionGraph, canonical IR, and runtime-computed artifact",
290                "one declared argument; result inherits the argument semantic type and serialization boundary",
291                "inherits the argument's compiler-derived reactive dependencies; no package code executes",
292                "input-only; no package-owned state or activation record",
293                "runtime-computed schema v4 pure-package-call instruction with package provenance",
294                "runtime_browser::pure_package_contracts_execute_only_the_compiler_lowered_operation_in_a_real_browser",
295            ),
296            admitted(
297                "template_interpolation",
298                SemanticCapabilityClass::Bounded,
299                "untagged template literal in a supported @computed() getter",
300                "parser, ExpressionGraph, canonical IR, and runtime-computed artifact",
301                "cooked static segments and compiler-supported interpolation expressions",
302                "compiler-derived union of every interpolation dependency",
303                "serializable string result; no independent resume record",
304                "runtime-computed schema v5 template instruction, retained in schema v6",
305                "runtime_browser::template_interpolations_execute_from_compiler_generated_runtime_programs",
306            ),
307            admitted(
308                "static_index_access",
309                SemanticCapabilityClass::Bounded,
310                "this.value[non-negative integer literal] or this.value[\"string literal\"] in a supported @computed() getter",
311                "parser, ExpressionGraph, canonical IR, and runtime-computed artifact",
312                "tuple, array, or object read with a literal string or non-negative integer index",
313                "compiler-derived dependency on the indexed object only; the literal index has no reactive dependency",
314                "serializable result when the selected value is serializable; no independent resume record",
315                "runtime-computed schema v6 get-index instruction, retained in schema v8",
316                "runtime_browser::static_index_accesses_execute_from_compiler_generated_runtime_programs",
317            ),
318            admitted(
319                "boolean_computed_conditional",
320                SemanticCapabilityClass::Bounded,
321                "boolean condition ? compiler-supported consequent : compiler-supported alternate in @computed()",
322                "parser, ExpressionGraph, canonical IR, and runtime-computed artifact",
323                "boolean condition with serializable compiler-supported branch values",
324                "compiler-derived union of condition and both branch dependencies",
325                "serializable selected result; no independent resume record",
326                "runtime-computed schema v7 select instruction, retained in schema v8",
327                "runtime_browser::boolean_conditional_computed_values_execute_from_compiler_generated_runtime_programs",
328            ),
329            admitted(
330                "builtin_math_abs",
331                SemanticCapabilityClass::Bounded,
332                "Math.abs(value) in a supported @computed() getter",
333                "compiler-registered BuiltinPureOperation, canonical IR, and runtime-computed artifact",
334                "exactly one compiler-supported numeric operand",
335                "inherits the operand's compiler-derived dependency set",
336                "serializable numeric result; no package or independent resume record",
337                "runtime-computed schema v9 unary abs operation",
338                "runtime_browser::registered_math_abs_executes_from_compiler_generated_runtime_programs",
339            ),
340            admitted(
341                "builtin_math_min_max",
342                SemanticCapabilityClass::Bounded,
343                "Math.min(left, right) or Math.max(left, right) in a supported @computed() getter",
344                "compiler-registered BuiltinPureOperation, canonical binary IR, and runtime-computed artifact",
345                "exactly two compiler-supported numeric operands",
346                "union of the compiler-derived dependencies of both operands",
347                "serializable numeric result; no package or independent resume record",
348                "runtime-computed schema v10 binary min/max operations",
349                "runtime_browser::registered_math_min_max_execute_from_compiler_generated_runtime_programs",
350            ),
351            admitted(
352                "builtin_math_rounding",
353                SemanticCapabilityClass::Bounded,
354                "Math.floor(value), Math.ceil(value), or Math.round(value) in a supported @computed() getter",
355                "compiler-registered BuiltinPureOperation, canonical unary IR, and runtime-computed artifact",
356                "exactly one compiler-supported numeric operand",
357                "inherits the operand's compiler-derived dependency set",
358                "serializable numeric result; no package or independent resume record",
359                "runtime-computed schema v12, including unary floor/ceil/round operations",
360                "runtime_browser::registered_math_rounding_executes_from_compiler_generated_runtime_programs",
361            ),
362            deferred(
363                "semantic_package_exports",
364                SemanticCapabilityClass::Unsupported,
365                "all other pure operations and capability, resource, codec, or component package exports",
366                "N1-A2 semantic-kind lowering products",
367                "declared export metadata is not yet an executable compiler semantic",
368                "cannot derive reactive, capability, resource, codec, or component behavior from a binding alone",
369                "no export-kind resume policy has been admitted",
370                "no package-kind IR or artifact provenance has been admitted",
371                "N1-A2 must admit each package kind through full-path lowering",
372            ),
373            admitted(
374                "resources",
375                SemanticCapabilityClass::Bounded,
376                "@resource(\"importedEndpoint\") field!: Resource<Data, Error>",
377                "integrity-checked semantic-package endpoint, Resource declaration and activation identity, browser runtime artifact, and generated runtime",
378                "one exactly imported semantic-package resource endpoint, Resource<Data, Error> field type, exact host-supplied runtime module location, and client or shared execution boundary",
379                "one compiler-owned cold activation per planned component instance; direct same-owner @computed() .data/.error/.state reads and terminal invalidation are admitted, while inputs and retry remain deferred",
380                "activation starts cold; terminal values invalidate compiler-derived Computeds. Resume fails closed for a Resource-reading Computed until an explicit Resource snapshot codec is admitted",
381                "runtime resource schema v1 plus runtime-computed schema v12, embedded page artifacts, and exact runtime module coordinate",
382                "runtime_browser::host_bound_resource_endpoint_activates_in_a_real_browser",
383            ),
384            admitted(
385                "opaque_typescript",
386                SemanticCapabilityClass::Opaque,
387                "@action() @opaque(\"package\", \"export\") method(): void {}",
388                "compiler-issued opaque terminal activation attached to one Action method",
389                "empty synchronous zero-parameter Action; exact imported opaque semantic-package export with () -> void client terminal contract",
390                "terminal after the compiler-owned Action batch; no State, Form, Context, Resource, or render dependency access",
391                "opaque terminals force cold resume fallback; no opaque snapshot codec exists",
392                "opaque.runtime.json schema v1, embedded page metadata, and exact integrity-bound runtime module coordinate",
393                "runtime_browser::integrity_bound_opaque_terminal_runs_only_from_a_compiler_action_in_a_real_browser",
394            ),
395        ],
396    }
397}
398
399#[must_use]
400pub fn semantic_capability_registry_json() -> String {
401    serde_json::to_string_pretty(&build_semantic_capability_registry())
402        .expect("semantic capability registry should serialize")
403        + "\n"
404}
405
406/// Deterministic human projection of the same registry used for JSON
407/// inspection. It is intentionally a view, not a second capability list or a
408/// schema-bearing product.
409#[must_use]
410pub fn semantic_capability_matrix_text() -> String {
411    let registry = build_semantic_capability_registry();
412    let mut output = format!(
413        "Presolve semantic capability matrix (schema v{})\n\n",
414        registry.schema_version
415    );
416    output.push_str("id | class | status | source form | proof fixture\n");
417    output.push_str("--- | --- | --- | --- | ---\n");
418    for capability in registry.capabilities {
419        let proof_fixture = if capability.proof_fixture.is_empty() {
420            "-"
421        } else {
422            capability.proof_fixture
423        };
424        writeln!(
425            output,
426            "{} | {} | {} | {} | {}",
427            capability.id,
428            capability_class_text(capability.class),
429            capability_status_text(capability.status),
430            capability.source_form,
431            proof_fixture
432        )
433        .expect("writing capability matrix cannot fail");
434        if let Some(reason) = capability.rejection_reason {
435            writeln!(output, "  rejection: {reason}")
436                .expect("writing capability matrix cannot fail");
437        }
438    }
439    output
440}
441
442/// Deterministic compatibility and migration guidance for the current
443/// registry. Deferred records are explained, never translated or relaxed.
444#[must_use]
445pub fn semantic_capability_migration_text() -> String {
446    let registry = build_semantic_capability_registry();
447    let deferred = registry
448        .capabilities
449        .iter()
450        .filter(|capability| capability.status == SemanticCapabilityStatus::Deferred)
451        .collect::<Vec<_>>();
452    let mut output = format!(
453        "Presolve semantic compatibility guide (registry schema v{})\n\n",
454        registry.schema_version
455    );
456    output.push_str("Compatibility policy\n\n");
457    output.push_str("- The registry is the exact compiler capability boundary.\n");
458    output.push_str("- Admitted records are supported only under their listed compiler rules.\n");
459    output.push_str("- Deferred records have no compatibility fallback, source rewrite, or opaque escape hatch.\n\n");
460    output.push_str("Migration guide\n\n");
461    for capability in &deferred {
462        writeln!(
463            output,
464            "- {}: {}\n  reason: {}",
465            capability.id,
466            capability.source_form,
467            capability
468                .rejection_reason
469                .expect("deferred capability has a rejection reason")
470        )
471        .expect("writing capability migration guide cannot fail");
472    }
473    output.push_str("\nRejected syntax catalog\n\n");
474    for capability in deferred {
475        writeln!(
476            output,
477            "- {} | {} | {}",
478            capability.id,
479            capability_class_text(capability.class),
480            capability
481                .rejection_reason
482                .expect("deferred capability has a rejection reason")
483        )
484        .expect("writing rejected syntax catalog cannot fail");
485    }
486    output
487}
488
489fn capability_class_text(class: SemanticCapabilityClass) -> &'static str {
490    match class {
491        SemanticCapabilityClass::Native => "native",
492        SemanticCapabilityClass::Bounded => "bounded",
493        SemanticCapabilityClass::Opaque => "opaque",
494        SemanticCapabilityClass::Unsupported => "unsupported",
495    }
496}
497
498fn capability_status_text(status: SemanticCapabilityStatus) -> &'static str {
499    match status {
500        SemanticCapabilityStatus::Admitted => "admitted",
501        SemanticCapabilityStatus::Deferred => "deferred",
502    }
503}
504
505#[allow(clippy::too_many_arguments)]
506fn admitted(
507    id: &'static str,
508    class: SemanticCapabilityClass,
509    source_form: &'static str,
510    semantic_owner: &'static str,
511    type_rule: &'static str,
512    dependency_rule: &'static str,
513    resume_policy: &'static str,
514    artifact_impact: &'static str,
515    proof_fixture: &'static str,
516) -> SemanticCapability {
517    SemanticCapability {
518        id,
519        class,
520        status: SemanticCapabilityStatus::Admitted,
521        source_form,
522        semantic_owner,
523        type_rule,
524        dependency_rule,
525        resume_policy,
526        artifact_impact,
527        proof_fixture,
528        rejection_reason: None,
529    }
530}
531
532#[allow(clippy::too_many_arguments)]
533fn deferred(
534    id: &'static str,
535    class: SemanticCapabilityClass,
536    source_form: &'static str,
537    semantic_owner: &'static str,
538    type_rule: &'static str,
539    dependency_rule: &'static str,
540    resume_policy: &'static str,
541    artifact_impact: &'static str,
542    rejection_reason: &'static str,
543) -> SemanticCapability {
544    SemanticCapability {
545        id,
546        class,
547        status: SemanticCapabilityStatus::Deferred,
548        source_form,
549        semantic_owner,
550        type_rule,
551        dependency_rule,
552        resume_policy,
553        artifact_impact,
554        proof_fixture: "",
555        rejection_reason: Some(rejection_reason),
556    }
557}
558
559#[cfg(test)]
560mod tests {
561    use super::*;
562
563    #[test]
564    fn registry_is_versioned_stable_and_explains_deferred_families() {
565        let registry = build_semantic_capability_registry();
566        assert_eq!(registry.schema_version, 1);
567        assert_eq!(
568            registry
569                .capabilities
570                .iter()
571                .map(|capability| capability.id)
572                .collect::<Vec<_>>(),
573            vec![
574                "component",
575                "component_invocation",
576                "state",
577                "serializable_state_replacement",
578                "static_action_parameters",
579                "action_parameter_state_types",
580                "serializable_action_locals",
581                "structured_serializable_action_locals",
582                "action",
583                "computed",
584                "effect",
585                "context",
586                "slot",
587                "keyed_structural_list",
588                "jsx_html_attribute_aliases",
589                "typed_aria_bindings",
590                "keyboard_action_event",
591                "form",
592                "module_bindings",
593                "advanced_types",
594                "semantic_package_bindings",
595                "semantic_package_pure_identity",
596                "template_interpolation",
597                "static_index_access",
598                "boolean_computed_conditional",
599                "builtin_math_abs",
600                "builtin_math_min_max",
601                "builtin_math_rounding",
602                "semantic_package_exports",
603                "resources",
604                "opaque_typescript"
605            ]
606        );
607        assert!(registry
608            .capabilities
609            .iter()
610            .filter(|capability| capability.status == SemanticCapabilityStatus::Deferred)
611            .all(|capability| capability.rejection_reason.is_some()));
612        assert!(semantic_capability_registry_json().contains("\"semantic_package_bindings\""));
613        assert!(semantic_capability_registry_json().contains("\"static_index_access\""));
614        let matrix = semantic_capability_matrix_text();
615        assert_eq!(matrix, semantic_capability_matrix_text());
616        assert!(matrix.starts_with("Presolve semantic capability matrix (schema v1)\n\n"));
617        assert_eq!(
618            matrix.matches("\ncomponent | native | admitted |").count(),
619            1
620        );
621        assert!(matrix.contains("advanced_types | unsupported | deferred |"));
622        assert!(matrix.contains("  rejection: N1-B must define advanced type semantics\n"));
623        let migration = semantic_capability_migration_text();
624        assert_eq!(migration, semantic_capability_migration_text());
625        assert!(
626            migration.starts_with("Presolve semantic compatibility guide (registry schema v1)\n\n")
627        );
628        assert!(!migration.contains("- opaque_typescript:"));
629        assert!(!migration.contains("- resources:"));
630        assert!(registry.capabilities.iter().any(|capability| {
631            capability.id == "resources"
632                && capability.status == SemanticCapabilityStatus::Admitted
633                && capability.class == SemanticCapabilityClass::Bounded
634        }));
635        assert!(registry.capabilities.iter().any(|capability| {
636            capability.id == "opaque_typescript"
637                && capability.status == SemanticCapabilityStatus::Admitted
638                && capability.class == SemanticCapabilityClass::Opaque
639        }));
640    }
641}