# Changelog

## Score

- CAI 65 → 62 (-2.3)
- Rubric changed (rubric-2026.10.1 → rubric-2026.10.5) — scores are not directly comparable.

## Lenses

- Code Health 82 → 86 (+4.5)
- Architecture 86 → 86 (-0.0)
- Maturity 55 → 50 (-5.2)
- Readiness 60 → 60 (+0.0)
- Security 85 → 82 (-2.6)
- Performance 95 → 95 (+0.0)

## Resolved (3)

- Ambiguity in return types and intent. `Page.text` and `Page.runs` are high-level accessors. `PageTextReceiver.runs` is a method on a receiver object. It is unclear if `PageTextReceiver.runs` is a getter for internal state or a method to trigger processing. If it's a getter, it duplicates `Page.runs`. If it's a trigger, the naming is misleading.
- Redundant accessors for object retrieval. `[]` and `object` appear to perform the same core function (retrieving an object by key), while `fetch` provides a default value variant. In Ruby, `[]` is the standard accessor, making `object` redundant and confusing.
- While consistent between the two types, `has_value?` is often less idiomatic in Ruby than `value?` or checking the result of `values.include?`. However, the bigger issue is the inconsistency with `include?` for keys. If `include?` is used for keys, `value?` might be a better parallel for values, or stick to `has_value?` everywhere. The current state is internally consistent between the two classes but arguably inconsistent with Ruby Hash idioms if `include?` is used for keys.

## New (5)

- Inconsistent default value handling in `fetch`. While both use `fetch`, the semantics of `local_default` in `ObjectCache` vs `ObjectHash` may differ (e.g., one might raise on missing, the other might use the default). More importantly, `ObjectHash` also has `[]` which might behave differently regarding missing keys compared to `fetch`. This creates confusion about the contract for missing keys across similar collection-like types.
- Inconsistent naming for geometric dimensions. `Rectangle` uses `height()` and `width()`, while `Page` also uses `height()` and `width()`. This is consistent. However, `Page` also has `origin()`, `orientation()`, and `boxes()`. The inconsistency lies in the fact that `Rectangle` is a pure data structure with simple accessors, while `Page` is a complex object. The real issue is that `Page` exposes `height()` and `width()` which likely refer to the media box dimensions, but `Rectangle` also has these. If `Page`'s dimensions are derived from a `Rectangle`, the naming is consistent, but the intent (static dimensions vs. dynamic page properties) might be conflated. A more significant inconsistency is `Page.boxes()` vs `Page.rectangles()`, which likely return similar geometric data.
- Orphaned file (lib/pdf/reader/advanced_text_run_filter.rb)
- Orphaned file (tools/fuzz.rb)
- Redundant text extraction interfaces. `Page.text` and `Page.runs` provide high-level access to text content. `PageTextReceiver` is a low-level receiver pattern that also has a `runs` method. Users might be confused whether to use the direct `Page` methods or construct a receiver. The `runs` method exists on both the high-level `Page` object and the low-level `PageTextReceiver`, suggesting overlapping intent for accessing text runs.
