STATUS: DRAFT — PROPOSAL ONLY Per AGENTS.md: "No ADR = no standard." Normative authority exists only for sections with explicit ADR citations below. Uncited sections are implementation proposals pending ADR ratification; they MUST NOT be treated as binding requirements.
Cited Section Authority ✅ ADR-017 §7 Package Manager (pnpm) Normative ✅ ADR-042 §8 Exception Process Normative ⏳ pending §3 Three-Axis Versioning Proposal ⏳ pending §4 Self-Test Fixtures Proposal ⏳ pending §5 Governed-Action Gate Proposal ⏳ pending §9 Profiles Proposal ⏳ pending §10 Bucket Classification Proposal
Standard ID: STD-TOOLCHAIN-001 Version: 1.3 Status: Draft Last Updated: 2026-06-21 Owners: Platform Engineering
This standard defines the mandatory toolchain, dependency contracts, and CI enforcement gates for all repositories on this platform. It governs which linters, static analyzers, test frameworks, and package managers are authoritative per repository profile. Consuming repos adopt this standard by referencing the reusable workflows from this standards repository.
Applies to all repositories under the Starisian Technologies GitHub organization that ship production code, including:
- WordPress plugins and modules (
wp-plugin,wp-module) - Standalone React applications (
standalone-react) - Standalone Node.js / server-side TypeScript services (
standalone-node) - Python microservices (
python-service)
Each consuming repo's standards.yml caller has three independent version axes:
| Axis | Where Set | What It Controls |
|---|---|---|
Workflow ref (@v1) |
uses: line |
The executable — bugfixes only |
profile_version (e.g. v1) |
with: input |
Dependency/config contract |
enforcement_mode |
with: input |
gate (fail-closed) or advisory |
Pin strategy:
| Pin | When to use |
|---|---|
@v1 |
Recommended — tracks latest compatible v1 workflow; receives bugfixes automatically |
@v1.2.0 |
Maximum reproducibility — exact immutable release; requires manual updates |
@main |
Never — breaking changes land here first; not for consumers |
Never pin to @main in production. Move axes independently.
Enforcement governance: Workflows default to advisory (warn-only) when no enforcement_mode is passed. Consumers must explicitly set enforcement_mode: gate to get fail-closed behavior. Only ADR-backed rules (§7, §8) can be mandated org-wide as required; proposal-only sections (§3–§6, §9–§10) must run advisory-only until their backing ADRs are ratified.
Each workflow must have corresponding fixture directories under fixtures/ in this standards repo:
fixtures/{workflow-name}/pass/— files that must pass all checksfixtures/{workflow-name}/fail/— files that must trigger at least one check
Presence-validation steps and Bucket-3 grep guards start WARN-ONLY until self-test fixtures are authored and the CI self-test suite is wired (tracked in the platform backlog). Each warn-only step carries a comment: # WARN-ONLY — flips to required after self-test fixtures authored (STD-TOOLCHAIN-001 §4).
Mutation entry points must call assert_governed_action() before mutating state.
Auto-detected entry points (no annotation required): top-level functions whose names match wp_ajax_*, wp_ajax_nopriv_*, admin_post_*, or admin_post_nopriv_*.
Annotation-gated entry points: REST route callbacks, WP-CLI mutation commands, and any other entry point may be brought under the gate by adding @governed-mutation to the function or method docblock. Without this annotation those entry points are out of scope for the current rule.
Enforced by: GovernedActionGateRule PHPStan rule (see standards/phpstan-rules/). Status: warn-only until backing ADR is ratified.
A self-test CI job runs against the fixtures in this repo to validate that pass fixtures pass and fail fixtures fail. This suite must be green before any presence-validation or Bucket-3 check flips from warn-only to required.
All JS/TS repositories use pnpm exclusively (ADR-017). pnpm-enforcement.yml validates lockfile presence and blocks npm/yarn usage.
Advisory exceptions to required rules must be declared in .standards/standards-exceptions.yml in the consuming repo. Each exception entry requires:
exceptions:
- id: EXC-001
rule: JS-TEST-001
reason: "Migrating from Jest to Vitest — 30-day window"
owner: "@team-handle"
expires: "2026-07-21"
approval: "ADR-042"Required fields: id, rule, reason, owner, expires, approval.
Expired exceptions are fail-closed — CI blocks immediately. Malformed entries also block. The exceptions parser runs in every workflow before presence validation.
PHP toolchain:
squizlabs/php_codesniffer^3.9wp-coding-standards/wpcs^3automattic/vipwpcs^3phpcompatibility/phpcompatibility-wp^2.1phpstan/phpstan^2szepeviktor/phpstan-wordpress^2php-stubs/wordpress-stubs^6brain/monkey^2dealerdirect/phpcodesniffer-composer-installer(allow-plugins)
Required rulesets: WordPressVIPMinimum, WordPress-Extra, WordPress-Docs, PHPCompatibilityWP
Required files: composer.json, composer.lock, phpcs.xml, phpstan.neon
Recommended files: phpunit.xml
JS toolchain (via @wordpress/scripts):
@wordpress/scripts^30.0.0@wordpress/stylelint-config^11.0.0- Do NOT hand-pin
eslintorstylelint—@wordpress/scriptsowns those versions. - Prohibited:
typescript-eslint, hand-pinnedeslint, hand-pinnedstylelint
E2E: @playwright/test, @wordpress/e2e-test-utils-playwright, @axe-core/playwright
See machine-readable contract: standards/profiles/wp/v1/manifest.json
eslint^9 with flat config (eslint.config.mjs)typescript^5,typescript-eslint^8eslint-plugin-react^7,eslint-plugin-react-hooks^5,eslint-plugin-jsx-a11y^6vitest^2 (exception required to use Jest)@testing-library/react^16,@testing-library/jest-dom^6stylelint^16,stylelint-config-standard^36@playwright/test^1,@axe-core/playwright^4- Prohibited:
@wordpress/scripts, Jest (without exception)
Required files: package.json, pnpm-lock.yaml, eslint.config.mjs, tsconfig.json (strict: true), .stylelintrc.json
See machine-readable contract: standards/profiles/standalone-react/v1/manifest.json
eslint^9,typescript^5,typescript-eslint^8eslint-plugin-n^17 (NOTeslint-plugin-node— unmaintained)vitest^2- Prohibited:
@wordpress/scripts,eslint-plugin-node
Required files: package.json, pnpm-lock.yaml, eslint.config.mjs, tsconfig.json (strict: true); package.json (type: "module" — enforced by NODE-ESM-001)
See machine-readable contract: standards/profiles/standalone-node/v1/manifest.json
ruff,mypy(strict: true),pytest,pytest-cov- All config in
pyproject.toml
See machine-readable contract: standards/profiles/python/v1/manifest.json
| Bucket | Description | Enforcement |
|---|---|---|
| 1 | Security-critical (SQL injection, secrets, arbitrary eval) | Required, fail-closed |
| 2 | Standard conformance (lint, type, test, build) | Required, fail-closed |
| 3 | Advisory quality (unbounded queries, CSS perf, media constraints) | Warn-only until §4 |
| Version | Date | Summary |
|---|---|---|
| 1.3 | 2026-06-21 | Three-axis versioning; profile manifests; exception parser; GovernedActionGateRule scaffold |
| 1.2 | 2026-03-15 | Added python-service profile; Bucket-3 classification |
| 1.1 | 2026-01-10 | Added standalone-node profile; pnpm enforcement |
| 1.0 | 2025-11-01 | Initial standard: wp-plugin, standalone-react |