Skip to content

Expose the options that passed the filters - #10

Merged
Meldiron merged 4 commits into
mainfrom
feat-filtered-options
Aug 13, 2026
Merged

Expose the options that passed the filters#10
Meldiron merged 4 commits into
mainfrom
feat-filtered-options

Conversation

@Meldiron

@Meldiron Meldiron commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Two changes that together make this library usable for fan-out, and installable alongside the current utopia stack.

1. Expose the options that passed the filters

run() answers "which one option should I use", and the set it picks from was not available to callers: $filters is private and getOptions() returns the unfiltered list. A caller that has to act on every qualifying option — fanning a request out to all of them rather than balancing between them — had only bad choices: re-implement filtering outside the class, or subclass and record filters as they are registered so they can be replayed.

getFilteredOptions() is that set, extracted from run() verbatim. run() now calls it:

public function run(): ?Option
{
    $options = $this->getFilteredOptions();

    if (\count($options) === 0) {
        return null;
    }

    return $this->algo->run($options);
}

Purely additive — no behaviour change to run(), addFilter(), addOption() or Group.

2. Require telemetry 0.4

Group's pin at utopia-php/telemetry: 0.1.* makes this library uninstallable next to anything on the current telemetry line. utopia-php/pools requires ^0.4.6, so any consumer that pulls in pools — through utopia-php/client, for one — cannot also require balancer. That is a hard blocker, not a preference.

The constraint moves to ^0.4.0. The 0.1 series is dropped rather than kept alongside, because it was already unreachable for any consumer that also pulls in pools — supporting both would keep a combination alive that nothing can install.

No code changes: the entire surface Group touches is identical between the two series. Adapter::createHistogram() and Histogram::record() have byte-identical signatures and Adapter\None exists in both.

Platform requirements narrow, which is worth stating since it is the opposite of what a version bump usually does:

telemetry 0.1.1 telemetry 0.4.6
ext-protobuf required required
ext-opentelemetry required not required

Test Plan

composer test — 6 tests, 69 assertions, all passing. The existing testBalancer case is what proves run() is unchanged: it drives filters and algorithms through the same sequence as before and was not touched.

testFilteredOptions covers the new method: unfiltered returns everything; one filter returns both survivors where run() returns only the first; filters compose; keys are reindexed from zero; and a filter matching nothing returns [] while run() returns null.

composer check (PHPStan --level max) reports [OK] No errors, composer lint (PSR-12) passes on all 9 files, composer validate is clean, and the lock resolves telemetry 0.4.6.

For the constraint itself I checked resolution rather than reasoning about it: a scratch project requiring utopia-php/pools:^2.0 plus a local copy of this library resolves balancer + pools 2.0.2 + telemetry 0.4.6. The same project with the pre-existing 0.1 pin fails on You can only install one version of a package. CI installs with --ignore-platform-reqs, so ext-protobuf is not a factor there.

Breaking changes

Requiring ^0.4.0 is breaking for a consumer that pins telemetry to 0.1. Nothing in this repository does, but I cannot see every consumer of this library.

Related PRs and Issues

Needed by utopia-php/cdn#5, which declares every CDN provider that may hold a cached response for a domain as an option and filters down to the ones fronting it. A cache purge has to reach all of them — evicting one provider and leaving another serving a stale response is the same as not purging — so it needs the survivors, not a winner. This deletes the CdnBalancer subclass it was carrying to work around the missing accessor.

Checklist

  • I read the contributing guide
  • I ran composer lint
  • I ran composer check
  • I ran composer test

🤖 Generated with Claude Code

run() answers "which one option should I use", and the filtered set it
picks from was unreachable: $filters is private, so a caller that has to
act on every qualifying option — fanning a request out rather than
balancing between them — had to re-implement filtering outside the class,
or subclass to record filters as they were registered.

