let d = import "defaults/gate.ncl" in { membranes = [ d.make_membrane { id = "framework-boundary", name = "Framework Boundary Protection", description = "Prevents this implementation from modifying Rustelo framework internals. All customization must go through the layered override system or the plugin architecture. Framework crates are dependencies, never edited in place.", permeability = 'Closed, accepts = ['FrameBreakingQuestion], protects = ["framework upgrade path", "implementation independence", "override system integrity"], opening_condition = { max_tension_dimensions = 0, pending_transitions = 0, core_stable = true, description = "Never opens — the consume-not-fork axiom is non-negotiable. Any framework change belongs upstream in the rustelo project.", }, closing_condition = "Direct modification to a rustelo framework crate, or a vendored copy of framework source, detected in this project.", max_duration = 'Indefinite, protocol = 'Reject, active = true, }, d.make_membrane { id = "bilingual-parity-gate", name = "Bilingual Parity Gate", description = "Challenges any route or content addition that ships EN without a tracked path to ES parity. Blocks production publication of asymmetric routes.", permeability = 'Low, accepts = ['DepthDemonstrated, 'ProductiveMisunderstanding], protects = ["bilingual parity invariant", "audience trust", "SEO hreflang correctness"], opening_condition = { max_tension_dimensions = 1, pending_transitions = 2, core_stable = true, description = "Opens for EN-ahead drafting when the ES gap is registered as a publication blocker in content-coverage; never opens for production publication of an asymmetric route.", }, closing_condition = "A route or FTL key present in one locale and missing in the other reaches production publication.", max_duration = 'Indefinite, protocol = 'Challenge, active = true, }, d.make_membrane { id = "config-driven-gate", name = "Configuration-Driven Gate", description = "Challenges any hardcoded language, path, route, or content type in Rust source. All such values must come from NCL/TOML configuration under site/config.", permeability = 'Low, accepts = ['ProductiveMisunderstanding, 'DepthDemonstrated], protects = ["config-driven architecture", "language agnosticism", "deployment portability"], opening_condition = { max_tension_dimensions = 1, pending_transitions = 2, core_stable = true, description = "Opens only when a literal is justified as a framework-provided default overridable via configuration.", }, closing_condition = "Hardcoded language code, route path, or content type found in implementation source without a configuration override.", max_duration = 'Indefinite, protocol = 'Challenge, active = true, }, d.make_membrane { id = "purpose-gate", name = "Purpose Alignment Gate", description = "Challenges production publication when purpose.ncl criteria are not met: bilingual completeness, hydration parity on hydration-opted routes, and Hard SEO criteria (hreflang, JSON-LD, meta descriptions). Blocks any claim that the site is publication-ready unless validate-purpose-alignment passes all Hard criteria.", permeability = 'Low, accepts = ['DepthDemonstrated, 'FrameBreakingQuestion], protects = ["purpose declaration accuracy", "bilingual parity at publication", "audience trust"], opening_condition = { max_tension_dimensions = 1, pending_transitions = 2, core_stable = true, description = "Opens when validate-purpose-alignment passes all Hard criteria and publication-readiness has reached production-ready.", }, closing_condition = "A Hard validation or SEO criterion fails, or documentation/state describes the site as production-ready while content-coverage is below full-parity.", max_duration = 'Indefinite, protocol = 'Challenge, active = true, }, ], }