Parity Auditing Process
This guide describes the process for auditing RatatuiRuby against upstream Rust Ratatui to find API parity gaps of any kind.
Philosophy
RatatuiRuby should behave identically to Rust Ratatui. When a Rust user can do something with a widget, a Ruby user should be able to do the equivalent. Deviations are bugs.
The Audit Mindset
Ask the Right Questions
Every audit begins with a question:
-
βDoes
RatatuiRubysupport everything upstream supports for widget X?β -
βWhen I pass type Y to parameter Z, does Ruby do what Rust does?β
-
βAre there features in upstream that we havenβt exposed at all?β
Symptoms That Trigger Audits
-
Inspect strings in output (
#<data RatatuiRuby::...>) β type conversion failure -
Missing methods β user canβt access upstream functionality
-
Wrong behavior β code runs but produces different results than Rust
-
Type mismatches β Ruby API accepts different types than Rust API
The Three-Layer Model
Every RatatuiRuby feature has three layers. Gaps can occur at any layer:
βββββββββββββββββββββββββββββββ β Ruby API (lib/**/*.rb) β β What users see βββββββββββββββββββββββββββββββ€ β Rust Bindings (ext/**/*.rs)β β Bridge layer βββββββββββββββββββββββββββββββ€ β Upstream Ratatui β β Source of truth βββββββββββββββββββββββββββββββ
Layer 1: Ruby API Gaps
Ruby doesnβt expose a parameter that upstream supports.
Layer 2: Binding Gaps
Ruby exposes a parameter, but the Rust binding converts it incorrectly.
Layer 3: Upstream Changes
New upstream features we havenβt implemented yet.
Audit Process
1. Choose an Audit Scope
Define what youβre auditing: - Single widget: All parameters of Tabs - Single feature: All places that accept styled text - Version delta: Everything new in Ratatui 0.29
2. Establish Source of Truth
For any scope, identify the authoritative upstream source: - Method signatures β Rust source files - Type constraints β Generic bounds (Into<Line>, &str, etc.) - Behavior β Upstream documentation and tests
3. Inventory Our Implementation
List everything in our codebase related to the scope: - Ruby classes and methods - Rust binding functions - Conversion/parsing logic
4. Compare Systematically
For each item in the upstream source of truth, ask: 1. Do we expose this at all? 2. If yes, does our implementation match the type signature? 3. If yes, does our behavior match?
5. Document Findings
For each gap found, record: - What the gap is - Where it occurs (files, lines) - What upstream expects - What we currently do
6. Fix and Verify
Apply fixes, then verify: - Compiles without errors - Tests pass - Visual/manual verification if applicable
Verifying Completeness
Finding gaps is not enough. You must verify youβve found all gaps within your scope.
The Completeness Mindset
An initial audit pass often finds the obvious issues. But βobviousβ means βincomplete.β After your first pass, stop and ask:
-
Did I search for every variation of the pattern I was looking for?
-
Are there synonyms or related terms I should also search?
-
Did I check all code paths, not just the happy path?
-
Are there duplicate implementations (e.g.,
rendervsrender_stateful)?
Broaden Your Search Terms
Your first search term wonβt catch everything. For each pattern, think of variations:
| If you searched for⦠| Also search for⦠|
|---|---|
funcall("to_s" |
String::try_convert |
Into<Line> |
Into<Span>, Into<Text>
|
| One widgetβs file | All widget files |
| The method youβre fixing | Related methods in the same file |
Work From the Complete List
Donβt spot-check. Generate the complete list of potential issues, then classify each one:
-
Run a search that catches all possible instances
-
Count them (e.g., β31
to_scall sitesβ) -
Review every single one, marking each as βgapβ or βcorrectβ
Half-measures lead to half-fixes.
Verify Against Upstream Exhaustively
For type-related gaps, donβt just check the methods you already know about. Search upstream for all uses of the pattern:
-
grep -rn 'Into<Line' /path/to/ratatui/src/widgetsfinds EVERY place upstream acceptsLine -
Then verify we handle EACH of those correctly
Question Your Assumptions
After completing your audit, challenge yourself:
-
βIs there anywhere I should look that I havenβt?β
-
βIs there any term I should search that I havenβt?β
-
βAm I sure I didnβt miss anything?β
If you canβt answer confidently, keep searching.
The βOne More Passβ Rule
When you think youβre done, do one more verification pass with a different approach:
-
If you searched our code first, now search upstream first
-
If you searched for method names, now search for type signatures
-
If you audited file-by-file, now audit feature-by-feature
This catches gaps your initial framing missed.
Search Strategies
Different gap types require different search approaches:
Finding Type Conversion Gaps
Look for places where we convert Ruby objects to simpler types: - funcall("to_s", ...) β converting to string - String::try_convert(...) β same - u16::try_convert(...) β numeric conversion
Then check: does upstream accept richer types?
Finding Missing Features
Compare file structure: - What files/modules exist upstream? - What methods exist in each upstream struct? - What parameters does each upstream method accept?
Finding Behavioral Differences
Run equivalent code in both environments and compare output.
Red Flags in Our Code
When reviewing RatatuiRuby code, these patterns suggest potential gaps:
| Pattern | Potential Gap |
|---|---|
funcall("to_s", ...) |
Upstream may accept styled types |
usize or u16 for padding |
Upstream may accept content types |
Missing parse_* call before using a value |
Type not being converted properly |
| Widget with fewer Ruby methods than Rust methods | Missing functionality |
// TODO or // FIXME comments |
Known gaps |
Upstream Patterns to Watch For
When reading upstream Rust code, these signatures indicate rich type support:
| Rust Signature | Meaning | Ruby Should Accept |
|---|---|---|
Into<Span<'a>> |
Styled single fragment |
Text::Span or String
|
Into<Line<'a>> |
Styled line |
Text::Line, Text::Span, or String
|
Into<Text<'a>> |
Multi-line styled |
Text::Text, Text::Line, or String
|
T: AsRef<str> |
Any string-like |
String (OK) |
&'a str |
String slice |
String (OK) |
Keeping Audits Maintainable
Create Checklists
For each widget or feature area, maintain a checklist of all parameters with their expected types.
Track Upstream Changes
When upgrading Ratatui versions: 1. Read the changelog 2. Search for new pub fn in widget files 3. Audit new functionality before exposing it
Automate Where Possible
Consider tooling that: - Compares upstream method counts to ours - Flags new to_s calls in code review - Tests styled content rendering
Example Audit Narrative
βI noticed inspect strings appearing in my tabs. I asked: βWhat types does upstream accept for the divider parameter?β I found
Into<Span>. I then asked: βWhat does our binding do?β I found we callto_s. Gap identified.β
This narrative approachβasking questions, finding answers, comparingβworks for any parity issue.