Art. I
The policy
policy/policy.json holds every support date as an ISO day, plus the rules: an audit threshold of high, banned constraints dev-* and *, and a grace of 90 days. A schema guards it.
Wayne State App Stack2026 EditionAdopted 2026-10-28
§0.1 Short title
This code shall be known as CREED, which stands for
C&IT Rules for Every Enterprise Developer
and may be cited as the standard everything rests on.
The written development standards for Wayne State's app stack: a handbook of numbered practices, plus policy.json, one file of support dates for PHP, Laravel, Node, MySQL, Vue and Inertia. A small PHP reader answers the one question every other tool asks: what state is this version in, on this date?
Table of contents
Each practice has a reason, sources and a stamp that says how the stack holds it today. Clause numbers follow the chapters: §2.1 is practice 11 in BEST_PRACTICES.md. This page prints the clauses an inspector reaches for most; the book has all of them.
Art. I
policy/policy.json holds every support date as an ISO day, plus the rules: an audit threshold of high, banned constraints dev-* and *, and a grace of 90 days. A schema guards it.
Art. II
Waynestate\Creed\Policy, framework-free PHP. stateOf returns Active, Security, Eol or EolGraceExpired. No other code in the stack decides a version's state.
Art. III
The rules chapter by chapter in handbook/, each citing the decision behind it. Where nothing is decided, the chapter says "To be decided" and states no rule.
Form CR-1 · Field inspection
Pick a runtime, a version and a day. The inspector reads the same dates as Policy::stateOf, by the same rules: the end day is inclusive, then 90 days of grace, then nothing. He stamps what he finds.
Certificate of inspection
No. 0001
$policy->stateOf('php', '8.2', new DateTimeImmutable('2026-10-28'))State::SecuritySecurity fixes only, until 2026-12-31: 64 days left. Plan the move to PHP 8.4 now.
Applicable clause: §2.2 Treat security-only as a countdown, not a resting place
InspectorCREED reader, schema v1
Chapter 1
Creed Bratton keeps his own records and nobody can audit them. CREED does the opposite: every date is in one file, with a source, where anyone can check it.
Every tool reads policy.json through the CREED reader. No other code decides whether a version is active, security-only or EOL.
Held by Waynestate\Creed\Policy, the only implementation.
PROCTOR is meant to depend on it.
A bad date, a wrong type or an unknown key fails the build.
Held by PolicySchemaTest and composer validate-policy, both in
PREFLIGHT php-test.
A version with no security_until is an error, not a silent pass, unless its line is marked current. An unknown component, or a version older than or between the listed lines, is an error. A version newer than every listed line is Active: current versions are never refused.
Held by stateOf, which throws for each case, and isAheadOfPolicy; tests cover every one.
A version is still supported on its security_until day. It is EOL the next day. After eol_grace_days (90) it is past grace, and no override applies.
Held by PolicyStateTest, on the PHP 8.2 boundary days.
Vue 3 and Inertia publish no fixed end dates. Do not invent them. The policy marks Vue 3 and Inertia 2 "current": true: Active on every date, with no security_until. Vue 2 keeps its real end, 2023-12-31.
Held by the schema, which refuses a current line that carries security_until and a dated line without it; PolicySchemaTest covers both.
Chapter 2
EOL PHP is not supported by the stack, with no exceptions. The adopted editions are in Table 2-1.
Apps declare and run a PHP version that php.net lists as supported. On 2026-10-28 that means 8.2 (security only, to 2026-12-31), 8.3, 8.4 and 8.5.
Held by
PROCTOR php-floor, which fails when the lowest bound of require.php is EOL by policy.
A version in security-only support warns now and fails on the day after security_until. Plan the move before then.
Held by
PROCTOR php-floor (a WARN). The runtime ribbon waits for
HELMET.
The PHP floor for apps moves from ^8.2 to ^8.3 on 2027-01-01. CREED itself already requires ^8.3; Creed has always been one version ahead of everyone else, at least by his own account.
Held by oldestSupported computes it. No automation bumps a package's constraint.
| Runtime | Active until | Security until | Latest patch | State |
|---|---|---|---|---|
| PHP floor 8.2 | ||||
| 8.5 | 2027-12-31 | 2029-12-31 | 8.5.12 | Active |
| 8.4 | 2026-12-31 | 2028-12-31 | 8.4.27 | Active |
| 8.3 | 2025-12-31 | 2027-12-31 | 8.3.36 | Security |
| 8.2 | 2024-12-31 | 2026-12-31 | 8.2.35 | Security |
| 8.1 | n/a | 2025-12-31 | n/a | Grace expired |
| Laravel floor 12 | ||||
| 13 | 2027-09-17E-1 | 2028-03-17 | 13.39.0 | Active |
| 12 | 2026-08-13 | 2027-02-24 | 12.70.2 | Security |
| 11 | 2025-09-03 | 2026-03-12 | 11.57.1 | Grace expired |
| 10 | 2024-08-06 | 2025-02-04 | 10.50.4 | Grace expired |
| Node floor 22 | ||||
| 26 | 2027-10-20 | 2029-04-30 | 26.12.1 | Active |
| 24 | 2026-10-20 | 2028-04-30 | 24.22.1 | Security |
| 22 | 2025-10-21 | 2027-04-30 | 22.23.4 | Security |
| 20 | 2024-10-22 | 2026-04-30 | 20.20.2 | Grace expired |
| MySQL floor 8.4 | ||||
| 9.7 | 2031-04-30 | 2034-04-30 | n/a | Active |
| 8.4 | 2029-04-30 | 2032-04-30 | n/a | Active |
| 8.0 | 2025-04-30 | 2026-04-30 | n/a | Grace expired |
| 5.7 | 2020-10-31 | 2023-10-31 | n/a | Grace expired |
| 5.6 | 2018-02-28 | 2021-02-28 | n/a | Grace expired |
| Vue and Inertia | ||||
| Vue 2 | 2023-12-31 | 2023-12-31 | n/a | Grace expired |
| Vue 3 | Current line: no published end dates, none invented; see §1.9. | Active | ||
| Inertia 2 | Current line: no published end dates, none invented; see §1.9. | Active | ||
From policy/policy.json, schema version 1, patches checked 2026-10-28. For Node, "active" holds the maintenance start; for MySQL, the Premier end. That mapping is the policy's, not the vendors' wording.
Laravel gives bug fixes for 18 months and security fixes for two years. Laravel 11 and older are EOL. Laravel 12 gets security fixes until 2027-02-24; Laravel 13 until 2028-03-17.
Gap The reader can classify 10 to 13, but no PROCTOR v0.1 check reads composer.lock for the framework. The planned deploy gate will.
Build front ends on a Node line that has not reached end of life: 22, 24 and 26. Node 20 reached end of life on 2026-04-30.
Gap The dates are in policy.json; no check reads an app's Node version yet.
MySQL 8.4 LTS has Premier support to 2029-04-30 and Extended to 2032-04-30. MySQL 8.0 ended on 2026-04-30 and is past CREED's 90-day grace since 2026-07-29.
Gap Nothing checks it, and the platform's own MySQL timeline is still an open question.
Chapter 3
What goes into an app, and how it is allowed in.
composer.lock is in the repository for apps. Use composer install in CI and on deploy, not composer update.
Held by
PROCTOR lock-committed.
No dev-* branches and no * on runtime dependencies. Use caret constraints such as ^2.4.
Held by
PROCTOR unbounded-constraints, using banned_constraints from the policy.
Run composer audit --locked in CI and fail at or above the policy threshold, high.
Held by
PREFLIGHT composer-audit and
PROCTOR composer-audit.
Include shared CI components at a tag or a full commit SHA, never ~latest. CREED's own pipeline pins both of its components to a SHA.
Held by ci.md; components from
PREFLIGHT. No check scans other repos.
Chapter 4
Three practices, three gaps, all printed. The inspector would rather you knew.
Do not commit .env, keys, tokens or passwords. Commit .env.example with placeholders. Rotate a secret that was ever exposed.
Gap No handbook chapter covers secrets, and no check scans for them yet.
APP_DEBUG is false in production.
Gap The runtime and headers chapter says "To be decided";
HELMET's refusal rules are not built.
Chapter 5
Every code has variances. These are the rules for asking for one.
An override sits in the app's policy-overrides.json with a reason and an expiry. Every run prints every override. An expired override fails.
Held by
PROCTOR overrides.
ROLLCALL is meant to list them across apps.
Each rule moves report, then warn, then block. A deploy that does not make things worse always passes.
Held by the proposed deploy gate. The schema has no field for stage dates yet.
Chapter 6
How the code itself is kept: decisions cited, questions owned, checks that give the same answer twice.
Each handbook rule links to the ADR that decided it. Where nothing is decided, the chapter says "To be decided" and states no rule.
No gate depends on a language model's opinion. A model may explain a failure; it does not decide pass or fail.
Scripts ship as a .ps1 and .sh pair, or as one PHP command. Every repo carries .gitattributes with * text=auto eol=lf.
CI runs CREED's unit tests on 8.3, 8.4 and 8.5, from its own floor up.
Held by
PREFLIGHT php-test, a matrix in CREED's pipeline.
Chapter 7 · Added in the second pass
Nine practices, one held so far. Chapters 8 to 10 (platform and database, policy data, accessibility) are all "Not yet" and are in the book.
A supported branch is not a patched one. On 2026-10-21 PHP released 8.5.12, 8.4.27, 8.3.36 and 8.2.35 to fix two critical advisories. policy.json now carries a latest_patch for each branch.
Held by latestPatch() in the reader; maintainers refresh it with php bin/refresh-patches.php.
Inserted after printing
Open questions in the 2026 edition. Each is written down with the clause it touches, and stays open until a decision or a source closes it.
| No. | Clause | Erratum or amendment | Status |
|---|---|---|---|
| E-1 | Table 2-1 | Laravel 13 active_until is 2027-09-17, but Laravel's page gives only "Q3 2027". Find the source and record it, or remove the date (§1.3, §1.6). | Open |
| E-4 | §9.3 | Strict or tolerant schema: can an older tool still read a newer policy that only added a field? A test with an old schema and reader decides. | Open |
| E-5 | §9.1 | Node 27 and later have no Maintenance phase on the new yearly schedule, so how active_until is derived needs a new rule. | Open |
| E-6 | Ch. 10 | The accessibility chapter: aim at WCAG 2.2 AA, after confirming which legal dates apply. To be decided. | Open |
| E-7 | Handbook | Runtime and headers: no rules until a decision lands with HELMET. The auth chapter still has the gateway's key distribution, and the SAML library if a SAML driver is built, to decide. | Open |
The full backlog, 37 items, is at the end of BEST_PRACTICES.md.
Referenced tools
CREED writes the rules; the rest of WELD inspects, builds and runs to them. Every tool below reads policy.json through the reader, never through its own copy.
Appendix A
Read the policy from your tool, or run CREED's own checks in a clone.
Any OS with PHP 8.3 or newer and Composer. On Packagist, 0.1.0
$ composer require waynestate/creed
use Waynestate\Creed\Policy;
use Waynestate\Creed\State;
$policy = Policy::bundled();
// What state is PHP 8.2 in, on this date?
$state = $policy->stateOf('php', '8.2', new DateTimeImmutable('2026-10-27'));
// State::Security
// What is the oldest PHP an app may declare?
$floor = $policy->oldestSupported('php', new DateTimeImmutable('2026-10-27'));
// '8.2'
In a clone, with PHP and Composer installed, one command runs the whole gate (validate, PHPUnit, policy schema, Pint, PHPStan, audit). The same command runs on GitLab and GitHub.
$ composer ci
No PHP on the machine? Docker runs the suite and the schema check.
PowerShell, with Docker Desktop.
PS> docker run --rm -v "${PWD}:/app" -w /app composer:2 composer install --no-interaction
PS> docker run --rm -v "${PWD}:/app" -w /app php:8.4-cli vendor/bin/phpunit
PS> docker run --rm -v "${PWD}:/app" -w /app composer:2 composer validate-policy
Terminal, with Docker Desktop.
$ docker run --rm -v "${PWD}:/app" -w /app composer:2 composer install --no-interaction
$ docker run --rm -v "${PWD}:/app" -w /app php:8.4-cli vendor/bin/phpunit
$ docker run --rm -v "${PWD}:/app" -w /app composer:2 composer validate-policy
Any shell, with Docker Engine.
$ docker run --rm -v "${PWD}:/app" -w /app composer:2 composer install --no-interaction
$ docker run --rm -v "${PWD}:/app" -w /app php:8.4-cli vendor/bin/phpunit
$ docker run --rm -v "${PWD}:/app" -w /app composer:2 composer validate-policy
Maintainers refresh the patch numbers from the upstream feeds with php bin/refresh-patches.php --dry-run (drop --dry-run to write).