Skip to content

[architecture] Reassess isolated tooling distribution after CPX and domain extraction #197

Description

@coisa

Proposal / validation gate: this issue records an extraction design for maintainer validation. Repository/package names are candidates. Approve the boundary and migration plan before implementation; this task does not authorize creating repositories, implementing the extraction, releases or consumer rollout.

Revised question — optional isolated distribution, not a required architecture (2026-10-21)

The old Box/PHP-Scoper + shared-runtime design remains below as historical rationale; it is not a prerequisite for #240 domain extraction. Open #376 proposes CPX external runtime execution and LLM Skills. Its candidate SHA cde0cc6 is not merged/released. Changelog is already independent; do not restart its extraction or assume domains must depend on a generic DevTools runtime/container.

Remaining design work

The issue remains open with this narrower validation question. It does not ask to build a shim merely because the old proposal named one. Naming, artifact choice and implementation require maintainer validation.

Historical proposal — preserved, no longer prerequisite

Original #197 Box/PHP-Scoper proposal

Summary

Create a dedicated fast-forward/dev-tools-shim distribution built with Box + PHP-Scoper so Fast Forward tooling can be split into smaller reusable packages while still sharing the existing DevTools runtime, container, and automation capabilities.

Problem

fast-forward/dev-tools currently acts as one large Composer plugin and tool bundle. That works well for repository bootstrap, workflow sync, and the unified composer dev-tools entrypoint, but it makes it hard to extract parts of the project into smaller standalone packages that can be consumed independently.

A concrete example is changelog automation. A dedicated fast-forward/changelog package could be useful on its own in consumer repositories, but today the implementation is tightly coupled to the main dev-tools dependency graph and command surface.

At the same time, those smaller Fast Forward components would still benefit from DevTools capabilities during development, such as:

  • the existing container and service-provider wiring
  • command orchestration and process helpers
  • changelog, docs, and workflow conventions
  • shared QA tooling and CI surfaces

Goal

Introduce a dev-tools-shim artifact that packages the DevTools runtime in an isolated PHAR-style distribution, so that:

  • fast-forward/dev-tools can evolve into an orchestrator and aggregator of smaller Fast Forward components
  • standalone Fast Forward component packages can depend on fast-forward/dev-tools-shim as a require-dev tool dependency
  • those component packages can reuse DevTools internals and tooling without exposing DevTools' third-party dependency graph directly to their own consumers

Proposed Direction

  1. Create a dedicated fast-forward/dev-tools-shim package built with Box + PHP-Scoper.
  2. Scope the bundled runtime so the shim can safely embed DevTools internals and its third-party implementation dependencies.
  3. Keep fast-forward/dev-tools as the repository-facing orchestrator responsible for:
    • the Composer plugin integration
    • workflow wrappers and local GitHub actions
    • consumer sync flows
    • packaged skills, packaged agents, and repository bootstrap defaults
  4. Allow extracted Fast Forward component packages to use fast-forward/dev-tools-shim during development and CI.
  5. Move toward a model where fast-forward/dev-tools aggregates smaller Fast Forward components instead of permanently owning all behavior directly.

Why This Matters

This would let Fast Forward packages reuse a common runtime and toolchain while reducing direct dependency pressure on downstream consumers.

In practice, it could help with cases where the current dev-tools dependency set is too broad or too invasive, especially because the repository currently requires runtime and QA packages such as:

  • php-di/php-di
  • phpunit/phpunit
  • phpunit/php-code-coverage
  • friendsofphp/php-cs-fixer
  • rector/rector
  • phpdocumentor/shim
  • symplify/easy-coding-standard
  • other tool-specific packages that are useful to DevTools itself but may be undesirable as direct dependency constraints for a smaller component package

A shim would also allow Fast Forward components to reuse the existing DI surface from DevToolsServiceProvider instead of duplicating container choices package by package.

Repository Constraints And Challenges To Capture

The issue SHOULD explicitly account for the current repository shape:

1. Composer-plugin and orchestrator split

fast-forward/dev-tools is currently a composer-plugin with:

  • plugin capability registration
  • bin/dev-tools
  • synchronized workflow wrappers in resources/github-actions/
  • local reusable GitHub actions in .github/actions/
  • sync orchestration for repository defaults, skills, agents, changelog automation, wiki, and other managed assets

The shim cannot simply replace the main package. We need a deliberate split between:

  • the repository orchestration package (fast-forward/dev-tools)
  • the isolated reusable runtime/tool distribution (fast-forward/dev-tools-shim)

2. Service container reuse

DevToolsServiceProvider currently wires a large shared runtime:

  • process builder / queue
  • filesystem and file locators
  • changelog services
  • git client
  • console loader and logger services
  • diffing, gitignore, gitattributes, license, Twig loader, clock, etc.

If extracted component packages are expected to reuse this runtime, we need a stable contract for what the shim exposes versus what remains private implementation detail.

3. Third-party dependency scoping strategy

A major motivation is avoiding consumer dependency conflicts, but some dependencies have public-facing development ergonomics.

Example challenge:

  • a package that installs only the shim would not automatically have the real phpunit/phpunit classes available to extend in its own test suite unless we make an explicit decision about what is bundled, what is scoped, and what remains a normal Composer dependency.

We need a clear strategy for cases like:

  • PHPUnit APIs used directly by package tests
  • Prophecy / coverage helpers used directly in package tests
  • tool configs or extension classes that are meant to be referenced by consumers

This may require selectively scoping only implementation dependencies, or splitting some concerns into separate packages instead of putting everything into one giant scoped PHAR.

4. Release and version propagation

If dev-tools-shim becomes a separate package or artifact, the release flow needs to keep it aligned with fast-forward/dev-tools.

One specific challenge is that fast-forward/dev-tools releases would need to trigger a shim release/update workflow so the shim can be rebuilt and published at the matching version.

The issue SHOULD cover:

  • how the shim version mirrors DevTools releases
  • whether the shim is released from the same repository or a dedicated repository
  • what workflow handoff or cross-repository dispatch is required

5. Sync and workflow compatibility

fast-forward/dev-tools currently synchronizes workflow wrappers, local action references, packaged skills, packaged agents, and repository bootstrap files into consumers.

The shim should not blur those responsibilities. The issue SHOULD keep clear that the shim is for isolated runtime/tool reuse, while the main dev-tools package remains the owner of:

  • consumer sync behavior
  • workflow wrappers and repository automation defaults
  • packaged agents / packaged skills surfaces
  • broader repository orchestration

6. Artifact duplication and content divergence

Using a shim means some files will effectively exist twice:

  • normal repository source in fast-forward/dev-tools
  • scoped / packaged equivalents inside the shim artifact

That duplication is acceptable only if we define what is intentionally replicated and how drift is prevented when the packaged content differs from repository source because of scoping, stubs, or build-time rewriting.

Non-Goals

  • This issue should not immediately extract all DevTools functionality into separate packages.
  • This issue should not decide every final package boundary up front.
  • This issue should not replace the existing fast-forward/dev-tools consumer sync and workflow orchestration role.

Acceptance Criteria

  • A design is documented for fast-forward/dev-tools-shim using Box + PHP-Scoper.
  • The design clearly distinguishes fast-forward/dev-tools orchestration responsibilities from shim responsibilities.
  • The plan covers how extracted component packages can depend on the shim in require-dev and reuse DevTools services safely.
  • The plan addresses public-vs-scoped dependency strategy, especially around PHPUnit and other developer-facing tool APIs.
  • The plan addresses version propagation and release workflow coordination between DevTools and the shim artifact.
  • The plan addresses how build-time replicated files are generated and kept in sync.
  • Follow-up implementation issues can be split cleanly from this design issue.

Activity

  1. added theissue type on Apr 24, 2026
  2. coisa commented on Apr 24, 2026

    @coisa
    ContributorAuthor

    Discussion Draft: incremental component extraction and dev-tools-shim architecture

    This is a proposed action plan for turning fast-forward/dev-tools into an orchestrator of specialized Fast Forward packages while preserving the current user-facing ergonomics:

    • consumers should still be able to run familiar composer ... commands;
    • this repository should still provide a standalone bin/dev-tools workflow for development;
    • extracted packages should be able to use Fast Forward tooling during their own development without inheriting the full unscopeable dependency graph;
    • a future fast-forward/dev-tools-shim should provide an isolated tool/runtime distribution for smaller Fast Forward packages.

    The important architectural distinction is that the current coupling is not just "we use Composer classes". The current package is doing several jobs at once:

    1. Composer plugin integration.
    2. A standalone console application.
    3. Domain commands and handlers.
    4. Heavy QA/tool orchestration.
    5. Consumer repository synchronization and workflow packaging.

    The extraction should split these jobs gradually, not all at once.

    Current Composer coupling map

    Current direct Composer touchpoints found in the repository:

    Area Current coupling Why it exists today Suggested replacement strategy
    Standalone application FastForward\DevTools\Console\DevTools extends Composer\Console\Application Lets bin/dev-tools behave like a Composer-flavored console application even when the package is the root package and cannot consume itself as a Composer plugin. Replace with Symfony\Component\Console\Application. Keep Composer-specific behavior in a plugin bridge only.
    Public commands Every public command extends Composer\Command\BaseCommand Composer capability commands are currently the same classes used by the standalone app. Split command adapters from handlers. Components expose handlers and optionally Symfony commands. dev-tools exposes thin Composer BaseCommand adapters only for the Composer plugin surface.
    Capability provider Composer\Plugin\Capability\CommandProvider, Composer\Command\BaseCommand filtering Registers commands inside a consumer's Composer process. Keep this inside fast-forward/dev-tools only. It can create Composer adapters around shared handlers instead of returning the same standalone commands.
    Plugin lifecycle PluginInterface, Capable, EventSubscriberInterface, ScriptEvents, Event, Composer, IOInterface Needed for installed-consumer plugin integration and post-install/update sync. Keep in fast-forward/dev-tools. Use composer-plugin-api in require; keep composer/composer in require-dev for tests/static analysis/autocomplete. Runtime classes come from the host Composer process.
    Composer\Factory::getComposerFile() Used by ComposerJson, FundingCommand, UpdateComposerJsonCommand Resolves the active composer.json path, including the COMPOSER env behavior. Introduce ProjectComposerFileResolver with explicit tests for COMPOSER, cwd, relative path, absolute path, and directory edge cases.
    Composer\Json\JsonFile Used for reading composer.json, installed.json, and funding metadata Convenient JSON parsing and Composer-specific behavior. Replace with a small JsonDocumentReader/JsonDocumentWriter using json_decode(..., JSON_THROW_ON_ERROR) plus repository-specific errors. Keep Composer's reader only behind an optional bridge if needed.
    Composer\Json\JsonManipulator Used by UpdateComposerJsonCommand to mutate composer.json while preserving structure. This is one of the stronger remaining reasons to keep Composer internals nearby. Extract a ComposerJsonEditor interface. Start with current JsonManipulator behind an implementation in a Composer bridge. Later evaluate a custom stable writer or a normalizer-driven approach.
    Composer\InstalledVersions Used in ComposerJson and RectorConfig. Reads installed package metadata. This does not justify composer/composer by itself because it is generated in normal Composer installs. Wrap behind InstalledPackageRepositoryInterface. Use Composer\InstalledVersions when available; fallback to vendor/composer/installed.json when needed.
    Composer\Util\Platform Used by GithubActionOutput for env checks. Convenience wrapper for environment lookup. Replace with a small Environment/RuntimeEnvironment abstraction around getenv()/$_SERVER.
    Composer IO Tests and command behavior rely on Composer IOInterface through BaseCommand. Current command classes are Composer commands. Handlers receive PSR logger/output DTOs. Composer adapters map IOInterface to the shared logger/output contract. Symfony adapters map Symfony IO/output to the same contract.
    Composer process execution in plugin event getLoop()->getProcessExecutor()->execute(...) Post-install/update sync is delegated through Composer's process executor. Keep plugin bridge-specific at first. Later prefer invoking the shared sync handler directly, with a process fallback only when isolation is required.

    Target shape

    The target model should be:

    fast-forward/dev-tools
      Composer plugin + repository orchestrator
      requires component packages
      exposes Composer BaseCommand adapters
      ships consumer sync, workflows, local actions, skills/agents/bootstrap
    
    fast-forward/dev-tools-runtime
      small reusable runtime contracts and infrastructure
      Symfony Console app bootstrap for bin/dev-tools-style execution
      no composer/composer dependency
    
    fast-forward/<component>
      focused package such as changelog, testing, docs, sync, code-quality
      owns handlers/domain logic
      MAY expose Symfony commands
      MUST NOT require composer/composer only for command execution
      MAY require-dev fast-forward/dev-tools-shim for its own QA/tooling
    
    fast-forward/dev-tools-shim
      Box + PHP-Scoper isolated PHAR/tool package
      scoped heavy toolchain and selected Fast Forward runtime
      used by smaller packages in require-dev
      does not force its scoped dependencies onto package consumers
    

    A key constraint: avoid a dependency cycle where component packages require-dev the shim while the shim also Composer-requires those same component packages. The safer approach is:

    • components depend on shared contracts/runtime, not on dev-tools;
    • dev-tools requires components and wires them into consumer-facing orchestration;
    • dev-tools-shim is built as an artifact/tool distribution and should avoid normal Composer require edges back into packages that are expected to require-dev it;
    • if the shim must include component behavior, prefer build-time inclusion or plugin-style discovery over Composer dependency cycles.

    Command architecture

    For each command domain, use three layers:

    1. Handler / application service

      • owns behavior;
      • accepts typed options DTOs;
      • returns typed result DTOs or integer exit status;
      • uses PSR logger/output abstractions;
      • has no Symfony InputInterface, no Composer BaseCommand, and no Composer IO.
    2. Symfony command adapter

      • lives in the component package or runtime package when standalone CLI matters;
      • maps Symfony input/options into the handler DTO;
      • powers bin/dev-tools and future component-local binaries.
    3. Composer command adapter

      • lives in fast-forward/dev-tools only;
      • extends Composer\Command\BaseCommand if Composer capability compatibility requires it;
      • delegates to the same handler as the Symfony adapter.

    Example for testing:

    fast-forward/testing
      RunTestsHandler
      TestsOptions
      TestsResult
      TestsSymfonyCommand (optional)
    
    fast-forward/dev-tools
      TestsComposerCommand extends Composer\Command\BaseCommand
      delegates to RunTestsHandler
    
    fast-forward/dev-tools-shim
      can run the Symfony command/handler through isolated tooling
    

    This keeps the package extractable while preserving the current composer tests UX.

    Proposed package boundaries

    1. fast-forward/dev-tools-runtime

    Purpose:

    • shared runtime used by dev-tools, components, and the shim;
    • no Composer plugin dependency;
    • no heavy QA tools.

    Likely contents:

    • process builder / process queue contracts and default Symfony Process implementation;
    • filesystem wrapper and finder factory;
    • path resolvers and managed workspace helpers;
    • console logger/output processors;
    • runtime environment abstraction;
    • lightweight container/service-provider contracts;
    • generic resource diffing.

    Dependencies:

    • php:^8.3
    • psr/log
    • psr/container
    • psr/clock
    • symfony/console
    • symfony/filesystem
    • symfony/finder
    • symfony/process
    • sebastian/diff
    • possibly container-interop/service-provider
    • avoid composer/composer

    2. fast-forward/composer-metadata

    Purpose:

    • own reading and writing Composer project metadata without forcing the full Composer package everywhere.

    Likely contents:

    • ProjectComposerFileResolver
    • ComposerJsonReader
    • ComposerJsonMetadata DTOs (Author, Support, Funding)
    • InstalledPackageRepositoryInterface
    • ComposerJsonEditorInterface
    • optional ComposerJsonManipulatorEditor implementation in a bridge namespace.

    Dependencies:

    • php:^8.3
    • symfony/filesystem or runtime filesystem contracts
    • maybe composer/composer only in a dedicated bridge package or require-dev

    Migration note:

    • Composer\Factory::getComposerFile() and Composer\Json\JsonFile should be replaced early.
    • JsonManipulator should be isolated behind an interface before deciding whether to replace it.

    3. fast-forward/changelog

    Purpose:

    • extracted changelog domain and CLI.

    Likely contents:

    • current src/Changelog/*
    • DependabotChangelogEntryMessageResolver
    • changelog command handlers for entry, check, next-version, promote, show
    • optional Symfony command adapters.

    Dependencies:

    • php:^8.3
    • fast-forward/dev-tools-runtime or smaller contracts package
    • psr/log
    • psr/clock
    • no composer/composer

    dev-tools role:

    • provide Composer BaseCommand adapters for composer changelog:*;
    • keep GitHub Actions release/changelog workflows as repository orchestration.

    4. fast-forward/testing

    Purpose:

    • own PHPUnit execution orchestration and coverage summary logic without exposing PHPUnit as a runtime dependency to every consumer unless intentionally chosen.

    Likely contents:

    • RunTestsHandler
    • TestsOptions
    • CoverageSummary, CoverageSummaryLoader
    • PHPUnit command argument builder
    • optional PHPUnit extension classes should be considered separately because consumers may reference them directly.

    Dependencies:

    • php:^8.3
    • fast-forward/dev-tools-runtime
    • psr/log
    • phpunit/php-code-coverage only if CoverageSummaryLoader directly type-checks CodeCoverage
    • avoid making phpunit/phpunit a hard runtime dependency unless the package intentionally exposes PHPUnit extension APIs.

    Shim strategy:

    • the shim can contain scoped PHPUnit for command execution;
    • packages that extend PHPUnit classes in their own tests still need real PHPUnit in require-dev or a deliberately unscoped public testing extension package.

    Open design question:

    • split user-extendable PHPUnit extension classes into fast-forward/phpunit-extension with real PHPUnit dependencies, while the shim owns isolated command execution.

    5. fast-forward/documentation

    Purpose:

    • own documentation generation handlers.

    Likely contents:

    • docs/wiki/phpdoc handlers;
    • phpDocumentor XML rendering;
    • Twig templates for generated configuration;
    • Markdown/HTML output orchestration.

    Dependencies:

    • php:^8.3
    • fast-forward/dev-tools-runtime
    • twig/twig
    • fast-forward/phpdoc-bootstrap-template
    • phpDocumentor tooling should preferably be invoked through the shim or remain a dev dependency, not leak broadly.

    Shim strategy:

    • scope phpDocumentor and markdown tooling inside the shim when possible;
    • keep templates/resources package-visible when consumers need to inspect them.

    6. fast-forward/code-quality

    Purpose:

    • own code-style, refactor, phpdoc, and maybe standards subflows that primarily orchestrate external QA tools.

    Likely contents:

    • handlers for ECS, Rector, PHP-CS-Fixer/PHPDoc cleanup;
    • config resolvers for packaged/local ecs.php, rector.php, .php-cs-fixer.dist.php;
    • command-result aggregation.

    Dependencies:

    • php:^8.3
    • fast-forward/dev-tools-runtime
    • psr/log
    • heavy tools should move toward shim-scoped execution where possible:
      • rector/rector
      • symplify/easy-coding-standard
      • friendsofphp/php-cs-fixer
      • ergebnis/rector-rules
      • rector/jack

    Important caveat:

    • if consumer configs reference tool classes directly, those classes cannot be only scoped inside a PHAR. Public config APIs and scoped execution need a deliberate boundary.

    7. fast-forward/dependency-health

    Purpose:

    • own dependency analysis and outdated/breakpoint workflows.

    Likely contents:

    • current dependencies behavior;
    • config around shipmonk/composer-dependency-analyser and Jack.

    Dependencies:

    • php:^8.3
    • fast-forward/dev-tools-runtime
    • heavy analysis tools should be shim-managed when possible.

    8. fast-forward/repository-sync

    Purpose:

    • own consumer bootstrap file synchronization that is not specifically GitHub Actions.

    Likely contents:

    Dependencies:

    • php:^8.3
    • fast-forward/dev-tools-runtime
    • fast-forward/composer-metadata
    • symfony/yaml
    • no composer/composer except optional metadata bridge.

    dev-tools role:

    • keep dev-tools:sync as the orchestrator command that composes these handlers.

    9. fast-forward/github-automation

    Purpose:

    • own reusable workflow wrappers and local GitHub Actions as packaged assets, or keep them in dev-tools if we decide workflow sync is core orchestration.

    Likely contents if extracted:

    • resources/github-actions/*
    • .github/actions/* source payloads
    • workflow validation helpers
    • GitHub Pages/wiki preview action support

    Dependencies:

    • mostly packaging/assets;
    • Node scripts and shell scripts where already used;
    • no PHP dependency unless validators are added.

    Recommendation:

    • do not extract first. Workflows are central to dev-tools orchestration and release coordination, so they can remain in dev-tools until smaller domain packages stabilize.

    10. fast-forward/agents

    Purpose:

    Likely contents:

    • .agents/agents
    • maybe .agents/skills later, if skills should share the same distribution strategy.

    Dependencies:

    • likely none or only Composer installer metadata.

    dev-tools role:

    • ensure consumers install/sync the package into the expected directory;
    • stop treating agent payloads as internal DevTools source over time.

    What remains in fast-forward/dev-tools

    fast-forward/dev-tools should remain the repository-facing orchestrator:

    • Composer plugin registration and capability provider;
    • thin Composer BaseCommand adapters;
    • dev-tools:sync orchestration;
    • workflow wrappers and local action packaging;
    • repository bootstrap defaults;
    • release automation wiring;
    • docs that describe the unified Fast Forward workflow;
    • dependency on extracted Fast Forward packages.

    Target dependencies:

    • php:^8.3
    • composer-plugin-api:^2.0
    • symfony/console
    • fast-forward/dev-tools-runtime
    • extracted Fast Forward packages, such as fast-forward/changelog, fast-forward/testing, etc.
    • composer/composer should move toward require-dev only, used for tests/static analysis/autocomplete around the plugin bridge.

    What bin/dev-tools should become

    The standalone binary should stop depending on Composer\Console\Application.

    Target:

    • bin/dev-tools boots a plain Symfony\Component\Console\Application;
    • it registers Symfony command adapters around the same handlers used by Composer command adapters;
    • it does not need the package to consume itself as a Composer plugin;
    • it becomes the development entrypoint for this repository and for shim internals.

    This keeps the current local DX while removing the main reason the whole console layer needs composer/composer.

    What dev-tools-shim should do

    fast-forward/dev-tools-shim should be treated as an isolated development tool distribution, not as the main repository orchestrator.

    Responsibilities:

    • bundle a stable executable with Box;
    • scope implementation dependencies with PHP-Scoper;
    • expose shared Fast Forward tool commands to component repositories;
    • provide a stable development-time entrypoint for smaller repos;
    • avoid leaking tool dependency constraints to consumers.

    Non-responsibilities:

    • do not own consumer sync policy;
    • do not own repository workflow wrappers;
    • do not replace the Composer plugin;
    • do not become the normal runtime dependency of every component unless absolutely necessary.

    Dependency scoping strategy

    Use three buckets:

    1. Public APIs that consumers/components may extend or reference

      • do not scope these blindly;
      • examples: PHPUnit extension APIs, Symfony command interfaces if packages expose commands, Fast Forward contracts.
    2. Implementation-only tool dependencies

      • safe candidates for scoping;
      • examples: internal tool runners, phpDocumentor execution dependencies, PHP-CS-Fixer internals, Rector/ECS internals when configs do not expose their classes.
    3. Bridge dependencies

      • keep isolated in bridge packages or adapters;
      • examples: Composer JsonManipulator, Composer plugin command adapters, host Composer runtime classes.

    A practical rule: if package users need to import a class in their own PHP code or config, that class should not only exist inside a scoped PHAR.

    Migration phases

    Phase 0: Architecture guardrails

    • Document handler/adapter boundaries.
    • Add tests proving command handlers can run without Composer BaseCommand.
    • Add dependency-analysis rules that prevent new Composer\* imports outside approved bridge namespaces.
    • Keep the composer-plugin-consumer fixture as a regression surface.

    Phase 1: Replace standalone Composer application

    • Change DevTools from Composer\Console\Application to Symfony Application.
    • Keep Composer capability provider working through dedicated Composer adapters.
    • Verify:
      • php bin/dev-tools list
      • fixture composer list
      • fixture composer agents --help
      • core commands via both entrypoints.

    Phase 2: Introduce handler DTOs for one low-risk domain

    Recommended first domain: changelog.

    Why:

    • it already has a clear domain model;
    • it has fewer external process dependencies than testing/docs/code-style;
    • it is a likely first extracted package.

    Deliverables:

    • ChangelogEntryHandler, ChangelogCheckHandler, etc.;
    • Symfony command adapter;
    • Composer command adapter;
    • unchanged visible CLI behavior.

    Phase 3: Extract fast-forward/changelog

    • Move changelog domain and handlers to the new package.
    • Keep Composer adapters in dev-tools.
    • Have dev-tools require fast-forward/changelog.
    • Use dev-tools-shim in the changelog repo's require-dev once available.

    Phase 4: Extract runtime/core infrastructure

    • Move process/filesystem/path/logger/runtime abstractions to fast-forward/dev-tools-runtime.
    • Keep DevTools-specific service wiring in dev-tools.
    • Ensure components depend on the runtime package rather than on the monolithic dev-tools package.

    Phase 5: Extract repository sync

    Phase 6: Build the first dev-tools-shim

    • Create Box config.
    • Add PHP-Scoper config.
    • Start with a minimal command set, likely changelog + runtime utilities.
    • Publish the shim as a versioned artifact/package.
    • Add a consumer/component fixture that installs only the shim as require-dev and runs a command.

    Phase 7: Move heavy tool orchestration behind shim

    • Gradually move testing/docs/code-style/refactor/dependency-health execution to shim-backed handlers.
    • Keep public extension/config classes unscoped where users need to reference them.
    • Add explicit tests for consumer projects that do not install the real heavy tools directly.

    Phase 8: Release propagation

    • Add release workflow coordination so dev-tools releases trigger or require a matching dev-tools-shim release.
    • Decide whether shim releases are same-repo artifacts or separate-repo releases.
    • Include smoke tests that install:
      • fast-forward/dev-tools in a consumer fixture;
      • one extracted package with fast-forward/dev-tools-shim in require-dev;
      • a project using both without dependency conflicts.

    Suggested first follow-up issues

    1. Replace Composer\Console\Application with Symfony Console for bin/dev-tools while keeping Composer plugin command discovery intact.
    2. Introduce handler/DTO boundaries for changelog commands without changing behavior.
    3. Add dependency-analysis rules that allow Composer imports only in bridge namespaces.
    4. Extract project Composer metadata access behind ProjectComposerFileResolver, JsonDocumentReader, and ComposerJsonEditorInterface.
    5. Prototype fast-forward/changelog as the first extracted component package.
    6. Prototype fast-forward/dev-tools-shim with Box + PHP-Scoper using the smallest useful command set.
    7. Define public-vs-scoped dependency policy for PHPUnit, Rector, ECS, phpDocumentor, PHP-CS-Fixer, and config classes.

    Success criteria for the architecture

    • dev-tools can still provide the unified Composer plugin UX.
    • bin/dev-tools can run without extending Composer's console application.
    • command behavior lives in handlers that can be reused by Symfony commands, Composer adapters, and shim execution.
    • smaller Fast Forward packages can be developed with dev-tools-shim in require-dev without depending on the monolithic dev-tools package.
    • consumers are not forced to accept direct version constraints for the entire QA/tooling stack unless they intentionally use the unscoped public APIs.
    • extracted components remain specialized and independently testable.
  3. changed the title [-][architecture] Design a Box + PHP-Scoper dev-tools-shim for extracted Fast Forward components[/-] [+][architecture] Reassess isolated tooling distribution after CPX and domain extraction[/+] on Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions