Appearance
Release harness
A harness tests released packages straight from the registry, with no checkout at all. The manifest names the packages; composer installs them into each cell with full dependency resolution, exactly as a customer would; the source gates run on what was installed. Nothing is downloaded anywhere else: every package reaches the tests only through a real composer require into a cell.
The manifest
Omit modules and the manifest is a harness. install must then be composer from packagist and name the packages.
json
{
"furnace": 1,
"name": "qoliber/advanced-faq",
"install": {
"method": "composer",
"source": "packagist",
"repositories": ["https://qoliber.repo.packagist.com/qoliber-shop"],
"packages": [
"qoliber/advanced-faq",
"qoliber/advanced-faq-ai",
"qoliber/advanced-faq-graphql",
"qoliber/advanced-faq-hyva",
"qoliber/advanced-faq-rule",
"qoliber/advanced-faq-search",
"qoliber/advanced-faq-webapi",
"qoliber/ai"
],
"version": "^1.0"
},
"layers": ["unit", "integration"],
"requires": { "capabilities": [] },
"matrix": {
"magento": ["2.4.6", "2.4.7", "2.4.8", "2.4.9"],
"mageos": ["1.3.1", "2.3.0", "3.4.0"],
"php": ["8.1", "8.2", "8.3", "8.4", "8.5"],
"themes": ["luma", "hyva"]
}
}name is the extension under test. install.repositories is a list of URLs (composer repositories) or {"type": "composer"|"vcs"|"git"|"github"|"gitlab"|"bitbucket", "url": ...} entries; they are added to the cell for the run and removed by the golden restore. version applies to every package; with a range such as ^1.0 each cell may legitimately hold a different release, and the report says which.
Publish the harness as a package of its own next to the extension it tests, with the manifest, and later the seed and specs, inside. Ours lives at ~/qoliber-extensions/furnace-advanced-faq as qoliber/furnace-advanced-faq (composer type furnace-manifest); it is not on the registry yet.
Running it
bash
# from the harness directory
cd ~/qoliber-extensions/furnace-advanced-faq
furnace run --gate=all --release=1.0.0 -c m248 # one cell, a pinned release
furnace run --gate=all -p 3 # the matrix, newest ^1.0 per cell
# from anywhere: composer fetches the harness itself first
furnace run --gate=all --package=qoliber/furnace-advanced-faq \
--repository=https://qoliber.repo.packagist.com/qoliber-shop
furnace run --gate=all --package=qoliber/furnace-advanced-faq:dev-main \
--repository=~/qoliber-extensions/furnace-advanced-faq # a local checkout--package is the one composer require that happens outside a cell: the harness itself, into a small work project under ~/.furnace/work/harness/, because its manifest decides which cells run. --repository says where to find it: a composer repository URL, or a local directory used as a path repository (repeatable). Composer's own credentials apply.
A harness always runs --gate=all; --install=copy, --source=path and --source=archive need module code and are refused.
What runs where
| Gate | Source |
|---|---|
composer require | the packages, from install.repositories and the repositories the cell already knows |
rector, syntax floor, static analysis, unit | on each cell after the install, against the module directories inside the cell's vendor, with the cell's PHP, PHPUnit, PHPStan and PHPCS and Magento's unit bootstrap; they land in that cell's row |
setup:upgrade, modules enabled, di:compile, cron | the installed packages that carry a registration.php |
integration | Test/Integration inside the installed packages |
seed, e2e | the harness directory, when it ships e2e.seed and dev/tests/specs |
Two cells, m248 and m249, ship no vendor/bin/phpstan or vendor/bin/phpcs, so static analysis is reported n/a there; the other seven cells have all three tools.
What this requires of the packages
The tests must ship in the dist. With no checkout there is no fallback: a package that export-ignores its Test/ directory contributes no unit or integration tests, and the gate records a skip, which blocks certification. The m2-faqs modules have no .gitattributes, so their 1.0.0 dists carry 145 unit tests and 82 integration tests. Most other Qoliber modules export-ignore /Test; for those, certify from the main repository with --release, where the checkout's tests run against the installed package. The decision is one per vendor: ship the tests, or always certify from a checkout.
A harness judges the release by its own tests. On 2026-10-26 the 1.0.0 release of m2-faqs failed its shipped FaqsTest on m248: the test constructs a block with six arguments and the block takes seven. The current checkout has the fixed test; the release does not. That is a release finding, and the correct verdict.
Verified
Both on m248, 2026-10-26:
- From the harness directory with
--release=1.0.0: eight packages installed from the private registry in 6 s, twosetup:upgradepasses, eight modules enabled,di:compile, cleanup left the cell clean. - With
--package=qoliber/furnace-advanced-faq:dev-main --repository=<local dir>: the harness fetched by composer into the work project, install, rector 2 s, syntax floor, static analysisn/a(no tools on m248), unit 145 tests with the 15 release errors above, cleanup clean,doctorfully green afterwards.
Two traps surfaced and were fixed on the way: Rector's global */vendor/* skip silently excluded modules that live in the cell's vendor, so skips are now per module path; and a cell's composer platform_check.php refuses furnace's own PHP (m248 requires 8.4), so the installed packages carry the cell's PHP binary into every tool that runs on them.