Use feature branches and PRs against master. The canonical source layout is:
| Path | Responsibility |
|---|---|
images/*/definition.json |
Authored intent, runtime/OS lines, revisions, capabilities, limitations and changes |
images/*/Dockerfile |
Build recipe |
images/shared/ |
Shared tools and workspace/user handling |
images/tools.json |
Resolved Composer/uv digests, PECL versions and verified Symfony CLI artifact |
release-records/<family>/<line>/<revision>.json |
Published, behavior-tested release facts; created by publication |
retired-records/*.json |
Explicit removal declarations bound to exact historical record bytes and original source commits |
artifacts/<kind>/<name>/definition.json |
Authored binary, environment, configuration, or context contract |
artifacts/<kind>/<name>/payload/ |
Explicit bundle inputs and upstream notices |
release-records/artifacts/<kind>/<name>/<revision>.json |
Verified downloadable artifact facts; created by publication |
profiles/ |
Explicit role choices and exact resource revisions |
schemas/ |
Definition/release/catalog structure; cross-field invariants live in the validator |
discovery/organization.json |
Authored applicability, layers and direct profile navigation; no artifact facts |
catalog.json, catalog-v2.json, discovery.json, README tables, docs/capabilities.md, docs/images/, docs/resources/index.md, docs/releases/ |
Generated outputs |
scripts/ |
Small build, inventory, release, generation and refresh helpers |
scripts/xorder/ |
Shared typed model, resolution, transport, application, and artifact release helpers |
tests/fixtures/, tests/requirements/ |
Locked real consumer fixtures and independent mock requirements |
The image paths remain stable. Architecture describes the extension boundaries for binaries, environments, configuration, context, and profiles. Add a new path with its first meaningful definition or implementation; do not create empty category directories or list an unverified resource as available. Keep one normalized resource model and generate any compatibility views from it. Existing image selection inputs and outputs are compatibility contracts while generic discovery is introduced.
Local metadata validation:
Run the fast static checks before pushing Python, shell, Dockerfile or GitHub automation changes. The same commands run locally and in CI; tool setup plus checks has an initial ninety-second target. Scanner failures block, and reviewed exceptions are bound to the exact source bytes.
python3 -m pip install -r requirements-ci.txt
python3 scripts/library.py generate
python3 scripts/library.py check
python3 -m unittest discover -s tests -vValidation plans the affected runtime checks before starting the full unit suite.
Unit, image, resource and application checks run in parallel after planning and
fast static checks succeed. The required checks aggregate still requires the
unit result; only verified reuse of the same tested head/base/tree permits it to
be skipped. This keeps long unit runs off the image-build critical path without
removing their merge gate. Metadata-only changes first check the current image
and component COPY sources; copied metadata remains a build input. Changes to
shared or unknown runtime helpers retain full runtime verification. The shared
Symfony/Mago fixture targets its Mago/Serena and Chrome consumers.
Interactive, user-directed development, including AI-assisted work, uses the
requesting person's established Git identity for both author and committer.
Preserve the user's identity and verify git var GIT_AUTHOR_IDENT and
git var GIT_COMMITTER_IDENT before committing. If the identity is unavailable,
ask the user rather than inventing one or substituting an automation identity.
Dependabot and the repository's xorder automation and image-library automation
identities are reserved for unattended repository jobs such as dependency
refreshes and release/catalog workflows. Using an agent to run Git commands in
an interactive session does not make that session an automation job.
Do not attribute a commit or pull request to Claude, Codex, Grok, Anthropic, OpenAI, or xAI: omit their author/committer identities, attribution trailers, generated-with signatures, and model session links. This is a metadata policy, not a ban on using or discussing development tools; ordinary technical references to those tools and providers remain allowed.
Validation checks the full history reachable from a proposed head plus the pull request title and body. A branch based on superseded history must be rebased; there is no grandfathered range for prohibited attribution.
The Attribution Policy workflow runs the default branch's trusted checker and
publishes an attribution-policy check on the proposed head. It queries each
proposed commit's author, committer, message, and parent metadata through
GitHub's authenticated Git commits API, stopping at the fully audited local
default-branch history. No proposed objects enter the local Git database, and
the workflow never downloads proposed trees or blobs or checks out or executes
proposed code.
Repository administrators must keep that context required by the master ruleset
after its first successful run, and explicitly allow this workflow's
pull_request_target event in the repository Actions execution policy.
The shared .claude/settings.json suppresses Claude Code's default commit and
pull-request footer for the normal project configuration. It is a convenience,
not an enforcement boundary: higher-precedence local, command-line, or managed
settings can override it. The history audit remains the repository policy gate.
For a downloadable resource, pin an exact upstream URL and SHA-256 or declare
every authored payload file. Set its prerequisites, owned destination paths,
limitations, usage page, and behavior verifier in the definition. Allocate a new
SemVer packaging revision for changed input bytes, executable modes, destination
paths, or verification behavior. Fingerprints normalize payload modes to 0644
or 0755; executable intent is part of the release input.
Run its actual packaging and readiness check before opening the PR:
PYTHONPATH=scripts python3 -m xorder.verify verify KIND/NAMEPublication checks the anonymous released bytes again before proposing a durable release record. Review and merge that record through normal metadata checks; only then does generation expose the resource as available. Definitions and profile pins alone cannot make a release selectable. Update a native environment's committed lock through its backend and verify that readiness leaves it unchanged. Keep profile updates explicit: adding a newer accepted resource does not upgrade an existing profile, resolution lock, or managed installation.
On a Docker-capable host, use scripts/build.py LINE_ID LOCAL_TAG and
scripts/verify-image.sh LINE_ID IMAGE. Derived build input must be the exact
matching parent artifact; PR tests reuse an available matching digest or use the
just-built local parent. Publication
uses its immutable registry digest. Image builds collect measured versions,
packages, runtime and extensions using scripts/inventory.py.
Before editing a released recipe/input, allocate the appropriate image revision
and write meaningful changes plus migration guidance in the line definition.
Do not hand-edit measured tool versions in generated docs. A global shared tool
refresh intentionally changes all consumers; image-specific changes stay scoped.
README/docs/record-only PRs do not rebuild images. The release jobs additionally
skip source-identical lines already in the accepted ledger.
Validation scopes container jobs to changed recipes and consuming fixtures; release orchestration and unit-test changes still run metadata tests. Unknown build/verification helpers conservatively select all images. Publication also checks the accepted ledger before allocating runners, retaining incomplete PHP parent/browser pairs and changed-input guards.
PR image selection keeps exact behavior targets within each shared parent build tree. Recipe, copied-input, tool-pin, and definition changes test their consumers and descendants. A change confined to one definition line tests only that line and its descendants; a change to the family's common definition tests every line. Fixture and runner changes test only the images that execute them. Ancestors provide exact build inputs without repeating their own behavior checks, and unaffected sibling branches are skipped. Matching available parent artifacts are pulled by digest; missing or changed parents are built before the selected child.
Independent fixture changes also select their own checks on an unchanged, accepted image:
| Changed input | Selected checks |
|---|---|
tests/fixtures/trust/ |
CA trust checks on each family that runs them |
tests/fixtures/native-check.c |
Native compilation on the PHP, Python and Rust families that run it |
| Image recipe, copied input, tool pin, definition or unknown runtime helper | Full readiness for every affected image and descendant |
The Python compatibility matrix also consumes the native fixture internally; changes to that fixture retain its full matrix readiness check.
Multiple fixture changes combine their checks. Full readiness takes precedence when another changed input requires it. A target without an exact matching accepted artifact builds and runs full readiness even when the requested checks were narrower. The public readiness command and publication retain full verification by default. Partial checks record their actual suites in PR metrics and do not establish full readiness or publication evidence.
Catalog and known schema-only changes run metadata validation. Shared image
orchestration changes, including validate.yml, and unknown runtime helpers
still exercise all images because their impact spans the validation path.
Catalog and policy validation run on every PR. Unit and syntax checks run for
every new source head. checks accepts intentionally skipped runtime jobs while
failing on failed or cancelled required jobs.
Inspect selection without building:
python3 scripts/library.py validation-matrix --base BASE_COMMIT
python3 scripts/library.py validation-matrix --allThe matrix records each parent tree, its verify_lines, and the requested
verify_suites for each target, also shown in the workflow summary. The existing
affected root-list interface remains available.
For a toolkit-only local check:
python3 scripts/build.py php-dev/8.5-trixie image-library-check:dev \
--children --reuse-accepted --verify-lines '["php-toolkit/8.5-trixie"]'Manual Validate runs and the weekly Tuesday 06:23 UTC schedule exercise every
image, resource, environment, and application surface. Unchanged available
images are still reused for runtime checks; these runs do not publish images.
After a successful validation of the same PR and unchanged tested base, image,
resource and application selection reuse that validated coverage. Each run
retains a validation-context artifact binding its run, source head, actual
checkout parents and tree. The checked-out merge supplies the tested base;
historical API PR metadata and the event's base SHA are not proof of that base.
Incremental updates
compare source heads when the successful ancestral head already contains the
base. A source head behind the base can reuse an identical successful head;
later source updates conservatively check the full PR delta. Failed runs,
changed bases, unrelated force-pushes, unavailable history and missing or expired
context evidence also fall back to the full PR delta. An unrecognized checkout
runs every runtime check. This preserves changes introduced by the tested merge.
Title/body edits queue behind active validation instead of cancelling it. Once the same source head, tested base and checkout tree have passed, the queued run retains catalog/policy checks and reuses the completed unit, syntax and runtime results. A changed target branch still cancels obsolete work and requires selection against the new base. A failed or cancelled run cannot supply reusable coverage.
New revisions use version-2 fingerprints of their Dockerfile, its local COPY
inputs, executable modes, .dockerignore, and consumed tool pins. PHP-only
shared files do not change Rust or Python fingerprints. Derived fingerprints
also bind the exact accepted parent digest. Historical release records retain
their original algorithm and evidence; migration belongs to fresh revisions.
Tool-file changes select only consumers of the keys that actually changed.
Validation pulls an unchanged available accepted digest and runs selected behavior
without building it. Missing or changed artifacts still build and verify normally. The optional
--cache-probe checks source-label layer reuse when explicitly requested.
Build caches use family-specific input fingerprints rather than commit SHAs.
Source labels are applied after install layers. Observed Debian package-index
checksums form APT_REFRESH, invalidating package-install layers only when
those actual upstream inputs change. PHP CI uses Docker's containerd image store so its exact local
parent remains visible while both parent and browser caches can be exported.
Build artifacts and job summaries retain image size and build/verification
times. A source-label-only rebuild checks that filesystem layers stay identical.
Fresh image revisions record https://github.com/xormania/xorder in their OCI
source labels; historical artifacts retain their original provenance. Changing a
label changes the input fingerprint even when filesystem layers are unchanged:
allocate new revisions for the affected lines and derived consumers and run
normal build/publication verification. Never rebuild an accepted exact revision
or rewrite historical release evidence to disguise a provenance change.
PR build metrics describe validation artifacts; they are not published release
facts. Measured release facts belong in verified release-records/, and their
documentation is generated from that ledger in the image/release pages and
release measurements. Publication records local image size,
measurement method/store, timestamps, evidence, and public-artifact verification
time. Fresh builds also record build time and external cache input; resumed
artifacts have no invented build time.
Size comparisons use the preceding available accepted revision. Publication reuses its recorded size when the method/store match, or anonymously pulls its digest and measures it in the current store. This supports older records without metrics without rewriting their durable release assets. A comparison appears only when that accepted baseline is present; missing measurements stay absent. Rebuild timings depend on cache state and runner/network conditions; compare equivalent inputs rather than treating one run as a guaranteed duration.
Refresh build inputs runs weekly and manually. It resolves upstream digests,
PECL versions and the Symfony/Infection artifact checksums, then stages fresh
patch revisions only for changed consumers and their descendants. It tracks
Debian main amd64 package-index checksums for Trixie, updates and security;
changed package feeds trigger the apt consumers. Release dates and signatures
alone do not allocate rebuilds. Identical resolved inputs create no refresh PR.
These checksums observe repository changes; Debian packages remain measured
from the resulting artifact rather than claimed to come from a frozen snapshot.
Review upstream compatibility/security changes and adjust
the revision when a patch refresh would break the contract. Never reuse an exact
release for a fresh build. Dependabot proposes Actions/validation dependency
updates separately.
Fixtures have committed Composer, uv and Cargo locks. Updating a fixture lock is a source change and reruns behavior, rather than substituting the fixture's dependency versions for the consuming project's own lock. No global PHPUnit, Panther, CUE or speculative Cargo tools are bundled.
Browser parity also pins the accepted application-image digest alongside its consumer commit. Publication stages a candidate without executing consumer code. A separate job with no repository permissions, persisted checkout credentials, or registry login verifies that public digest. Its Compose configuration belongs to xorder, ignores consumer Compose/dotenv files, and rejects bind paths escaping the disposable checkout. The runner receives an explicit minimal environment. Finalization requires successful evidence bound to the exact digest, source, image inputs and parity fixture; it does not rerun consumer code with publication credentials.
To add a family/line, inspect the target project's requirements, choose an official upstream base and resolve its digest, define its intended profile, extend the build/inventory/behavior recipes, add independent selection scenarios, and keep it unavailable until the shared publication path produces a verified record. Extend platform schema/build/tests together before adding arm64. Keep discovery usable from the repository URL without a pipeline service, MCP server, or installed discovery skill. A selected context resource may contain a skill; that payload is independent of the discovery entry point. Reuse common release evidence and orchestration, with kind-specific build/verification and application behavior. Configuration/context changes must not rebuild unrelated images.
Pins make build inputs traceable; apt repositories and project download services still change. Byte-for-byte reproducible rebuilds are not claimed.