Skip to content

fix: compose all provider extensions by default - #49

Draft
coisa wants to merge 2 commits into
mainfrom
codex/issue-48-provider-composition
Draft

coisa wants to merge 2 commits into
mainfrom
codex/issue-48-provider-composition

Conversation

@coisa

@coisa coisa commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Providers registered separately could return before later extensions ran, or let an earlier extension-only provider shadow a later factory. The helper, factory and builder now select the first callable factory and apply all provider extensions in registration order by default, with no activation API.

Composition state stays in existing classes. AggregateContainer stores source order, required-entry policy and inferred-alias origins internally; ServiceProviderContainer owns provider definitions, extension composition and shared caches. The builder assembles those objects. There are no additional runtime classes or per-provider wrapper objects.

The aggregate can directly compose PSR-11 sources and providers, and the provider adapter accepts an ordered provider list. Selected factories retain their original positions against interleaved external sources. Explicit AggregateServiceProvider keeps its existing last-factory precedence. Selected provider failures propagate instead of becoming successful fallback values; failed chains remain retryable.

Updates regression coverage, the isolated production-consumer CI job, RST/PHPDoc, runnable examples, the bundled consumer skill and a fixed/patch changelog fragment.

The latest local validation ran the configured GrumPHP tasks sequentially, without a hook bypass. The overall gate failed and the PR remains draft.

  • Composer validation, PHP/JSON/YAML lint, Rector, PHPDoc, ECS and a separate Composer Normalize dry run passed.
  • The PHP 8.5 suite completed 290 tests and 997 assertions; the explicit 80% coverage requirement passed at 93.92%.
  • The direct PHP 8.4 suite reached 290 tests and 997 assertions, then emitted a third-party desktop-notification subscriber warning. This is not counted as a clean gate.
  • The PHP 8.3 suite completed 290 tests and 993 assertions with one existing skip requiring the intl extension.
  • All four isolated production-consumer combinations (PHP 8.3/8.5 and minimum/current dependencies) passed 33 tests and 205 assertions each, with platform requirements checked against their respective runtimes.

The complete DevTools composite failed in Code Style: its dependency lock refresh triggers plugin synchronization that mishandles Git worktrees. Skill synchronization also encountered a filesystem denial. Report generation additionally produced malformed JUnit output and a notification-subscriber warning. These failures remain visible; no checks, permissions, hooks or vendor code were changed to turn them into a pass.

Dependencies were installed only in the authorized worktree. No new runtime or extension was installed. Generated scaffolding changes were restored, and no implementation changes, commit, push, merge or release followed this validation. Full logs remain local.

The two original published commits used --no-verify, as previously disclosed. That historical bypass was not repeated. The published PR head is unchanged. A clean gate is still required.

Additional diagnostic review:

  • The published head and main are unchanged, and no new review findings were posted. No full suite was repeated.
  • A small read-only probe of the installed DevTools result interpreter confirmed two cases: a failed PHPUnit payload with a warning is labeled successful when the process exit is zero; two consecutive success/failure payloads also leave an exit-derived success while the payloads fall back to raw text.
  • A separate saved-artifact check confirmed the two conflicting PHPUnit snapshots and an invalid JUnit document with a second XML declaration. These are diagnostic reproductions, not passing gates.
  • This dependency belongs with the existing Testing issue #380 and DevTools PR #376. Their work is not assumed to be present in this consumer. No vendor/runtime patch, check suppression, permission change or code publication was performed here.

Dependency handoff follow-up:

  • Read back the focused Testing qualification: 40 fixture tests and 110 assertions, with scoped style checking and review. This is not a released runtime or qualification of the real Container incident.
  • The installed consumer tooling is unchanged. Lock-refresh/plugin synchronization, worktree hook-target resolution and the skills filesystem denial remain independent blockers.
  • Prepared a bounded replay plan for the exact saved stdout and malformed JUnit. The stdout must retain the late failure; the old JUnit must be rejected rather than repaired into a pass. Regenerating a clean real consumer artifact remains pending.
  • No new suite, matrix, compilation, installation, vendor substitution, hook/permission change or code publication was performed for this follow-up. The gate remains failed.

Fixes #48.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Changelog

✅ Contribution check passed.

Head: fbb7df58b9fbdf4759401fcaf7b7454bba80cfca

Base: 67865fa35231c11e38c9facbfe775e0c5fbe2461

Contribution: 1 new valid fragment(s). Policy: ordinary.

  • compose-provider-extensions.md — fixed, patch

    Fixes cross-provider extension composition by default in `container()`, `ContainerFactory::create()` and `ContainerBuilder::build()`. The first callable factory keeps precedence and all provider extensions run in registration order after selection, including earlier extension-only providers. Selected provider failures propagate instead of being masked by fallback. Explicit `AggregateServiceProvider` retains its last-factory precedence.

This branch has not been deployed

No deployments
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.

Compose all extensions across providers passed to container()

1 participant