Commit d89034e
feat(rules): AffineScript hand-port pitfalls — HANDLE-as-fn-name + OCaml float ops (#332)
## Summary
Adds 5 patterns under language `"affine"`/`"affinescript"` to catch
parse-blocking hand-port leaks that surface when `.res` / `.ml` / `.re`
code is migrated to AffineScript. Both classes were discovered manually
during the sustainabot ReScript→AffineScript migration
(gitbot-fleet#148) and resolved via 5 parser PRs + a hand-port-rewrite
PR — but the underlying *signal* ("this code won't parse") only emerged
after `affinescript check`. Capturing them as Hypatia rules surfaces the
signal at PR-review time, before the iteration loop.
## The two pitfalls
1. **`handle` as a fn name.** AffineScript's `handle` is a reserved
keyword (HANDLE token), used by the effect-handler expression form
`handle body { handler_arms }`. So `pub fn handle(...)` is a parse
error. Severity: `:high`. Recommended rename: `dispatch`,
`handle_request`, `handle_event`.
2. **OCaml-style float operators.** AffineScript uses unified `+ - * /`
for both Int and Float. The OCaml form `+. -. *. /.` is never accepted.
Four separate patterns (one per operator) — each requires an
operand-character preceding the operator-and-dot, so `.0`-suffixed
numeric literals (e.g. `1.0 + x`) don't false-positive. Severity:
`:high` (parse blocker).
## Integration
- New `@affine_hand_port_patterns` module attribute in
`lib/rules/code_safety.ex` (immediately after `@rescript_patterns`).
- Dispatch registered for both `"affine"` and `"affinescript"` language
keys (mirrors the `javascript`/`typescript` alias precedent at lines
384-385).
- File-extension fallback in `lib/rules/rules.ex` after the existing
JS/TS web-security fallback: any `.affine` file gets the hand-port scan
even when the caller passes `language = nil` or an unrelated upstream
default.
## Test plan
- [x] Regex spot-check via `elixir -e 'Regex.scan(...)'`: `pub fn
handle(` matches; `let x = a /. 1.0` matches; `let x = a / 1.0` does NOT
match (true negative). All three confirmed.
- [x] `elixirc` of both modified files succeeds (only pre-existing
module-resolution warnings unrelated to this patch).
- [ ] `mix compile` blocked by a Phoenix-dep / Elixir-1.15 mismatch in
the sandbox env; not in scope for this PR.
## Cross-refs
- Refs hyperpolymath/gitbot-fleet#148
- Refs hyperpolymath/affinescript#370, #371, #372, #373, #376
- Refs hyperpolymath/gitbot-fleet#206
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 7d69b8a commit d89034e
2 files changed
Lines changed: 40 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
71 | 97 | | |
72 | 98 | | |
73 | 99 | | |
| |||
359 | 385 | | |
360 | 386 | | |
361 | 387 | | |
| 388 | + | |
| 389 | + | |
362 | 390 | | |
363 | 391 | | |
364 | 392 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
101 | 101 | | |
102 | 102 | | |
103 | 103 | | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
104 | 116 | | |
105 | 117 | | |
106 | 118 | | |
| |||
0 commit comments