From c9fa4e9c776d67a41f1cfade2f3aada78d450f4d Mon Sep 17 00:00:00 2001 From: Joey Smith Date: Sat, 10 Oct 2026 10:00:04 -0500 Subject: [PATCH 1/3] docs(spec): ratify the Webware Theme constitution v1.0.0 Replaces the unfilled init template in .specify/memory/constitution.md. The repository has been running without a ratified constitution, so plan.md for 001-theme-resolution records that there are no project principles to gate against and substitutes a hand-written gate list. Content is derived from what the repository already enforces and documents, not invented to fill the template: the fleet quality gates the console and migration constitutions share, the resolution semantics recorded in 001-theme-resolution/decisions.md, and the operational rules in .github/instructions/memory.instructions.md. Principles: Library-First; Resolution by lookup, encoding the resolver formula, the aggregate priority order 100/50/1 and the ConfigProvider merge ordering; Consumer-Agnostic; Webware Quality Gates; Naming and Compatibility; Asset serving contract, encoding /theme//{css,js,img,fonts} and the view_helper_config.asset.resource_map key; Cross-Platform Development Environment, including that agents work on the Windows host so tooling scripts must be host-native; and Reference Repositories Are Read-Only. The technology stack is deliberately absent. The agentic-sdd command reference places the stack in the plan, and composer.json, phpunit.xml.dist, mago.toml and webware-ci.json already hold those facts authoritatively. Constitution files are not manifest-managed, so specify integration upgrade does not touch this file. Signed-off-by: Joey Smith --- .specify/memory/constitution.md | 130 +++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 35 deletions(-) diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index a4670ff..650b61f 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,50 +1,110 @@ -# [PROJECT_NAME] Constitution - +# Webware Theme Constitution ## Core Principles -### [PRINCIPLE_1_NAME] - -[PRINCIPLE_1_DESCRIPTION] - +### I. Library-First -### [PRINCIPLE_2_NAME] - -[PRINCIPLE_2_DESCRIPTION] - +Every capability ships as a self-contained, independently testable library component. Components +MUST have a clear, singular purpose; organizational-only or kitchen-sink packages are prohibited. -### [PRINCIPLE_3_NAME] - -[PRINCIPLE_3_DESCRIPTION] - +### II. Resolution by Lookup -### [PRINCIPLE_4_NAME] - -[PRINCIPLE_4_DESCRIPTION] - +Theme resolution is a lookup, never a path stack. The resolver reads the theme maps and returns a +template name or `false`; it performs no filesystem call: -### [PRINCIPLE_5_NAME] - -[PRINCIPLE_5_DESCRIPTION] - +```text +maps[active][name] ?? maps['default'][name] ?? false +``` -## [SECTION_2_NAME] - +- `ThemeResolver` is `final` and implements `ResolverInterface`. +- `ThemeResolverFactory` reads `theme.themes` and `theme.active`. The resolver never reads + configuration directly. +- `AggregateResolverFactory` attaches the theme resolver at priority 100, + `TemplateMapResolver` at 50, and the namespaced path stack at 1. The order is the contract: the + theme wins over the module map, and both win over the path stack. +- `ConfigProvider` MUST be merged after `Mezzio\LaminasView\ConfigProvider`. Merging before it + reorders the aggregate resolver chain and silently defeats it. -[SECTION_2_CONTENT] - +### III. Consumer-Agnostic -## [SECTION_3_NAME] - +The package provides theming; it does not know the application. It MUST NOT hard-couple to a +specific application or component. Configuration is contributed through `ConfigProvider` and +merged by the host, which is how the skeleton binds components (see the ecosystem composition +doctrine). -[SECTION_3_CONTENT] - +### IV. Webware Quality Gates (NON-NEGOTIABLE) + +Every change MUST pass the shared webware gates: Mago format, lint, analyze, and guard with no +silent suppression; PHPUnit 13 strict mode (coverage metadata, mock/stub split, `failOnNotice` / +`failOnDeprecation` / `failOnWarning`); and Infection mutation coverage at or above the configured +thresholds (MSI 95/95 from `webware-ci.json`). Test doubles follow PHPUnit 13 rules - +`createStub()` for value doubles, `createMock()` only with `expects()`. + +Gates are checked by exit code, not by the last line of output. + +### V. Naming & Compatibility + +Namespace root is `Webware\Theme\`. Interface names end in `Interface`; trait names end in +`Trait`. A namespace segment never repeats its parent segment. Support only current supported PHP +versions (`~8.4.1 || ~8.5.0`). Named arguments are required in all code the package owns. + +### VI. Asset Serving Contract + +Assets are served from `/theme//{css,js,img,fonts}`. They MUST NOT be served from a bare +`//` path: `.htaccess` would let a directory shadow a route and the asset would become +unreachable. + +The asset helper reads `view_helper_config.asset.resource_map` - not `view_manager.asset`. The +config key is part of the contract; consumers override it by key. + +### VII. Cross-Platform Development Environment + +Local tooling runs inside the persistent container (`docker compose exec tooling ...`) or the +VS Code Dev Container; the host is not required to carry a native PHP toolchain. `compose.yml` is +the single source of truth and the Dev Container is a thin wrapper over it. These files are kept in +sync with the central `webware/webware-tools` preset. + +Agents working this repository run on the Windows host and drive the repository toolchain from +there; scripts invoked by tooling MUST be host-native. + +### VIII. Reference Repositories Are Read-Only + +`ims` (and any other repository named as reference-only) is READ-ONLY. It is a source of evidence +and original templates, never a place to write. Nothing in it is edited, moved, renamed, or +committed to, for any reason. + +## Quality Gates + +Every pull request passes, on all CI matrix legs: + +- Mago format check, lint, analyze, guard +- Unit tests under lowest/locked/latest dependency strategies +- Integration tests where `run_integration` is set +- Codecov upload from the canonical coverage leg (report-only) +- Infection mutation score at or above the configured MSI thresholds + +## Development Workflow + +- Every change goes through a pull request. `1.0.x` is never pushed to directly. Releases and tags + belong to the owner. +- Each spec-driven step (constitution, specify, plan, tasks, implement, converge) lands as its own + branch and pull request. +- Commits use Conventional Commits and are signed off by the maintainer's real identity + (`git commit -s`, `Joey Smith `). Merge commits by default. +- No file is deleted, renamed, or moved without owner approval. +- Form field names are never changed. +- Application code is never run while a debug session may be attached + (`ss -ltnp | grep -E ':(9000|9003)'`). ## Governance - -[GOVERNANCE_RULES] - +- This constitution supersedes other practices; conflicts are resolved in its favor or the + constitution is amended via pull request. +- Amendments require a pull request that updates the version and Last Amended date. +- Every pull request is reviewed for compliance with the Core Principles. +- `.github/instructions/memory.instructions.md` carries the session handoff and operational rules + derived from this constitution. The full standing rules live in + `specs/001-theme-resolution/decisions.md` section 2 and + `vendor/webware/webware-tools/agent-working-agreements.md`. -**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE] - +**Version**: 1.0.0 | **Ratified**: 2026-10-10 | **Last Amended**: 2026-10-10 From bd49740c793ceea3579e988831557db435640d98 Mon Sep 17 00:00:00 2001 From: Joey Smith Date: Sat, 10 Oct 2026 21:15:02 -0500 Subject: [PATCH 2/3] docs: point the required-CI badge at the renamed workflow Signed-off-by: Joey Smith --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d4ad20..6eb5918 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ single array read, with no filesystem walk. [![PHP Version](https://img.shields.io/packagist/php-v/webware/webware-theme)](https://packagist.org/packages/webware/webware-theme) [![Latest Version](https://img.shields.io/packagist/v/webware/webware-theme)](https://packagist.org/packages/webware/webware-theme) [![License](https://img.shields.io/github/license/webinertia/webware-theme)](LICENSE) -[![Required CI](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/org-required-ci.yml/badge.svg)](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/org-required-ci.yml) +[![Required CI](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/continuous-integration.yml/badge.svg)](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/continuous-integration.yml) [![codecov](https://codecov.io/gh/webinertia/webware-theme/graph/badge.svg)](https://codecov.io/gh/webinertia/webware-theme) [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fwebinertia%2Fwebware-theme%2F1.0.x)](https://dashboard.stryker-mutator.io/reports/github.com/webinertia/webware-theme/1.0.x) From 27a925df409cb5e5104df994f724c5ca0ae85e65 Mon Sep 17 00:00:00 2001 From: Joey Smith Date: Sat, 10 Oct 2026 21:19:12 -0500 Subject: [PATCH 3/3] docs: name the required-CI badge alt text Continuous Integration Signed-off-by: Joey Smith --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6eb5918..df1c79e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ single array read, with no filesystem walk. [![PHP Version](https://img.shields.io/packagist/php-v/webware/webware-theme)](https://packagist.org/packages/webware/webware-theme) [![Latest Version](https://img.shields.io/packagist/v/webware/webware-theme)](https://packagist.org/packages/webware/webware-theme) [![License](https://img.shields.io/github/license/webinertia/webware-theme)](LICENSE) -[![Required CI](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/continuous-integration.yml/badge.svg)](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/continuous-integration.yml) +[![Continuous Integration](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/continuous-integration.yml/badge.svg)](https://github.com/webinertia/webware-theme/actions/workflows/required/webinertia/.github/.github/workflows/continuous-integration.yml) [![codecov](https://codecov.io/gh/webinertia/webware-theme/graph/badge.svg)](https://codecov.io/gh/webinertia/webware-theme) [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fwebinertia%2Fwebware-theme%2F1.0.x)](https://dashboard.stryker-mutator.io/reports/github.com/webinertia/webware-theme/1.0.x)