getFilteredOptions() is that set, extracted from run() unchanged. run()
now calls it and behaves exactly as before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR exposes all options surviving the balancer's filters and delegates run() to that shared filtering path. It also changes the telemetry dependency requirement, but the resulting constraint drops compatibility with telemetry 0.1 rather than allowing both supported lines.

  • Adds Balancer::getFilteredOptions() with ordered, reindexed results.
  • Adds coverage for composed filters, multiple survivors, and empty results.
  • Updates the locked telemetry package to 0.4.6 and changes the root telemetry constraint.

Confidence Score: 4/5

The PR is not yet safe to merge because its dependency constraint breaks installations that still resolve telemetry 0.1.x.

The new ^0.4.0-only requirement conflicts with telemetry 0.1.x consumers even though the compatibility change is intended to support both telemetry series.

Files Needing Attention: composer.json

Important Files Changed

Filename Overview
composer.json Changes telemetry compatibility to ^0.4.0 only, preventing installation for consumers that still require the previously supported 0.1 line.
composer.lock Updates the lock metadata and telemetry package entry to 0.4.6 consistently with the new root constraint.
src/Balancer/Balancer.php Extracts the existing filtering sequence into a public accessor and reuses it from run() without changing selection behavior.
tests/Balancer/BalancerTest.php Covers unfiltered results, multiple survivors, filter composition, reindexing, and empty filtered results.

Fix all with Greploop

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
### Issue 1
composer.json:18
**Telemetry 0.1 compatibility is dropped**

When an existing consumer requires telemetry 0.1.x, the new `^0.4.0`-only constraint makes Composer reject the dependency graph, turning the intended additive compatibility widening into a breaking change.

```suggestion
        "utopia-php/telemetry": "^0.1.0 || ^0.4.0"
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (4): Last reviewed commit: "Require telemetry 0.4" | Re-trigger Greptile

Group's telemetry pin at 0.1.* makes this library uninstallable next to
anything on the current utopia telemetry line: utopia-php/pools requires
^0.4.6, so any consumer pulling in pools — through utopia-php/client, for
one — cannot also require balancer.

The whole surface Group touches is unchanged between the two lines. The
Adapter::createHistogram and Histogram::record signatures are identical,
and Adapter\None exists in both, so the constraint is widened rather than
the code changed.

Verified against 0.4.6: tests, PHPStan --level max and PSR-12 all pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Meldiron added a commit to utopia-php/cdn that referenced this pull request Aug 13, 2026
CdnBalancer existed to work around a missing accessor, not to add
anything: run() returns one option and $filters is private, so the only
way to reach the filtered set was to shadow the filters on the way in.
utopia-php/balancer#10 exposes getFilteredOptions(), so the adapter now
takes an ordinary Utopia\Balancer\Balancer and the subclass is gone.
Options are checked to be CdnOption where they are used, since a plain
balancer accepts any Option.

Provider becomes a class of string constants, matching how the rest of
this library and appwrite/appwrite carry these values, and how
Certificates\Status already reads.

Extend/ now holds the one thing it was for: a typed option.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread composer.json Outdated
Meldiron and others added 2 commits August 13, 2026 21:26
Review preferred caret syntax. ^0.1.0 on its own cannot work: below 1.0.0
Composer's caret is patch-only, so it resolves 0.1.0 or 0.1.1 and still
conflicts with utopia-php/pools at ^0.4.6. Both series have to be named.

Same resolution as 0.1.*|0.4.*, in the requested style.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Drops the 0.1 series rather than supporting both. 0.1 was already
unreachable for any consumer that also pulls in utopia-php/pools, which
requires ^0.4.6, so keeping it alive supported a combination nothing could
install.

Requirements narrow rather than widen: telemetry 0.1.1 needed ext-protobuf
and ext-opentelemetry, 0.4.6 needs only ext-protobuf.

Breaking for a consumer pinning telemetry to 0.1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread composer.json
@Meldiron
Meldiron merged commit 7fc8922 into main Aug 13, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants