Skip to main content

Command Palette

Search for a command to run...

Core Review Request: Deterministic Artifacts, Package Boundaries, and SSoT in a PHP 8.4+ Framework

A focused request for feedback on Coretsia’s core: contracts, foundation primitives, kernel lifecycle, module planning, runtime-driver selection, and rerun-no-diff artifacts.

Updated
13 min read
Core Review Request: Deterministic Artifacts, Package Boundaries, and SSoT in a PHP 8.4+ Framework
V
I write about PHP framework architecture, deterministic tooling, strict package boundaries, source-of-truth documentation, and the engineering decisions behind Coretsia — an early-stage PHP 8.4+ framework experiment.

Coretsia is an early-stage PHP 8.4+ framework experiment, but this post is not asking for review of the entire future framework. I am looking for focused feedback on the core that is currently being finalized: package boundaries, deterministic artifacts, module planning, runtime-driver selection, and the connection between code, tests, and source-of-truth documentation. If you have maintained long-lived PHP systems, internal platforms, framework integrations, or package-heavy monorepos, critical feedback would be especially useful.

I am building an early-stage PHP 8.4+ framework called Coretsia, where deterministic tooling is treated as part of the framework foundation rather than as an afterthought. One of the core goals is simple to state but difficult to enforce: generated artifacts should not create meaningless Git diffs, package boundaries should be explicit, and architectural rules should have a canonical source of truth.

This article is not a release announcement, and it is not a call for adoption. The project is not production-stable, does not have its first stable release yet, and should not be evaluated as a finished alternative to Laravel, Symfony, Spiral, Yii, Mezzio, or CodeIgniter.

The review request is intentionally narrow: I am asking for feedback on the core packages, not on the entire future framework. The core is close enough to its intended Phase 1 shape that external review is now useful, but still early enough that architectural criticism can change the direction. I am publishing this because it is much easier to criticize framework architecture before it becomes stable and starts accumulating backward-compatibility constraints.

What I am looking for is specific, constructive feedback: whether the package boundaries are understandable, whether the source-of-truth documents feel useful or too formal, whether the repository is easy to evaluate locally, and whether the codebase and documentation disagree anywhere. Feedback from people who have maintained long-lived PHP systems, internal platforms, framework integrations, or package-heavy monorepos would be especially valuable.

Why I am asking for review before the first stable release

Most framework problems do not appear in the first version. A framework can start clean, but conventions may drift over time, generated files may start creating Git noise, documentation may stop matching the implementation, and package boundaries may become informal. Eventually, nobody is completely sure where a canonical rule actually lives.

Many PHP projects solve these problems later through internal platform layers, CI scripts, documentation conventions, custom tooling, or team discipline. That can work, and many mature teams do this successfully. Coretsia exists to explore a narrower foundation-level question: what happens if deterministic tooling, strict package boundaries, and Single Source of Truth architecture are treated as framework constraints from the beginning?

This does not mean existing frameworks ignore these concerns. They do not. It also does not mean Coretsia is more mature than existing frameworks. It is not. The point is to test a different starting assumption and expose that assumption to criticism before the core becomes stable.

What is currently implemented in the core

The main focus of this article is the framework core. Active work is currently centered on contracts, foundation primitives, kernel lifecycle, configuration rules, module planning, deterministic artifacts, and runtime-driver selection. Later platform areas such as HTTP runtime, database integration, queues, events, cache, security, and higher-level application modes are separate roadmap areas and are not the primary subject of this review.

The current core review surface is:

Package Role
coretsia/core-contracts Public contracts, ports, interfaces, enums, and cross-package boundaries
coretsia/core-dto-attribute Canonical DTO marker attribute used as explicit transport-shape metadata
coretsia/core-foundation Container, deterministic primitives, context, diagnostics, reset orchestration, and low-level runtime services
coretsia/core-kernel Bootstrap phases, config merging and validation, module planning, artifacts, fingerprints, cache verification, and runtime-driver matrix selection

There are also supporting packages such as platform-cli (a Phase 0 kernel-free CLI base), devtools-cli-spikes, and devtools-internal-toolkit. Those packages are useful context because they exercise the core rules through tooling, CLI behavior, and runtime-adjacent checks. However, they are not the main review target of this article.

I am asking reviewers to look at code and documentation together, because in this project those two surfaces are intentionally connected. If an architectural rule exists only in code, only in a README, or only in an old discussion, that is already a problem. If a rule affects package structure, runtime behavior, artifact shape, configuration ownership, or public contracts, it should have a canonical place, and the implementation should either enforce it or make clear why enforcement is not possible yet.

Example 1: deterministic JSON is not cosmetic

One representative piece of the core is stable JSON encoding in core-foundation. Coretsia does not treat diagnostic and artifact serialization as “call json_encode() on whatever array is currently available.” Instead, maps are recursively normalized and sorted by byte-order string comparison, while lists preserve caller-supplied order.

The accepted value model is intentionally narrow: null, bool, int, string, lists, and maps with string keys. This restriction is not meant to make serialization elegant. It is meant to make diagnostic payloads, exported structures, and artifact-related data deterministic and safe.

StableJsonEncoder::encodeStable([
    'z' => 'last',
    'a' => [
        'z' => 'nested-last',
        'a' => 'nested-first',
    ],
]);

// The JSON object shape is always:
// {"a":{"a":"nested-first","z":"nested-last"},"z":"last"}
// The encoder also appends a final LF to the returned string.

The implementation also rejects floats, resources, objects, closures, and non-string map keys. This may look strict, but the goal is to avoid unsafe or non-portable runtime shapes before they enter diagnostics or artifact-related payloads. The encoder is not a generic redaction engine: callers still own semantic redaction for sensitive strings such as paths, tokens, credentials, payload fragments, or environment-specific values. The strict JSON-like model only ensures that once a caller provides a safe shape, the encoded bytes are deterministic and bounded to supported scalar/list/map structures.

This is one area where review would be useful. Is this JSON-like model too restrictive, or is it the right level of strictness for framework diagnostics, artifacts, and exported lifecycle payloads?

Example 2: module metadata is explicit instead of filesystem magic

Modules in Coretsia are described through Composer metadata, not through filesystem scanning or implicit runtime discovery. For example, the kernel package declares itself as a runtime module with a module id, module class, service providers, required modules, conflicts, and default configuration path.

{
  "extra": {
    "coretsia": {
      "kind": "runtime",
      "moduleId": "core.kernel",
      "moduleClass": "Coretsia\\Kernel\\Module\\KernelModule",
      "providers": [
        "Coretsia\\Kernel\\Provider\\KernelServiceProvider"
      ],
      "requires": [
        "core.foundation"
      ],
      "conflicts": [],
      "defaultsConfigPath": "config/kernel.php"
    }
  }
}

The kernel reads this metadata, normalizes it into module descriptors and manifests, and then builds a module graph with required module edges, preset-driven optional modules, transitive dependencies, conflict checks, optional-missing warnings, and deterministic topological ordering. The resolver intentionally reads runtime dependency and conflict edges from normalized Coretsia module metadata, not from arbitrary filesystem paths, loaded module classes, or Composer-level require and conflict sections.

The review question here is whether this model is explicit in a useful way or simply verbose. I would like to know whether the distinction between Composer package dependencies and Coretsia runtime module dependencies is clear enough, and whether the documentation explains why these two dependency models are not treated as the same thing.

Example 3: runtime drivers are derived from configuration only

The current kernel contains a RuntimeDriverGuard that derives selected runtime drivers only from canonical configuration input. It does not inspect environment variables, loaded PHP extensions, process names, CLI arguments, open ports, filesystem adapters, generated artifacts, service containers, or reflection. That restriction is intentional.

The guard handles HTTP drivers such as classic PHP, FrankenPHP, Swoole, RoadRunner, and worker-based HTTP. It also handles background worker queue mode. If no non-classic HTTP driver is enabled, the selected HTTP driver is http.classic. If more than one HTTP driver is enabled, the guard fails with a deterministic conflict exception and stable reason tokens.

A simplified example of the intended behavior:

\(drivers = (new RuntimeDriverGuard())->detect(\)config);

$drivers->httpDriverId();        // "http.classic", "http.roadrunner", etc.
$drivers->backgroundDriverIds(); // e.g. ["bg.worker_queue"]
$drivers->driverIds();           // sorted canonical driver ids

The important part is not the driver names themselves. The important part is where responsibility lives. Config validation owns declared config shapes and framework-owned unknown-key policy. RuntimeDriverGuard owns runtime-driver matrix selection. Module compatibility is checked separately against a caller-provided ModulePlan, so the guard does not secretly resolve modules or inspect package metadata internally.

This separation is deliberate, but it may still be wrong. I would like feedback on whether config-only detection makes runtime selection easier to reason about, whether the failure modes are clear enough, and whether the split between config validation, driver detection, and module compatibility is too fine-grained.

This is driver-matrix selection only; it does not implement a worker pool, queue transport, or runtime adapter.

Example 4: artifacts must be rerun-no-diff

Another important part of the core is the artifact pipeline. Coretsia currently works with kernel-owned artifacts such as compiled config, compiled container, and module manifest artifacts. The pipeline includes deterministic payload normalization, stable PHP array dumping, artifact headers, fingerprints, and cache verification.

There is a specific test that compiles artifacts twice from the same inputs and verifies that the generated bytes are identical. There is also a boundary check that only kernel-owned artifacts are written by that pipeline, such as:

config.php
container.php
module-manifest.php

The “rerun-no-diff” rule is one of the central engineering ideas behind Coretsia. Generated files should not create meaningless Git noise. If an artifact changes, it should be because the inputs or schema changed, not because of filesystem traversal order, incidental process state, unstable map ordering, or other nondeterministic behavior.

I would especially value review of this area. Is the artifact model understandable? Is fingerprint and cache verification behavior documented clearly enough? Are the current artifact boundaries strict enough without being overdesigned?

SSoT documents and the connection between code and documentation

Coretsia uses SSoT documents — Single Source of Truth documents — for important architectural invariants. The project currently has source-of-truth documents for areas such as config roots, config and environment behavior, config merge order, config directives, modules and manifests, runtime drivers, artifacts and fingerprints, compiled containers, UnitOfWork shapes, UnitOfWork outcome policy, context lifecycle, tags, reset behavior, observability, error descriptors, and contract boundaries.

This does not mean every small decision should become a formal document. The intention is narrower: if a rule affects package structure, runtime behavior, artifact shape, configuration ownership, lifecycle boundaries, or public contracts, it should have a canonical place. Code should then either enforce that rule or be clearly traceable to it.

For example, configuration defaults and rules are package-owned. core/foundation owns the foundation config root and provides config/foundation.php and config/rules.php. core/kernel owns the kernel config root and its strict config shape. This is not just a comment: package config files return only their subtree, framework-owned roots are validated only through their loaded declarative rulesets, and unknown keys are rejected inside those strict ruleset-owned maps.

At the same time, the global config is not a closed world. Application or skeleton config may define user-owned/custom top-level roots that do not have framework rulesets. Those roots are accepted, merged, explainable, and fingerprintable, but they are reported as user_owned and unvalidated rather than being silently treated as framework-validated config. Reserved internal namespaces such as forbidden top-level roots and unsupported @* directive keys are still guarded by kernel config policy.

That is why I am not asking for a code-only review. If the code is correct but the documentation does not explain the invariant, the project still has a problem. If the documentation says one thing and tests enforce another, that is a more serious problem. The intended review surface is code, documentation, tests, and roadmap alignment together.

What is out of scope for this review

I am not asking for a review of the whole future framework. HTTP runtime, routing implementation, validation implementation, filesystem integration, database integration, migrations, mail, secrets, queues, scheduler, CQRS, security, cache, and higher-level application modes are important areas, but they are not the subject of this article.

I am also not asking for production adoption, implementation help, or broad feature requests such as “add support for X.” Feature suggestions are useful only when they expose a deeper core design problem. For example, “add database support” is not useful feedback here, but “your core contracts already contain assumptions that will make database integration awkward later” would be useful.

The review target is the core foundation: contracts, deterministic runtime primitives, config ownership, module planning, artifacts, lifecycle boundaries, and documentation-to-code consistency.

The specific questions I want answered

The most useful feedback would be direct and specific. I would rather receive one concrete issue than ten general compliments. A confusing term, a weak boundary, a mismatched SSoT rule, an overcomplicated abstraction, or a setup problem is valuable feedback at this stage.

The questions I care about most are:

  1. Are the core package boundaries clear?

  2. Does core-contracts stay small and implementation-neutral enough?

  3. Does core-foundation contain the right low-level primitives, or is it mixing too many concerns?

  4. Does core-kernel own the right lifecycle responsibilities?

  5. Are config roots, config rules, and config merge behavior understandable from the docs and code together?

  6. Is the module metadata model explicit in a useful way, or is it too verbose?

  7. Are deterministic artifacts and fingerprints documented well enough for a new reviewer to evaluate them?

  8. Does the UnitOfWork lifecycle look format-neutral enough for HTTP, CLI, queues, and scheduler adapters?

  9. Are stable diagnostics and redaction rules too strict, too weak, or placed at the wrong layer?

  10. Does the roadmap clearly separate implemented core behavior from planned platform features?

  11. More broadly, does the Single Source of Truth approach make the framework more maintainable, or does it create too much ceremony before the runtime surface is large enough?

How to evaluate the repository locally

The intended local evaluation path is simple: clone the repository, install dependencies, and run the baseline checks from the repository root.

git clone https://github.com/coretsia/monorepo.git
cd monorepo
composer setup
composer ci

The current workflow also includes architecture and tooling checks: package index generation and verification, Deptrac config generation and verification, package compliance gates, DTO gates, artifact header schema gates, runtime/tooling artifact separation checks, and deterministic tests. This does not mean every part of the project is finished. It means the repository is already trying to make architectural drift visible.

If the setup flow is unclear, that is useful feedback. If the checks are hard to understand, that is useful feedback too. If an error message does not help a reviewer understand what broke, that is also a core quality problem.

This request is intentionally narrow. I am looking for review of the core before it becomes stable. I am not asking people to use Coretsia in production, and I am not presenting the wider framework roadmap as completed.

If you have experience maintaining long-lived PHP systems, framework integrations, internal platforms, package-heavy monorepos, deterministic tooling, or runtime lifecycle code, your criticism would be especially useful. The best feedback would identify where the current core is unclear, overdesigned, under-specified, or inconsistent with its own documentation.

Core Review: Deterministic PHP Framework Foundation