# Changelog

## Score

- CAI 72 → 57 (-15.3)
- Rubric changed (rubric-2026.10.1 → rubric-2026.10.5) — scores are not directly comparable.

## Lenses

- Code Health 78 → 64 (-14.1)
- Architecture 99 → 99 (+0.1)
- Maturity 63 → 38 (-24.9)
- Readiness 77 → 75 (-2.5)
- Security 78 → 79 (+0.7)
- Performance 95 → 95 (+0.0)

## Resolved (10)

- Ambiguous lifecycle methods: `terminate`, `exit`, and `exit_if_finished` all suggest stopping the application. `exit_if_finished` is specific, but `terminate` vs `exit` is unclear. Does `exit` call `terminate`? Does `terminate` wait for completion? This creates a confusing API for users trying to shut down the application.
- Ambiguous naming convention: `command?` suggests a boolean check (existence), while `command` suggests retrieval. However, without seeing return types, it is unclear if `command` returns the command object or raises an error if not found, or if `command?` is a predicate. In Ruby, `?` is strictly for predicates. If `command` is the getter, this is consistent. If `command` is an action, it's inconsistent with `command?`. Given `Spring.commands` (plural) exists as a property, `command(name)` likely retrieves. The potential issue is if `command?` is redundant if `command` can be used for existence checks, or if `command` is ambiguous.
- Documentation: no architecture or design documentation (README.md)
- Inconsistent bang method semantics: `state` and `state!` take the same arguments. In Ruby, `!` often implies mutation or a more aggressive action. If `state` is a getter, `state!` might be a setter. If both are setters, the distinction is unclear. If `state` is a getter and `state!` is a setter, the naming is non-standard (usually `state` and `state=`). If both are setters, it's confusing.
- Inconsistent callback registration pattern: `after_fork(block)` takes a block/proc, while `after_fork_callbacks()` returns a collection. This is a common pattern (register vs list), but `after_environment_load` follows the same pattern. However, `Spring.after_fork_callbacks()` might be internal, while `after_fork` is public. If both are public, it's consistent. If `after_fork_callbacks` is private, it's fine. The inconsistency lies in `Spring.after_fork(block)` vs `Spring.after_environment_load(block)` - these are consistent. The potential issue is if `after_fork_callbacks` is exposed unnecessarily.
- Off-boarding risk: anonymized user #1
- Overloaded method signature: `boot` exists with and without arguments. This is common, but if `boot(options)` is the main implementation, `boot()` should be a clear alias. If they have different behaviors, the naming is misleading.
- PR-triggered workflow without a permissions block
- Redundant entry points: `Run.call(args)` and `Run.run()` both seem to execute the run command. `call` is the standard Ruby interface for executable objects, while `run` is descriptive. Having both can confuse users about which to use.
- Redundant/Confusing accessor pattern: `watcher` is a property/method returning the watcher instance, while `watch_method` is a string/enum identifier for the type of watcher. This is distinct, but `Spring.watch(items)` is a method that likely configures what to watch, whereas `Spring.watcher` is the active watcher instance. The naming `watch_method` vs `watcher` is clear, but `Spring.watch(items)` might be confused with `Abstract.add(items)` or `Polling.add()`. More critically, `Spring.watcher` (property) vs `Spring.Watcher` (class) is a namespace collision risk in documentation, though distinct in code.

## New (13)

- Ambiguous naming convention for existence check vs retrieval. `command?` suggests a boolean predicate (is there a command named X?), while `command` suggests retrieval. However, in many Ruby libraries, `method?` is a predicate and `method` is the accessor. If `command?` returns a boolean and `command` returns the command object, this is consistent. But if `command?` returns the command (truthy/falsy) and `command` also returns the command, it's redundant. Given the context of `Spring` being a registry, `command?(name)` likely checks existence, while `command(name)` retrieves. This is a minor naming convention inconsistency if `command?` is intended to be a predicate but might be confused with a getter that returns nil/false.
- Bang method ambiguity. In Ruby, `state!` often implies a side effect or a stricter validation than `state`. However, `state` usually implies a getter. If `state(val)` is a setter, `state!(val)` might be a setter with validation or side effects. If `state` is a getter, `state!` is unusual. The presence of both suggests a lack of clear convention for state mutation vs retrieval. Typically, setters are named `state=` or `set_state`. Using `state(val)` as a setter is non-idiomatic.
- Duplicate intent for execution entry points. `Run.call(args)` is the standard Ruby interface for executing an object (like a command). `Run.run()` is also present. In many command patterns, `call` is the primary entry point. Having both `run` and `call` on the same object suggests either one is an alias (redundant) or they serve different purposes (e.g., `run` for the full lifecycle, `call` for a specific step). Without bodies, it's hard to tell, but typically `call` is the preferred idiom for 'execute this command'.
- Flaky test: AcceptanceTest#test_code_changes_in_pre-referenced_app_files_are_picked_up
- Off-boarding risk: anonymized user #1
- Orphaned file (lib/spring/application_manager.rb)
- Orphaned file (lib/spring/env.rb)
- Orphaned file (lib/spring/json.rb)
- Orphaned file (lib/spring/server.rb)
- Orphaned file (lib/spring/watcher/abstract.rb)
- Overlapping lifecycle termination methods. `terminate`, `exit`, and `exit_if_finished` all suggest ending the application's lifecycle. `exit_if_finished` is conditional, but `terminate` and `exit` are ambiguous. Does `exit` call `terminate`? Does `terminate` call `exit`? This creates a confusing API for users trying to shut down the application.
- PR-triggered workflow without a permissions block (.github/workflows/ci.yml)
- Redundant/Confusing accessor for watcher configuration. `Spring.watcher` is a property/method returning the watcher instance. `Spring.watch_method` and `watch_method=` are used to configure the strategy (e.g., polling vs inotify). However, `Spring.Watcher` is also a namespace/module. The distinction between the *instance* of the watcher (`watcher`) and the *strategy* (`watch_method`) is clear internally but the API surface exposes both as top-level Spring methods, which can be confusing. More critically, `Spring.watcher` (method) and `Spring.Watcher` (module) share the same root name, which is acceptable in Ruby but adds cognitive load.
