When given a RUNE spec and its corresponding implementation file, compare them and report every discrepancy.
Input: a RUNE spec (.rune or Markdown) + an implementation file (.py, .ts, .go, etc.).
Output: a diff report listing all mismatches.
Compare the spec’s SIGNATURE against the actual function declaration.
Check:
Example mismatch:
**SIGNATURE MISMATCH**
- Spec: `def validate_coupon(code: str, coupons: list[dict], date: str) -> tuple[bool, str]`
- Code: `def validate_coupon(coupon_code: str, coupon_list: list, current_date: str) -> dict`
- Issues:
- Parameter renamed: `code` -> `coupon_code`
- Parameter renamed: `coupons` -> `coupon_list`
- Parameter renamed: `date` -> `current_date`
- Type changed: `coupons` lost `[dict]` annotation
- Return type changed: `tuple[bool, str]` -> `dict`
For each WHEN/THEN rule in the spec, verify the implementation handles it.
Process:
Check:
Example mismatch:
**BEHAVIOR DRIFT**
- Rule: `WHEN code is empty THEN return (False, "Coupon code cannot be empty")`
- Code: `if not code: raise ValueError("Code required")`
- Issues:
- Action changed: spec says `return (False, ...)` but code `raises ValueError`
- Message changed: `"Coupon code cannot be empty"` -> `"Code required"`
Extract all error messages from the implementation and compare against BEHAVIOR.
Check:
For each CONSTRAINT in the spec, check if the implementation validates it.
Check:
Example mismatch:
**MISSING CONSTRAINT CHECK**
- Spec CONSTRAINT: `"email: maximum 254 characters (RFC 5321)"`
- Code: No length check found
- Impact: Emails longer than 254 chars will be accepted
For each EDGE_CASE in the spec, verify the implementation handles it correctly.
Check:
Identify behavior in the code that is NOT described in the spec.
Look for:
Example:
**UNDOCUMENTED BEHAVIOR**
- Code has: `if len(email) > 254: return (False, "Email too long")`
- Spec: No BEHAVIOR rule or CONSTRAINT mentions max length
- Action: Add to spec or remove from code
## RUNE Diff Report: `<function_name>`
**Spec:** `validate_coupon.rune`
**Code:** `src/coupon.py`
### SIGNATURE
- [MATCH] Function name: `validate_coupon`
- [MATCH] Parameters: `code`, `coupons`, `date`
- [DRIFT] Return type: spec says `tuple[bool, str]`, code returns `tuple[bool, dict | str]`
### BEHAVIOR
| Rule | Status | Detail |
|------|--------|--------|
| WHEN code is empty... | MATCH | Line 12 |
| WHEN code not found... | MATCH | Line 18 |
| WHEN coupon expired... | DRIFT | Message differs: "Coupon has expired" vs "Expired coupon" |
| OTHERWISE... | MATCH | Line 28 |
### ERROR MESSAGES
- [DRIFT] Line 22: `"Expired coupon"` should be `"Coupon has expired"`
### CONSTRAINTS
- [MATCH] code: non-empty string
- [MISSING] code: case-insensitive — code uses exact match instead
### EDGE_CASES
- [MATCH] empty code: handled
- [DRIFT] expires today: spec says "still valid" but code treats it as expired
### UNDOCUMENTED
- Line 8: `if not isinstance(code, str): raise TypeError` — not in spec
### Summary
- **Status:** DRIFT DETECTED
- **Matches:** 7
- **Drifts:** 3 (return type, error message, expiration logic)
- **Missing:** 1 (case-insensitive matching)
- **Undocumented:** 1 (type check)
- **Recommendation:** Update spec to match code, OR fix code to match spec (see details above)