Module inspector now catches the two Stripo authoring traps that quietly break compose: static-asset re-registration and nested-selector clobbering
Two new detectors land on orbit_inspect_stripo_module_bindings and orbit_audit_stripo_modules, both targeting Stripo authoring patterns that pass structural inspection, render fine in the editor, and then misbehave at compose time. First: the static-asset pattern. When a module registers three or more image variables all bound to src on esd-gen-image* class elements, the asset URLs are almost always design — tick markers, badge grids, brand-logo walls — not per-send content. The trap is that Stripo's Smart Element wizard auto-re-registers esd-gen-* classes every time the module is reopened in the editor, so deregistering from the Data tab doesn't stick. The fix is documenting which variables are static-by-design as an HTML comment at the top of the module, which the wizard leaves alone. The inspector flags the shape and tells you what comment to add. Second: nested selectors. When two Smart Property bindings target elements where one contains the other in the DOM, Stripo writes the outer binding by replacing the inner element wholesale at compose time, and the inner binding's value gets clobbered. Detection uses real DOM containment via Cheerio, not string matching. Both detectors fire in the single-module inspector and the bulk auditor, and the static-asset best practice is now in orbit_setup_stripo's onboarding instructions. Also in this release: a brand-name fallback fix so unconfigured workspaces no longer see a hardcoded value.
What shipped
•New detection — static-asset pattern. orbit_inspect_stripo_module_bindings and orbit_audit_stripo_modules now flag modules that register three or more image-bound variables (p_image, p_image2, p_image3, etc.) all targeting src attributes on elements with esd-gen-image* classes. This shape almost always indicates a module whose imagery is design rather than dynamic content — a row of tick markers, a feature-comparison grid, a logo wall. The pitfall the detector exists to prevent: Stripo's Smart Element wizard auto-re-registers esd-gen-* classes every time the module is reopened in the editor, so removing the variables from the Data tab doesn't survive the next edit. The recommended fix surfaces in the inspector's notes — add an HTML comment at the top of the module listing each static variable and its canonical asset URL. The wizard leaves HTML comments alone, so the comment is the durable record of what's intentionally static.
•New detection — nested Smart Property bindings. When a module has two bindings where one selector targets a DOM element that contains the other binding's target, the inspector and auditor now flag the pair. The mechanism: at compose time Stripo applies bindings by replacing the targeted element wholesale, so when the outer binding fires it overwrites the inner element and the inner binding's value never lands. Detection walks the parsed DOM with Cheerio's $.contains rather than guessing from selector strings, so cases like a header binding wrapping a CTA binding are caught reliably regardless of how the selectors are written.
•Onboarding update — orbit_setup_stripo's 'Module design — works best with these principles' section now includes the HTML-comment best practice for static assets. New modules built against the latest setup output get the durable-contract pattern baked in from the start, rather than discovering the wizard-re-registration trap after the fact.
•Storage hardening — ten tools that accept an optional output_dir argument (orbit_render_email_preview, orbit_rfm_score, orbit_cohort_retention, orbit_build_exec_report, orbit_build_braze_pack, orbit_create_braze_canvas, orbit_generate_email_components, orbit_assemble_email_template_from_components, orbit_upload_images_to_braze, orbit_reconcile_image_urls) now route the caller-supplied path through Orbit's workspace primitive. Relative paths anchor to ~/Orbit/outputs reliably regardless of how Claude Desktop launched the MCP, and path-traversal attempts surface a clean error instead of writing somewhere unexpected. Bonus fix: orbit_probe_stripo_values was double-nesting reports under outputs/outputs/.
•Bug fix — orbit_compose_stripo_email's default brand-name fallback in email-components.js is now 'Brand' instead of a workspace-specific value that had no business being there. Only affects users whose ORBIT_COMPANY_NAME env var is unset; everyone with a configured workspace was already getting their own brand name through.