Make an ignore-file pattern matcher follow its spec (anchoring, directory-only, double-star, negation, parent exclusion)
Exact prompt
# Make the ignore-file matcher follow its spec `ignore.py` decides which paths our sync tool skips, using `.gitignore`-style patterns. It is a quick `fnmatch` hack and gets many cases wrong. Rewrite it so `Matcher(text).ignored(path, is_dir=False)` follows the rules below exactly. Python 3 standard library only. Keep the class name, constructor and method signature. `path` is a relative POSIX path with no leading `./` or `/` (e.g. `src/app/main.py`); `is_dir` says whether the path itself is a directory. Every ancestor of `path` (e.g. `src`, `src/app`) is a directory. ## Rules 1. **Lines.** Split `text` into lines (strip a trailing `\r`). Trailing spaces are removed unless the last space is escaped as `\ ` (backslash-space, which keeps one literal space). Blank lines are ignored. A line starting with `#` is a comment; `\#` at the start is a literal `#`. Leading spaces are NOT stripped. 2. **Negation.** A leading `!` makes the pattern a negation (re-include). `\!` at the start is a literal `!`. 3. **Directory-only.** A trailing `/` is removed and makes the pattern match only directories. A pattern that is empty after removing `!` and the trailing `/` is ignored. 4. **Anchoring.** If the remaining pattern contains a `/` anywhere (start or middle), it is matched against the full path from the root (a leading `/` is dropped first). Otherwise it is matched against the last component at any depth (i.e. against the full path or any suffix that starts right after a `/`). 5. **Wildcards.** `*` matches any run of characters except `/` (including none); `?` matches exactly one character except `/`. `[...]` is a character class: ranges like `a-z` work, `!` or `^` as the first character negates it, a `]` directly after `[` (or after the negation mark) is literal; a class never matches `/`. A `[` with no closing `]` is a literal `[`. A backslash outside a class makes the next character literal. 6. **Double star.** Only these forms are special: a leading `**/` matches zero or more leading directories; `/**/` matches one `/` or `/any/dirs/`; a trailing `/**` matches one or more characters (anything inside, but not the directory itself). Any other run of `*` (e.g. `a**b`, `**` on its own) behaves like a single `*`. 7. **Last match wins.** For a given path, look at all patterns in file order; the last one that matches decides (normal = ignored, negated = not ignored). No match = not ignored. Directory-only patterns are only considered when the path being tested is a directory. 8. **Parents.** First test each ancestor directory from the top (`src`, then `src/app`, ...) using rule 7 with `is_dir=True`. If any ancestor is ignored, the path is ignored and nothing (not even a later `!` pattern) can re-include it. Otherwise the path's own result from rule 7 is the answer. 9. **Speed.** Building a matcher from 300 patterns and answering 20,000 `ignored()` calls must take under 10 seconds in total on our (shared, slow) test box. ## Scoring Hidden checks (one per group, all must pass; partial credit is the fraction passed): `comments_spaces_escapes` (rules 1-2, 5 backslash), `negation_last_match` (2, 7), `dir_only` (3, 7), `anchoring` (4), `wildcards_classes` (5), `double_star` (6), `parent_exclusion` (8), `randomized_agreement` (400 random pattern/path pairs built from the characters `a b / * ? [ ] ! -` must all agree with the rules), `speed` (9). Each group has 10-40 exact assertions.
Nine interacting rules (escaped trailing spaces, class edge cases like []] and [!]], three special ** forms, last-match-wins, and 'a parent directory once excluded cannot be re-included') checked by exact assertions plus 400 randomized pattern/path pairs, so half-right regex translations score partially. Original benchmark task written for usecaserank.com (not based on a specific public post). Headless, offline run on a reproducible fixture. Each run's notes say how its cost was measured (estimates are marked).
Success criteria: 1. comments_spaces_escapes 2. negation_last_match 3. dir_only 4. anchoring 5. wildcards_classes 6. double_star 7. parent_exclusion 8. randomized_agreement (400 random pairs) 9. speed (300 patterns x 20,000 paths < 10 s)
Best model for this task so far: Claude Haiku 5.5 (effort default (no --effort flag) · thinking on) (success, $0.03, 3m).
All runs (4)
100% pass rate across 4 eligible runs: 4 pass, 0 partial, 0 fail. Partial and failed runs are listed below with everything else.ⓘ
| Model | Cost | Time | Step-insⓘ | Autonomy | Outcome | Trustⓘ | Date | Compare |
|---|---|---|---|---|---|---|---|---|
| OGPT-6.1 Soldefault · thinking on | $0.07 | 1m | 0 | Fully autonomous | pass | Trust 80% | 2026-10-22 | |
| AClaude Haiku 5.5default · thinking on | $0.03 | 3m | 0 | Fully autonomous | pass | Trust 80% | 2026-10-20 | |
| AClaude Opus 5.5default · thinking on | $0.51 | 3m | 0 | Fully autonomous | pass | Trust 80% | 2026-10-20 | |
| AClaude Sonnet 5.5default · thinking on | $0.13 | 55s | 0 | Fully autonomous | pass | Trust 80% | 2026-10-20 |
Embed this result
A live badge for this use case. It links back here and updates as new runs are published.
Get new runs and ranking changes weekly
Which models got better or cheaper on real tasks like this one.