From eeea1088d49d8321665631087531e4a76a0bbfaf Mon Sep 17 00:00:00 2001 From: Mohamed Abdulalim Date: Thu, 17 Sep 2026 17:08:44 +0300 Subject: [PATCH 1/3] chore: adopt pinned standards and close compliance gaps --- .github/workflows/ci.yml | 32 +- AGENTS.md | 19 + CHANGELOG.md | 4 +- CONTRIBUTING.md | 23 +- PERSISTENCE_PACKAGE_REFERENCE.md | 14 + README.md | 23 +- composer.json | 3 +- .../STANDARDS_MANIFEST.md | 77 + .../GITHUB_PHASE_STACK_WORKFLOW_AR.md | 421 ++++++ .../STANDARDS_ADOPTION_STANDARD_AR.md | 528 +++++++ .../ai/AI_COLLABORATION_WORKFLOW_AR.md | 1245 +++++++++++++++++ .../packages}/CI_WORKFLOW_STANDARD.md | 79 +- .../packages}/COMPOSER_PACKAGE_STANDARD.md | 111 +- .../LIBRARY_PRESENTATION_STANDARD.md | 134 +- .../packages}/PACKAGE_BUILDING_STANDARD.md | 357 +++-- .../profiles/COMPOSER_PACKAGE_PROFILE.md | 38 + .../profiles/REPOSITORY_GOVERNANCE_PROFILE.md | 35 + .../standards/testing/TESTING_STANDARD.md | 135 ++ schema/README.md | 7 + tests/Consumer/run.php | 418 ++++++ .../MySql/create_global_ordering_table.sql | 10 +- .../MySql/create_pagination_items_table.sql | 20 +- .../MySql/create_scoped_ordering_table.sql | 14 +- ...eate_transaction_savepoint_items_table.sql | 6 +- 24 files changed, 3495 insertions(+), 258 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/php-engineering-standards/STANDARDS_MANIFEST.md create mode 100644 docs/php-engineering-standards/standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md create mode 100644 docs/php-engineering-standards/standards/STANDARDS_ADOPTION_STANDARD_AR.md create mode 100644 docs/php-engineering-standards/standards/ai/AI_COLLABORATION_WORKFLOW_AR.md rename docs/{standards => php-engineering-standards/standards/packages}/CI_WORKFLOW_STANDARD.md (60%) rename docs/{standards => php-engineering-standards/standards/packages}/COMPOSER_PACKAGE_STANDARD.md (79%) rename docs/{standards => php-engineering-standards/standards/packages}/LIBRARY_PRESENTATION_STANDARD.md (64%) rename docs/{standards => php-engineering-standards/standards/packages}/PACKAGE_BUILDING_STANDARD.md (54%) create mode 100644 docs/php-engineering-standards/standards/profiles/COMPOSER_PACKAGE_PROFILE.md create mode 100644 docs/php-engineering-standards/standards/profiles/REPOSITORY_GOVERNANCE_PROFILE.md create mode 100644 docs/php-engineering-standards/standards/testing/TESTING_STANDARD.md create mode 100644 schema/README.md create mode 100644 tests/Consumer/run.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b2b79b..be03374 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - codex/transaction-savepoint-orchestration-draft push: branches: - main @@ -69,6 +70,7 @@ jobs: --prefer-dist \ --no-progress composer check-platform-reqs + composer dump-autoload --optimize --strict-psr composer audit \ --no-interaction \ --abandoned=fail @@ -102,6 +104,7 @@ jobs: shell: bash run: | set -euo pipefail + git diff --check git diff --exit-code unit-regression: @@ -153,13 +156,14 @@ jobs: shell: bash run: | set -euo pipefail - vendor/bin/phpunit --testsuite unit - vendor/bin/phpunit --testsuite regression + composer test:unit + composer test:regression - name: Repository integrity shell: bash run: | set -euo pipefail + git diff --check git diff --exit-code lowest-dependencies: @@ -256,11 +260,10 @@ jobs: shell: bash run: | set -euo pipefail - vendor/bin/phpunit --testsuite unit - vendor/bin/phpunit --testsuite regression - vendor/bin/phpunit --testsuite integration - vendor/bin/phpunit --testsuite integration - vendor/bin/phpunit + composer test:unit + composer test:regression + composer test:integration + composer test:integration - name: Verify MySQL residue if: ${{ always() && !cancelled() && steps.setup-php.outcome == 'success' }} @@ -325,6 +328,7 @@ jobs: shell: bash run: | set -euo pipefail + git diff --check git diff --exit-code integration: @@ -414,13 +418,18 @@ jobs: exit 1 fi - - name: Run Integration and full suites + - name: Run Consumer Verification Harness shell: bash run: | set -euo pipefail - vendor/bin/phpunit --testsuite integration - vendor/bin/phpunit --testsuite integration - vendor/bin/phpunit + composer test:consumer + + - name: Run Integration and repeatability suites + shell: bash + run: | + set -euo pipefail + composer test:integration + composer test:integration - name: Verify MySQL residue if: ${{ always() && !cancelled() && steps.setup-php.outcome == 'success' }} @@ -485,6 +494,7 @@ jobs: shell: bash run: | set -euo pipefail + git diff --check git diff --exit-code ci-gate: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d1df92e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,19 @@ +# تعليمات مستودع maatify/persistence + +## التفعيل المعياري + +قبل التخطيط أو التنفيذ أو المراجعة، يجب قراءة [ملف معيار الاعتماد المثبت](docs/php-engineering-standards/standards/STANDARDS_ADOPTION_STANDARD_AR.md) كاملًا، ثم قراءة المعايير المنطبقة المسجلة في [STANDARDS_MANIFEST.md](docs/php-engineering-standards/STANDARDS_MANIFEST.md) بحسب نطاق المهمة. + +يسجل [STANDARDS_MANIFEST.md](docs/php-engineering-standards/STANDARDS_MANIFEST.md) مجموعة الاعتماد المحلية ونتيجة الحل، ولا يجوز استخدام مرجع upstream عائم أو نسخ معايير إضافية خارج المجموعة المسجلة. + +## قواعد خاصة بالمشروع + +- هذه الحزمة مكتبة Composer مستقلة، framework-agnostic وhost-agnostic، وتستخدم PDO المباشر مع MySQL/MariaDB-compatible SQL. +- يجب الحفاظ على عقد v1.4.0 العام، بما في ذلك ملكية المعاملات، ودعم المعاملة الخارجية، ودلالات savepoint المعتمدة؛ لا يُجرى تغيير breaking public API. +- اختبارات قاعدة البيانات تتطلب MySQL حقيقيًا؛ لا يجوز استخدام SQLite أو mocks لإثبات سلوك persistence الحقيقي. +- لا يُتتبّع composer.lock، ولا يُضاف حقل Composer باسم version، ولا تُنشأ Tag أو GitHub Release ضمن أعمال هذا المستودع ما لم يصدر تصريح صريح بذلك. +- يجب أن تبقى تغييرات Work Unit داخل نطاقها، وأن تمر عبر بوابات التحقق الفعلية الموثقة في [CONTRIBUTING.md](CONTRIBUTING.md) قبل النشر أو فتح Pull Request. + +## تعليمات إضافية + +لا توجد ملفات AGENTS.md إضافية خاصة بمسارات فرعية في هذا المستودع. diff --git a/CHANGELOG.md b/CHANGELOG.md index 9426b9f..3435245 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.4.0] - 2026-09-17 +## [1.4.0] - Stable Release Preparation (planned 2026-09-17) + +> **Release state:** Stable Release Preparation. The `v1.4.0` tag and release are not published; publication awaits owner approval. ### Added * Transaction savepoint orchestration capability (`SavepointTransactionRunnerInterface`, `PdoSavepointTransactionRunner`) for safe, operation-local rollback boundaries within caller-owned PDO transactions. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 085dbfa..33a3309 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,7 +30,7 @@ Contributions should respect the current directory structure: * `src/`: Contains the production source code. * `tests/`: Contains the test suites (`unit`, `regression`, and `integration`). -* `docs/`: Contains internal documentation and standards. +* `docs/`: Contains internal documentation, architecture decisions, and the pinned engineering standards. ## Local Verification @@ -39,12 +39,24 @@ Before submitting a Pull Request, please ensure all local verification steps pas ```bash composer install composer validate --strict +composer dump-autoload --optimize --strict-psr +composer check-platform-reqs +composer audit --no-interaction --abandoned=fail composer analyse composer test:unit composer test:regression +composer test:integration +composer test:consumer vendor/bin/php-cs-fixer fix --dry-run --diff +git diff --check ``` +The commands above are the local parity sequence for the CI quality and test +gates. `composer test:integration` and `composer test:consumer` require the +real MySQL service configured below. The consumer harness must be run from the +package root; it creates and removes its own clean consumer root and test +table twice. + ### Integration Testing Integration tests require a real MySQL database. SQLite is explicitly **not** supported as a substitute for these tests. @@ -69,6 +81,13 @@ Or to run the full test suite: composer test ``` +Workflow syntax is verified locally with actionlint `v1.7.12`, using the +checksum pinned in `.github/workflows/ci.yml`: + +```bash +actionlint -color +``` + ## Architectural Contribution Rules When contributing code, you must adhere to the following architectural rules: @@ -85,7 +104,7 @@ When contributing code, you must adhere to the following architectural rules: * **No Global Normalization**: Do not perform global normalization of gaps as a side effect of a scoped operation. * **Rollback Behavior**: Rollbacks must preserve the original error/exception. * **Exception Handling**: Do not catch every `\PDOException` or external `\Throwable` randomly to wrap it in a package exception. `PersistenceException` is strictly for package-defined exceptions. -* **Composer Lock**: This reusable library does not track `composer.lock`, in accordance with the [Composer Package Standard](docs/standards/COMPOSER_PACKAGE_STANDARD.md). Remove any locally generated `composer.lock` before submitting changes. +* **Composer Lock**: This reusable library does not track `composer.lock`, in accordance with the [Composer Package Standard](docs/php-engineering-standards/standards/packages/COMPOSER_PACKAGE_STANDARD.md). Remove any locally generated `composer.lock` before submitting changes. ## Pull Request Rules diff --git a/PERSISTENCE_PACKAGE_REFERENCE.md b/PERSISTENCE_PACKAGE_REFERENCE.md index 00a7903..746f118 100644 --- a/PERSISTENCE_PACKAGE_REFERENCE.md +++ b/PERSISTENCE_PACKAGE_REFERENCE.md @@ -13,6 +13,16 @@ * **Boundaries**: Framework-agnostic and host-agnostic. No HTTP API, no generic application repository, no ORM, no container bindings. * **Note**: PDO Pagination was introduced in v1.1.0. +## Persistence and Schema Ownership + +The package owns the reusable PDO ordering, transaction, savepoint, and +pagination behavior, but it does not own a persistent business entity or a +production table. Consumers provide their own trusted table and column +identifiers, SQL, scopes, and mapping. The package does not create migrations, +foreign keys, or joins to Host tables. MySQL/MariaDB-compatible SQL through +direct PDO is the supported persistence boundary; the package-level schema +notes are in [schema/README.md](schema/README.md). + ## Public API Inventory ### `Maatify\Persistence\Pdo\Ordering\ScopedOrderingConfig` @@ -402,6 +412,10 @@ Renaming the marker MAY be reconsidered only as part of a separately approved, m * `PERSISTENCE_TEST_MYSQL_PASSWORD` * **Test Database Isolation**: Assumes isolated test tables and requires local package privileges (trigger/table cleanup). Tests include trigger failure injection. * **Current CI MySQL Baseline**: 8.4.10. +* **Consumer Verification Harness**: `composer test:consumer` installs the + package into a separate non-symlinked Composer root and verifies a public + ordering, savepoint, and pagination workflow against real MySQL twice from + clean consumer/database state. ## Verification Model diff --git a/README.md b/README.md index 8a5642e..c7c11b1 100644 --- a/README.md +++ b/README.md @@ -309,9 +309,10 @@ Other important documentation: * [Contributing Guide](CONTRIBUTING.md) * [Code of Conduct](CODE_OF_CONDUCT.md) * [Architecture Decision Records](docs/adr/README.md) -* [Package Building Standard](docs/standards/PACKAGE_BUILDING_STANDARD.md) -* [CI Workflow Standard](docs/standards/CI_WORKFLOW_STANDARD.md) -* [Library Presentation Standard](docs/standards/LIBRARY_PRESENTATION_STANDARD.md) +* [Standards Manifest](docs/php-engineering-standards/STANDARDS_MANIFEST.md) +* [Package Building Standard](docs/php-engineering-standards/standards/packages/PACKAGE_BUILDING_STANDARD.md) +* [CI Workflow Standard](docs/php-engineering-standards/standards/packages/CI_WORKFLOW_STANDARD.md) +* [Library Presentation Standard](docs/php-engineering-standards/standards/packages/LIBRARY_PRESENTATION_STANDARD.md) ## ✅ Quality Status @@ -330,19 +331,33 @@ Other important documentation: ```bash composer validate --strict +composer dump-autoload --optimize --strict-psr +composer check-platform-reqs +composer audit --no-interaction --abandoned=fail composer analyse composer test:unit composer test:regression +composer test:integration +composer test:consumer vendor/bin/php-cs-fixer fix --dry-run --diff +git diff --check ``` -`composer test:integration` and `composer test` require a real MySQL database. SQLite is explicitly **not** an integration substitute. +`composer test:integration`, `composer test:consumer`, and `composer test` require a real MySQL database. SQLite is explicitly **not** an integration substitute. The Consumer Verification Harness creates a separate Composer root, installs this package as a non-symlinked dependency, and performs two clean runs. Set the following environment variables for Integration tests: * `PERSISTENCE_TEST_MYSQL_DSN` * `PERSISTENCE_TEST_MYSQL_USER` * `PERSISTENCE_TEST_MYSQL_PASSWORD` +For workflow syntax validation, install actionlint `v1.7.12` with the checksum pinned in `.github/workflows/ci.yml`, then run: + +```bash +actionlint -color +``` + +The CI `workflow-lint` job and this local command cover every workflow under `.github/workflows/`. + ## 📄 License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/composer.json b/composer.json index 52c00d2..93127db 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,8 @@ "test": "phpunit", "test:unit": "phpunit --testsuite unit", "test:regression": "phpunit --testsuite regression", - "test:integration": "phpunit --testsuite integration" + "test:integration": "phpunit --testsuite integration", + "test:consumer": "php tests/Consumer/run.php" }, "config": { "optimize-autoloader": true, diff --git a/docs/php-engineering-standards/STANDARDS_MANIFEST.md b/docs/php-engineering-standards/STANDARDS_MANIFEST.md new file mode 100644 index 0000000..5bbe7a3 --- /dev/null +++ b/docs/php-engineering-standards/STANDARDS_MANIFEST.md @@ -0,0 +1,77 @@ +# سجل اعتماد معايير Maatify + +## حالة الحل + +- Resolution Status: VALID +- Exception State: NONE +- Upstream Repository: Maatify/php-engineering-standards +- Adoption Commit: 44c8827095ab4007c355aa21c56b853f3b49d795 +- Adoption Date: 2026-09-17 +- Mixed-Commit Adoption: No +- Scope: / + +## Pinned Adoption Control Set + +الملفات التالية نسخ مثبتة من Adoption Commit المذكور أعلاه: + +- [standards/STANDARDS_ADOPTION_STANDARD_AR.md](standards/STANDARDS_ADOPTION_STANDARD_AR.md) — Standard ID std-standards-adoption, Version 2.0.0 +- [standards/profiles/COMPOSER_PACKAGE_PROFILE.md](standards/profiles/COMPOSER_PACKAGE_PROFILE.md) — Profile ID composer-package, Version 1.0.0 +- [standards/profiles/REPOSITORY_GOVERNANCE_PROFILE.md](standards/profiles/REPOSITORY_GOVERNANCE_PROFILE.md) — Profile ID repository-governance, Version 1.0.0 + +لا توجد Profiles غير مفعلة أو موروثة ضمن Control Set. + +## Active Profile Activations + +### composer-package + +- Profile Version: 1.0.0 +- Scope: / +- Artifact Facts: مكتبة PHP/Composer مستقلة قابلة لإعادة الاستخدام، وتملك سلوك SQL/PDO واختبارات MySQL حقيقية. +- Structural Resolution: VALID +- Exception State: NONE + +### repository-governance + +- Profile Version: 1.0.0 +- Scope: / +- Artifact Facts: مستودع يتبع دورة Work Unit وPhase Stack وPull Request في Maatify. +- Structural Resolution: VALID +- Exception State: NONE + +## Stage 1 — Candidate Standard References + +بعد حل المراجع المباشرة لكل Profile، تكون مجموعة المرشحين البنيوية التالية صحيحة ومثبتة من نفس Adoption Commit: + +- standards/packages/PACKAGE_BUILDING_STANDARD.md +- standards/packages/COMPOSER_PACKAGE_STANDARD.md +- standards/packages/CI_WORKFLOW_STANDARD.md +- standards/packages/LIBRARY_PRESENTATION_STANDARD.md +- standards/testing/TESTING_STANDARD.md +- standards/ai/AI_COLLABORATION_WORKFLOW_AR.md +- standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md + +لا توجد مراجع Extends أو Explicit Additional Standards إضافية. + +## Resolved Applicable Standards Set + +جميع المرشحين أعلاه منطبقة بصورة حاسمة على Scope / وحقائق الحزمة الفعلية، ولذلك تمثل هذه القائمة المجموعة النهائية فقط: + +- [standards/packages/PACKAGE_BUILDING_STANDARD.md](standards/packages/PACKAGE_BUILDING_STANDARD.md) — Standard ID std-package-building, Version 1.4.0 +- [standards/packages/COMPOSER_PACKAGE_STANDARD.md](standards/packages/COMPOSER_PACKAGE_STANDARD.md) — Standard ID std-composer-package, Version 2.0.0 +- [standards/packages/CI_WORKFLOW_STANDARD.md](standards/packages/CI_WORKFLOW_STANDARD.md) — Standard ID std-ci-workflow, Version 1.1.0 +- [standards/packages/LIBRARY_PRESENTATION_STANDARD.md](standards/packages/LIBRARY_PRESENTATION_STANDARD.md) — Standard ID std-library-presentation, Version 1.0.1 +- [standards/testing/TESTING_STANDARD.md](standards/testing/TESTING_STANDARD.md) — Standard ID std-testing, Version 1.1.0 +- [standards/ai/AI_COLLABORATION_WORKFLOW_AR.md](standards/ai/AI_COLLABORATION_WORKFLOW_AR.md) — Standard ID std-ai-collaboration-workflow, Version 6.0.0 +- [standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md](standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md) — Standard ID std-github-phase-stack-workflow, Version 2.2.0 + +## Additional Standards and Exceptions + +- Explicit Additional Standards: None +- Explicit Exceptions/Overrides: None + +## Resolver Evidence + +- تم تنفيذ Structural / Transitive Resolution من ملفات Profile المحلية المثبتة. +- تم تطبيق Canonical Standard Applicability على Scope / وحقائق أن الحزمة مستقلة وتملك سلوك PDO/SQL واختبارات MySQL ودورة Phase Stack. +- لم تُستخدم ملفات standards عائمة أو نسخة كاملة من مستودع المعايير. +- تم التحقق من كل ملف مثبت byte-for-byte مقابل Adoption Commit المسجل. diff --git a/docs/php-engineering-standards/standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md b/docs/php-engineering-standards/standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md new file mode 100644 index 0000000..d165ded --- /dev/null +++ b/docs/php-engineering-standards/standards/GITHUB_PHASE_STACK_WORKFLOW_AR.md @@ -0,0 +1,421 @@ +# معيار GitHub Phase Stack Workflow + +## بيانات المعيار + +- **Standard ID:** `std-github-phase-stack-workflow` +- **Standard Version:** `2.2.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` +- **اللغة المعتمدة:** العربية. +- **حالة الاعتماد:** يصبح معتمدًا عند دمجه في الفرع الافتراضي للمشروع. +- **الهدف:** تقليل زمن التسليم الكلي عبر Phase Draft أو Execution Batch وDependency-Aware Execution Train، مع الحفاظ على traceability والمراجعة والاختبارات وجودة `main` دون فرض Branch/PR أو تسلسل إداري لا تدعمه dependencies فعلية. + +--- + +# 1. قاعدة الـPhase الأساسية + +**كل Phase ذات عمل فعلي (Executed Phase) يجب أن تصل إلى حد تكامل ومراجعة مكتمل، بحيث لا يدخل إلى `main` إلا عمل مكتمل ومراجع ومثبت بالأدلة كوحدة هندسية مفهومة.** قد يكون حد التكامل هذا Phase Draft مستقلة، أو Work Branch واحدة تمثل Execution Batch تضم عدة Phases مترابطة، وفق قرار boundary المبني على dependencies والمخاطر وقابلية المراجعة. + +أما الـPhase التي يثبت Baseline Reconciliation أنها `No-op` بالكامل وفق §5، فلا تنشأ لها Phase Draft أو دورة فروع وPRs؛ تغلق تشغيليًا بأدلة ذلك الإثبات دون إسقاط Acceptance Criteria أو اختلاق تغيير. + +يستخدم هذا المعيار نموذج: + +```text +Dependency-Aware Phase Train +``` + +بدل فرض: + +```text +Strict Sequential Stack +``` + +ولا يعني السماح بالتوازي أو batching تخفيف أي Quality Gate أو قبول Phase ناقصة. + +## 1.1 فصل المفاهيم وقاعدة `Phase ≠ Branch ≠ PR` + +يجب عدم استخدام هذه المصطلحات كأنها طبقات متطابقة: + +- **Roadmap Phase:** حد تخطيطي وقبول منطقي يحدد ما الذي يجب إنجازه وإثباته. لا تعني تلقائيًا Branch أو PR مستقلة. +- **Execution Batch:** وحدة تسليم تشغيلية قد تضم Phase واحدة أو عدة Roadmap Phases مترابطة عندما تشترك في repository context أو architecture أو dependencies أو الملفات أو إعداد التحقق، أو عندما يكون استمرار نفس المنفذ على السياق الحالي أسرع من إعادة الفهم في جلسات متعددة. +- **Work Branch:** حد Git للعزل والتنفيذ والمراجعة والـrollback. قد تخدم Branch واحدة Execution Batch كاملة، وقد تكون Phase Draft نفسها عندما لا توجد حاجة لحد تجميع إضافي. +- **Commit:** وحدة traceability داخل Work Branch. يجوز إنشاء Commit واضحة لكل Phase أو logical milestone دون تحويل كل واحدة منها إلى Branch أو PR. +- **PR:** حد مراجعة وتكامل يختاره الفريق عندما يضيف reviewability أو dependency isolation أو rollback clarity أو safe integration. قد تغطي PR واحدة Execution Batch كاملة وعدة Phases. + +القاعدة الصريحة: + +```text +Phase ≠ Branch ≠ PR +``` + +لا تنشأ دورة GitHub مستقلة لمجرد أن Roadmap تحتوي Phase مرقمة. إذا كانت عدة Phases مترابطة وآمنة للتنفيذ المتتابع، يجوز تنفيذها في Execution Batch واحدة وWork Branch واحدة وPR واحدة، مع حفظ phase-level traceability عبر Commits واضحة وتوثيق الـmapping والـevidence. + +المبدأ التشغيلي: + +```text +Prefer context reuse over artificial parallelism. +``` + +إذا استطاع نفس المنفذ تنفيذ عدة Phases مترابطة بكفاءة باستخدام فهمه الحالي للمستودع والمعايير والـarchitecture، فلا تقسم المهمة على عدة agents أو sessions لمجرد تحقيق parallelism شكلي. + +## 1.2 الهيكل النموذجي + +يكون الهيكل المفاهيمي: + +```text +main +└── phase-draft أو batch-integration-branch + ├── execution batch 1 / work branch + │ ├── phase-a commits + │ └── phase-b commits + ├── execution wave 2 (إذا أثبتت استقلالًا حقيقيًا) + │ ├── work-branch-c + │ └── work-branch-d + └── phase closure + ├── required fixes (إذا لزم تغيير) + └── integration gates +``` + +الـPhase Draft في هذا الرسم حد تكامل ومراجعة، وليست وعدًا بBranch لكل Phase. يمكن أن تمثل Draft واحدة عدة Phases داخل Batch واحدة، ويمكن أن تكون Work Branch نفسها عندما لا توجد حاجة لBranch تجميع أخرى. الـWave تخطيط تشغيلي وليست ملفًا دائمًا إلزاميًا. ولا تصبح الـVerification أو Final Review أو Gate Component لمجرد وجودها في هذا الهيكل؛ لا تنشأ لها Branch أو PR إلا إذا نتج عنها تغيير مستودع مستقل ذي معنى. + +--- + +# 2. Phase Draft + +## 2.1 اختيار حد التكامل للـPhase أو الـExecution Batch + +1. تبدأ أول Phase أو Execution Batch من أحدث حالة فعلية ومعتمدة لـ`main`، أو من أحدث Work Branch/Phase Draft معتمد داخل نفس الـBatch. +2. قبل إنشاء Branch جديدة، يحدد المساعد القائد هل توجد حاجة فعلية إلى Work Branch مستقلة أو Phase Draft منفصلة. استمرار عدة Phases مترابطة على Work Branch واحدة هو الخيار المفضل عندما تكون dependencies والملفات والسياق مشتركة ولا يضيف الفصل عزلًا أو مراجعة أو rollback وضوحًا. +3. إذا احتاجت الـBatch إلى حد تجميع ومراجعة مستقل، تُعيّن Work Branch واحدة كـPhase Draft أو Batch Integration Branch. لا تنشأ Phase Draft إضافية إذا كانت Work Branch الحالية تؤدي هذا الدور بأمان. +4. يمكن أن تستهدف Work Branches المنفصلة Phase Draft عند وجود توازٍ حقيقي أو ownership مستقل. أما عند عدم الحاجة إلى تجميع منفصل، فتكون Work Branch/Batch PR الواحدة هي حد المراجعة النهائي قبل `main`. +5. لا يدخل `main` إلا حد التكامل المعيّن بعد اكتمال جميع Phases وWork Units وGates المطلوبة. وإذا كان هذا الحد هو Phase Draft، يظل **Phase Draft → `main` owner-only** وفق §8.2. + +إذا أثبت Baseline Reconciliation أن الـPhase `No-op` بالكامل، فلا تنفذ هذه الخطوات؛ يطبق مسار الإثبات والإغلاق التشغيلي في §5 بدل إنشاء Draft أو Branch أو PR. + +## 2.2 Work Units ذات التغيير + +1. كل Work Unit أو Component ينتج تغييرًا في المستودع يجب أن يملك حدًا واضحًا للملكية والقبول، لكنه لا يحتاج تلقائيًا إلى Branch أو PR مستقلة. يقرر ذلك على مستوى Execution Batch بناءً على dependency isolation وreviewability وrollback clarity وsafe integration وصافي زمن التسليم. +2. عندما تكون الوحدات مترابطة أو متتابعة أو تشترك في الملفات أو architecture أو verification setup، يجوز تنفيذها على Work Branch واحدة مع Commits واضحة لكل Phase أو logical milestone. +3. عندما تكون الوحدات مستقلة فعليًا ويكون التوازي أسرع بعد احتساب setup وإعادة الفهم والمراجعة وCI والتكامل والتعارضات، يجوز إنشاء Work Branchs وPRs منفصلة لها وتوجيهها إلى Phase Draft إن وجدت. +4. إذا كانت Phase Draft Branch منفصلة عن Work Branch، تظل نقطة تجميع محمية ولا تضاف إليها Commits عشوائية. وإذا كانت Work Branch الواحدة هي Batch/Phase Draft المعتمدة، يجوز أن تحتوي على Commits التنفيذ المحددة، مع بقاء review وGates وowner-only final merge كاملة. +5. لا يدخل إلى حد التكامل جزء سليم من Work Unit غير مكتملة. إذا تعثرت Work Unit، تطبق قواعد الاستعادة دون تقسيم acceptance الخاصة بها إلى Branch أو Component بديلة لمجرد مواصلة ceremony. +6. لا يحتاج تغيير صغير مثل ملف واحد أو جدول SQL واحد أو Test صغير أو جزء طبيعي من Phase أكبر إلى Branch أو PR مستقلة إذا أمكن ضمه بأمان داخل Batch مترابطة وقابلة للمراجعة. + +## 2.3 الدمج المنظم مع التوازي + +يجوز تنفيذ عدة Work Units بالتوازي، لكن التوازي خيار زمني لا هدف إداري. يستخدم فقط إذا كان صافي زمن التسليم أقل من التنفيذ المتتابع بعد احتساب: + +- إعادة قراءة وفهم الـrepository والسياق. +- قراءة المعايير والـarchitecture ذات الصلة. +- Branch setup وbaseline verification. +- review وCI لكل Branch/PR. +- integration وconflict cost وإعادة الاختبارات المتأثرة. + +إذا كان نفس المنفذ يستطيع إنهاء الوحدات المترابطة على Work Branch واحدة أسرع، لا تستخدم عدة agents أو sessions لمجرد زيادة عدد المسارات. + +عند اختيار التوازي، يظل دمج الوحدات إلى حد التكامل منظمًا: + +1. لا تدمج عدة Components إلى Draft بصورة عمياء. +2. يجب اعتماد كل Component واجتياز Component Gate قبل دمجها. +3. تتم عمليات الدمج إلى Draft واحدة تلو الأخرى حتى تظل حالة Draft معروفة بعد كل دمج. +4. قبل دمج Component مبنية على Draft أقدم، يتحقق المساعد القائد من توافقها مع أحدث Draft HEAD، ومن عدم تغير assumptions أو الملفات المشتركة. +5. إذا كانت المزامنة مطلوبة، يحدد التوجيه طريقة غير معيدة لكتابة التاريخ، مثل تنفيذ local `git merge` مصرح به لأحدث Draft في Branch الـComponent بCommit جديدة أو إنشاء Branch/PR بديلة من أحدث Draft عند الحاجة. يعاد تشغيل checks والمراجعة المتأثرة بعد المزامنة. +6. يمنع استخدام `git commit --amend` أو force-push لإخفاء تاريخ التصحيحات أو حل تعارض الـBaseline. + +عند اكتمال واعتماد Component مستقلة ذات PR، يتم **GitHub Squash Merge عبر Component PR إلى الـPhase Draft** وفق صلاحيات Git المعتمدة. أما الوحدات المتتابعة داخل Work Branch واحدة فتراجع وتدمج ضمن تلك الـBranch وفق الـGates نفسها، دون إنشاء Component PR لكل وحدة. لا يجوز دمج Component غير مكتملة أو تمرير تعارض لمجرد أن تنفيذها بدأ في Wave سابقة. + +--- + +# 3. Dependency-Aware Execution + +## 3.1 dependency graph وExecution Waves + +قبل التفويض، يعيد المساعد القائد بناء dependency graph ويثبت، لكل Work Unit أو Execution Batch: + +- dependencies التنفيذية. +- الملفات والـownership. +- Public Contract أو assumptions المشتركة. +- Acceptance Criteria المستقلة. +- Gate المطلوبة قبل الانتقال إلى Work Unit تعتمد عليها. + +تتكون الـPhase أو Execution Batch من Execution Waves. يمكن تنفيذ Work Units داخل نفس الـWave بالتوازي إذا أثبت المساعد القائد قبل التفويض: + +- عدم وجود dependency تنفيذية مباشرة تتطلب الترتيب. +- عدم وجود تعارض متوقع في Public Contract. +- عدم وجود overlap خطير في الملفات أو ownership. +- عدم اعتماد Work Unit على ناتج غير مدمج من أخرى. +- استقلال Acceptance Criteria وحدود الملفات والمسؤولية. + +إذا وجدت dependency أو overlap مؤثر، تنفذ الوحدات المعنية sequential على نفس Work Branch أو على Branchs متتابعة عند الحاجة. التوازي ليس إلزاميًا، لكنه ممنوع أن يكون محظورًا عالميًا، ولا ينتقل التنفيذ إلى Wave تالية إلا بعد اجتياز dependencies الفعلية وGates المطلوبة لها، وبعد إثبات أن كلفته الصافية أقل. + +--- + +# 4. تعريف Work Unit ومكوناتها + +## 4.1 Vertical Work Unit + +الأصل أن تكون Work Unit وحدة هندسية كاملة ذات معنى، وليست نوع Artifact منفصلًا. عندما يكون ذلك منطقيًا، تشمل Work Unit الخاصة بـFeature أو Gap واحدة: + +```text +Runtime ++ tests الخاصة بها ++ التوثيق المتأثر مباشرة ++ verification الخاص بالتغيير +``` + +يمنع افتراضيًا تقسيم Gap واحدة إلى Runtime PR وTests PR وDocumentation PR وVerification PR إذا كانت كلها تخص التغيير نفسه ويمكن مراجعتها كوحدة واحدة. تبقى هذه العناصر داخل Work Unit وExecution Batch وWork Branch واحدة متى كان ذلك آمنًا. + +يجوز الفصل عند وجود سبب هندسي حقيقي، مثل: + +- ownership مستقل. +- dependency مستقلة. +- cross-cutting verification. +- Documentation Sweep عامة للـPhase. +- تغيير واسع يحتاج isolation حقيقيًا. + +## 4.2 Verification كـGate + +Verification نشاط أو Gate، وليست Component افتراضية. + +إذا انتهت Verification بنتيجة `PASSED` ولم تنتج تغييرًا في المستودع: + +```text +لا Branch +لا Commit +لا PR +``` + +يسجل المساعد القائد evidence في التقرير أو المكان التشغيلي المناسب. وإذا كشفت Verification عن تغيير، ينفذ داخل Work Unit أو Work Branch المفتوحة إن كانت ما زالت قيد المراجعة، أو داخل Consolidated Required-Fix Component/Batch عند Phase Closure. + +لا تنشأ PR فقط لتسجيل أن الاختبارات نجحت. + +## 4.3 Final Review كـGate + +Final Review نشاط قبول ومراجعة، وليست Component افتراضية. + +إذا تضمنت المراجعة remediation غيّرت حالة سبق رفضها أو طلب تعديلها، فيجب قبل الدمج إلى **أي Integration Boundary** تنفيذ `Fresh Full Acceptance Review` للحالة النهائية المتراكمة. فحص إصلاح finding وحدها لا يكفي؛ مسؤولية المساعد القائد ومتطلبات هذه المراجعة يملكها [`AI_COLLABORATION_WORKFLOW_AR.md`](ai/AI_COLLABORATION_WORKFLOW_AR.md)، وهذا القسم يحدد موضعها كبوابة تكامل. + +إذا لم تنتج Final Review تغييرًا في المستودع، تسجل نتيجتها كـGate evidence فقط ولا تنشئ Branch أو PR مستقلة. وإذا كشفت عن تغييرات، تطبق قواعد Work Unit أو Consolidated Required Fixes داخل الـBatch، ولا تنشأ سلسلة PRs منفصلة لكل ملاحظة صغيرة. + +## 4.4 Consolidated Required Fixes + +تجمع findings المتوافقة الناتجة من نفس Review Pass داخل **Consolidated Required-Fix Component أو Batch واحدة** متى كان ذلك آمنًا ومتماسكًا، ويفضل إصلاحها على Work Branch/PR القائمة إن كانت الحدود ما زالت واضحة. + +لا تجمع مشاكل غير مترابطة إذا جعل ذلك PR غير قابلة للمراجعة، لكن يمنع إنشاء سلسلة: + +```text +fix-1 +fix-2 +fix-3 +docs-fix +status-fix +wording-fix +``` + +لمجرد أن findings اكتشفت منفردة. إذا كان finding يخص Work Unit مفتوحة، يعالج فيها بدل إنشاء Component إضافية. + +--- + +# 5. No-op وBaseline Reconciliation + +## 5.1 No-op Component وPhase Prohibition + +إذا كانت Acceptance Criteria لمكوّن أو Phase موجودة بالفعل ومثبتة في الـBaseline الحالي: + +```text +لا يعاد تنفيذها +لا ينشأ Branch فارغ +لا تنشأ PR Verification شكلية +``` + +تصنف الحالة بناءً على الأدلة الفعلية كـ`ALREADY IMPLEMENTED / VERIFIED` أو تصنيف أدق مناسب، ولا تنشأ Component لا تضيف تغييرًا أو دليلًا مطلوبًا. + +### Phase مثبتة بالكامل كـNo-op + +لا تصنف Phase بأنها `No-op` لمجرد وجود Implementation. يجب أن يثبت Baseline Reconciliation أن **جميع Acceptance Criteria الخاصة بالPhase نفسها** هي: + +```text +ALREADY IMPLEMENTED + PROVEN +``` + +على Baseline معتمدة، وألا يوجد في نطاقها: + +- repository change. +- missing proof. +- unresolved decision. +- required verification جديدة. +- documentation change. +- contract gap. + +عند تحقق هذه الشروط، تعتبر Phase `Execution No-op` مثبتة بالأدلة، ولا ينشأ لها: + +```text +Phase Draft +Branch +PR +empty commit +status-only documentation PR +owner merge ceremony +``` + +لا يجوز استخدام هذا المسار لإسقاط Acceptance Criteria أو تجاوز دليل مطلوب أو تغيير تاريخ المشروع. + +## 5.2 Baseline Reconciliation + +في المشاريع ذات Roadmap طويلة أو Legacy Implementation أو Extracted Module/Library أو Migration Baseline، تنفذ Baseline Reconciliation مرة واحدة على النطاق المتبقي عندما يكون ذلك أوفر من إعادة Discovery لكل Phase أو Execution Batch. + +التصنيفات الممكنة: + +```text +ALREADY IMPLEMENTED + PROVEN +IMPLEMENTED BUT MISSING PROOF +PARTIAL / GAP +NOT IMPLEMENTED +BLOCKED BY DECISION +``` + +هدفها عدم إعادة بناء الموجود، وكشف الـGaps مبكرًا، وإغلاق الـPhases المثبتة كـNo-op بالأدلة دون إنشاء دورة تنفيذ شكلية، وبناء dependency graph واقعية للعمل المتبقي. Baseline Reconciliation Activity تحليلية وليست PR أو طبقة Approval إلزامية بحد ذاتها. + +يجوز أن تنفذ Roadmap طويلة عمدًا في عدد قليل من Execution Batches، مع الاحتفاظ بحدود كل Phase وAcceptance Criteria وphase-level traceability عبر Commits واضحة وEvidence/Documentation مرتبطة بها. + +إذا أثبتت Reconciliation أن عدة Phases متتابعة كلها `No-op` بالكامل، يجوز إغلاقها تشغيليًا دفعة واحدة في Evidence/Reconciliation Record واحد، بشرط الاحتفاظ بإثبات Acceptance Criteria لكل Phase وعدم إسقاط أي منها أو تغيير تاريخ المشروع كذبًا. + +## 5.3 Phase / Roadmap Compaction + +داخل Roadmap معتمدة، يجوز للمساعد القائد **اقتراح** Execution Compaction عندما تكون عدة Phases متتابعة موجودة بالفعل جزئيًا أو كليًا، أو شديدة الترابط، أو لا تمثل Boundaries هندسية مستقلة أثناء التنفيذ. ويجوز عندها تنفيذها في Execution Batch واحدة وWork Branch واحدة وPR واحدة إذا كان ذلك يقلل زمن التسليم الكلي ويحافظ على وضوح المراجعة. إذا كان الدمج المقترح يغير Scope أو Phase Boundaries المعتمدة، فلا ينفذه المساعد القائد من نفسه؛ يعرض الأدلة والبدائل والأثر على المالك، ولا يصبح نافذًا إلا بعد اعتماد المالك. + +بعد الاعتماد، يمكن تنفيذ الـPhases ذات العمل الفعلي كـExecution Train أو Phase أوسع وفق هذا المعيار. أما الـPhases المثبتة كـNo-op فتظل مسار Evidence-only وفق §5 ولا تتحول إلى Draft أو PR شكلية. + +لا يجوز أن يؤدي ذلك إلى: + +- حذف Acceptance Criteria. +- إسقاط Quality Gates. +- الادعاء باكتمال شيء غير مثبت. +- تغيير Architecture أو Public Contract أو Scope مؤثر دون اعتماد مالك المشروع. + +يبقى الفصل المفاهيمي في الـRoadmap ممكنًا، بينما تصبح Execution Batches وWork Branches أقل وأكثر منطقية. لا يجوز أن تتحول أرقام الـPhases إلى سبب اصطناعي لفتح Branch أوPR أوSession جديدة. + +--- + +# 6. Tiered Verification وCI + +## 6.1 Work Unit وExecution Batch Gates + +تشغل كل Work Unit أو Execution Batch checks الكافية لاكتشاف Regression المرتبط بها، إضافة إلى Static/General Gates المطلوبة التي تكون تكلفتها معقولة لنطاقها وProfile المشروع. لا يفرض وجود Commit جديدة أو Phase جديدة تكرار Gate كاملة إذا لم يتغير risk أو dependency أو integration surface. + +لا تضطر Documentation-only Work Unit صغيرة إلى تكرار Expensive Integration Matrix بلا سبب، إلا إذا أثبت معيار آخر أن هذا Check إلزامي لهذا النوع من التغيير. لا يجوز في المقابل تخطي Check مرتبطة مباشرة بالسلوك أو العقد المتغير. + +## 6.2 Phase Integration Gate + +بعد اكتمال Work Batch مهمة أو Phase Draft أو حد التكامل النهائي، تشغل Full Required Verification لكل الـPhases وWork Units الداخلة في ذلك الحد بحسب Profile المشروع ومعايير CI وTesting، وتشمل عند انطباقها: + +- Full Test Suite. +- PHPStan أو Static Analysis. +- Latest وLowest Dependencies. +- Real Service/Database Integration. +- System/E2E Regression Protection. +- Composer/Package Checks. +- Workflow Checks. + +تظل CI بواباتها مستقرة وFail-Closed وفق `CI_WORKFLOW_STANDARD.md`، ويظل Testing Standard هو المرجع لتغطية السلوك وSystem/E2E. تركز Full CI عند نقاط integration ذات معنى مثل Work Batch مهمة أو Phase Draft أو Final Integration، ولا تكرر Full Gate بعد كل تعديل صغير إلا إذا بررته مخاطرة أو dependency أو تغيير في integration surface. لا تعتبر Phase أو Execution Batch جاهزة لـ`main` قبل نجاح Phase Integration Gate وجميع Gates الأخرى المطلوبة. + +## 6.3 Quality Invariant + +هذا التغيير لا يلغي: + +- Phase Draft. +- Review. +- Testing. +- Quality Gates. +- Regression Protection. +- شرط أن `main` لا يستقبل Phase ناقصة أو غير مثبتة. + +إنه يزيل Serial Bureaucracy فقط، ولا يزيل الأدلة أو المراجعة أو التحقق. + +--- + +# 7. Standards Freeze أثناء Active Execution Train + +عند بدء Phase أو Execution Batch/Train على Standards Snapshot مثبتة: + +- تظل Snapshot هي الـBaseline طوال الـTrain. +- لا يفرض تحديث Upstream Standards Refresh فوريًا أو تلقائيًا. +- لا يحدث Refresh أثناء Phase نشطة إلا إذا طلبه المالك صراحة، أو وجد Security/Correctness Blocker مؤثر، أو كان التغيير الجديد مطلوبًا لإكمال Phase بشكل صحيح. +- تنتظر التحديثات غير الضرورية Boundary مناسبة بين Phases أو Trains. + +--- + +# 8. اكتمال الـPhase والدمج إلى `main` + +## 8.1 شروط اكتمال الـExecuted Phase ذات العمل الفعلي + +لا تعتبر Phase مكتملة إلا بعد: + +1. اكتمال Acceptance Criteria لكل Phase داخلة في الـBatch، وكل Work Unit مطلوبة، أو إثبات No-op لها. +2. اجتياز Component Gates والتصحيحات اللازمة. +3. اكتمال Documentation المرتبطة مباشرة أو إثبات عدم الحاجة إليها. +4. اجتياز Phase Integration Gate وRegression Protection المطلوبة. +5. مراجعة حد التكامل المعيّن (Phase Draft إن وجد) وFinal Review كـGate، سواء أنتجت المراجعة تغييرًا أم سجلت evidence فقط. +6. عدم وجود Public Contract أو Architecture أو Scope غير معتمد. + +تنطبق هذه البوابات على كل Phase ذات عمل فعلي وعلى Execution Batch التي تجمعها. أما الـPhase المثبتة بالكامل كـ`Execution No-op`، فتغلق فقط وفق Evidence شروط §5، ولا تنشئ Draft أو Phase Integration Gate أو PR أو Merge. + +## 8.2 الدمج النهائي + +1. يمنع إدخال أي Work Unit أو Verification أو Documentation أو Fix غير مكتملة أو غير مراجعة مباشرة إلى `main`. +2. بعد اكتمال Phase Draft أو حد التكامل المعيّن للـExecution Batch وكل Gates، يكون حد التكامل نفسه جاهزًا للدمج. +3. يظل مالك المشروع صاحب القرار النهائي في **GitHub Squash Merge للـPhase Draft أو Batch Integration Boundary إلى `main`**. وإذا كانت الـBoundary هي Phase Draft، يبقى ذلك صراحةً **Phase Draft → `main` owner-only**. +4. إذا ضمت Work Branch/PR واحدة عدة Phases، يجوز أن تنتج Squash Commit واحدة إلى `main`، بشرط أن تكون Commits الـBranch وتوثيق الـPR قد حافظا على phase-level traceability لكل Phase وlogical milestone قبل الدمج. + +عندما لا توجد Phase Draft منفصلة، تطبق قاعدة owner-only نفسها على Work Branch/Batch Integration Boundary المعتمدة التي تمثلها؛ لا ينشئ ذلك دورة PR مستقلة لكل Phase. + +لا يوجد Phase-to-main Merge أو owner merge ceremony للـPhase المثبتة كـ`Execution No-op`، لأنها لا تنشئ Draft أو Commit أو PR أصلًا. + +## 8.3 Git History المستهدف + +يظل تاريخ `main` نظيفًا ومفاهيميًا، بينما تحفظ الـBranch والـPR والتوثيق traceability التفصيلية: + +```text +Execution Batch 1 — Phase A + Phase B — complete +Execution Batch 2 — Phase C — complete +``` + +ولا يتحول إلى سجل تفصيلي لكل Work Unit أو Gate داخل Phase. + +--- + +# 9. الصلاحيات والتوافق + +- يظل مالك المشروع صاحب القرار النهائي في الهدف، والأولوية، والـArchitecture الجوهرية، وقرارات Public Contract الجوهرية، وتوسيع Scope المؤثر، واعتماد Execution Compaction عندما يغير Phase Boundaries، ودمج Phase Draft إلى `main`، وTag، وRelease، وPublishing. +- بعد اعتماد Scope الـPhase أو Execution Batch من المالك، يملك المساعد القائد **Standing Execution Authority داخل الـPhase أو الـBatch**، عندما تكون الأدوات والصلاحيات متاحة، لإدارة دورة التنفيذ دون الرجوع للمالك عند كل Micro-step، بما يشمل تقسيم Work Units، وتحديد Dependency Waves، واختيار المنفذين، وتشغيل الوحدات المستقلة بالتوازي عندما يثبت أن صافي الزمن أقل، وإعادة استخدام السياق عندما يكون أسرع، وفتح وإدارة Branches/PRs اللازمة فقط، ومراجعتها، وطلب Fixes، وإعادة Verification، واعتماد Component، و**GitHub Squash Merge للـComponent PR إلى Phase Draft عند وجود Draft منفصلة**. +- لا تسمح Standing Execution Authority للمساعد القائد بتغيير Architecture أو Policy أو Public Contract جوهري، أو توسيع Scope مؤثر، أو الدمج إلى `main`، أو Tag/Release/Publish من نفسه. +- لا يحصل المنفذ تلقائيًا على Merge Authority لمجرد أن المساعد القائد يملك إدارة الـPhase. يظل Merge إلى `main` للمالك، ويظل تنفيذ المنفذ محصورًا في التكليف المحدد. +- تطبق صلاحيات Git التفصيلية وقواعد Amend وForce Push وStaging من `AI_COLLABORATION_WORKFLOW_AR.md` دون تعارض مع هذا المعيار. + +--- + +# 10. سجل تغييرات المعيار + +## `2.2.0` + +- ربط أي remediation تغيّر حالة سبق رفضها أو طلب تعديلها بـ`Fresh Full Acceptance Review` قبل الدمج إلى أي Integration Boundary، مع إحالة مسؤولية المراجعة إلى معيار AI Collaboration. + +## `2.1.0` + +- تثبيت الفصل المفاهيمي `Phase ≠ Branch ≠ PR` وإضافة `Execution Batch` كوحدة تسليم قد تضم عدة Roadmap Phases مترابطة. +- تفضيل إعادة استخدام السياق على التوازي الاصطناعي، وقصر parallel execution على الحالات المستقلة التي يكون فيها صافي زمن التسليم أقل بعد احتساب كلفة الفهم والإعداد والمراجعة وCI والتكامل. +- منع micro-branching وmicro-PRs غير الضرورية، وإبقاء Runtime والاختبارات والتوثيق والـverification المرتبطة مباشرة داخل Batch وWork Branch واحدة متى كان ذلك آمنًا. +- توضيح أن Phase Draft وحد تكامل اختياريان على مستوى الـBatch، مع إبقاء Phase Draft → `main` owner-only وGitHub Squash Merge وStanding Execution Authority وdependency-aware Waves وNo-op وQuality Gates دون تغيير. +- تركيز Full CI عند Work Batch مهمة أو Phase Draft أو Final Integration بدل تكراره بعد كل Commit أو تعديل صغير بلا سبب risk/dependency. + +## `2.0.0` + +- استبدال Strict Sequential Stack بنموذج Dependency-Aware Phase Train وExecution Waves. +- اعتماد Vertical Work Units، وتحويل Verification وFinal Review إلى Gates ما لم تنتجا تغييرًا مستقلًا. +- اعتماد Consolidated Required Fixes ومنع No-op Components وBaseline Reconciliation وPhase/Roadmap Compaction. +- اعتماد Component Gate وPhase Integration Gate مع الحفاظ على Full Required Verification قبل `main`. +- إضافة Standards Freeze أثناء Active Execution Train. +- تثبيت Standing Execution Authority للمساعد القائد داخل Phase بعد اعتماد Scope، مع إبقاء سلطة الدمج إلى `main` للمالك. + +## `1.0.0` + +- الإصدار الأول لنظام Phase Stack ودورة فروع الـPhase Draft والـComponents والدمج النهائي. diff --git a/docs/php-engineering-standards/standards/STANDARDS_ADOPTION_STANDARD_AR.md b/docs/php-engineering-standards/standards/STANDARDS_ADOPTION_STANDARD_AR.md new file mode 100644 index 0000000..39fd38d --- /dev/null +++ b/docs/php-engineering-standards/standards/STANDARDS_ADOPTION_STANDARD_AR.md @@ -0,0 +1,528 @@ +# معيار اعتماد وتوزيع معايير Maatify + +## بيانات المعيار + +- **Standard ID:** `std-standards-adoption` +- **Standard Version:** `2.0.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` +- **اللغة المعتمدة:** العربية. +- **حالة الاعتماد:** يصبح معتمدًا عند دمجه في الفرع الافتراضي للمشروع. +- **النطاق:** آلية اختيار المعايير وتثبيتها وتوزيعها وتفعيلها داخل المشاريع التابعة لمنظومة Maatify. +- **الهدف:** استبدال نسخ المستودع الكامل باعتماد انتقائي مثبت وقابل للتتبع، مع الحفاظ على المصدر المركزي وسلامة الروابط والترقية القابلة للمراجعة. + +هذا الملف هو **المصدر الوحيد للحقيقة لآلية Adoption**. لا يملك قواعد هندسية تخص PHP أو Composer أو Modules أو CI أو Testing؛ تلك القواعد تظل مملوكة للـ Standards المشار إليها في ملفات Profiles. + +## 1. المصدر المركزي وحدود الملكية + +المستودع: + +```text +Maatify/php-engineering-standards +``` + +هو المصدر المركزي الوحيد لتأليف المعايير وProfiles. المشروع التابع يحتفظ بنسخ محلية لأغراض الاعتماد والتثبيت، لكنه لا يجعل النسخة المحلية أو ملف الـ Manifest مصدرًا منافسًا للقواعد الأصلية. + +يجب أن يملك كل موضوع معياري ملفًا واحدًا. Profile هو **composition manifest** يحدد ما يجتمع وما ينطبق، ولا يعيد كتابة القواعد المملوكة للـ Standard. + +## 2. منع Full Repository Snapshot + +يجب ألا يعتمد أي مشروع على نسخ مجلد: + +```text +standards/ +``` + +بالكامل كإجراء افتراضي أو احتياطي. لا يجوز استخدام نمط `all standards just in case`، ولا يجعل وجود Standard في المستودع المركزي تلك الـ Standard منطبقة على كل مشروع. + +يجب أن يحتوي المشروع فقط على **Pinned Adoption Files**: الـ Pinned Adoption Control Set الإلزامية، والـ Pinned Applicable Standards Set الناتجة عن Profiles المفعلة وdependencies الخاصة بها، إضافة إلى Additional Standards المصرح بها صراحةً. لا تدخل ملفات أخرى لمجرد وجودها في المستودع المركزي. + +## 3. طبقات الاعتماد: Control Plane وApplicable Engineering Standards + +يستخدم كل consuming repository يعتمد هذا النظام طبقتين مختلفتين من الملفات المنسوخة من upstream، وسجلًا محليًا للنتيجة. لا تجعل هذه الطبقات Adoption Standard جزءًا من Required Standards الهندسية لأي Profile. + +### A. Pinned Adoption Control Set + +هذا الـ Control Set **إلزامي** لكل consuming repository يستخدم نظام Selective Adoption. يجب أن يحتوي، من upstream pinned commit، على: + +```text +standards/STANDARDS_ADOPTION_STANDARD_AR.md +active Profile manifests +all inherited Profile manifests required to resolve those active Profiles +``` + +يجب ألا يحتوي Control Set على Profile غير مستخدمة أو غير موروثة من Profile مفعلة. + +إذا كان الـ Active Profile هو: + +```text +project-aware-slim-module +``` + +فإن Profile manifests المحلية المطلوبة هي: + +```text +PROJECT_AWARE_SLIM_MODULE_PROFILE.md +SLIM_MODULE_PROFILE.md +BASE_MODULE_PROFILE.md +COMPOSER_PACKAGE_PROFILE.md +``` + +ولا يلزم نسخ: + +```text +REPOSITORY_GOVERNANCE_PROFILE.md +``` + +إلا إذا كان مفعّلًا أيضًا أو دخل في inheritance مطلوبة. + +وجود Adoption Standard وProfile manifests في Control Set لا يجعل Adoption Standard capability هندسية، ولا يضيفها إلى `Required Standards` لأي Profile. + +### B. Pinned Applicable Standards Set + +هو المجموعة النهائية من الـ canonical Engineering Standards التي تنطبق على Activation/Scope وفق applicability المملوكة لكل Standard. لا تساوي هذه المجموعة مجرد union للـ Required Standards المشار إليها في Profiles. ينتجها الحل على مرحلتين إلزاميتين موضحتين في §7: + +```text +Structural / Transitive Resolution +→ Candidate Standard References +→ Canonical Standard Applicability +→ Final Resolved Applicable Standards Set +``` + +تشمل مجموعة المرشحين المراجع المباشرة والموروثة من Profiles وأي `Explicit Additional Standards` صالحة بنيويًا. ولا تصبح أي Standard جزءًا من هذه المجموعة النهائية إلا بعد تقييم Activation Scope وحقائق الـartifact مقابل canonical Applicability وConditional Applicability المملوكة لتلك Standard. هذه المجموعة النهائية وحدها تحدد القواعد الهندسية المطلوب قراءتها وتطبيقها على Scope المهمة. + +### C. Local Resolver Record + +```text +STANDARDS_MANIFEST.md +``` + +هو ملف محلي يولده المشروع ويسجل نتيجة adoption والعلاقة بين Control Set وApplicable Standards Set. ليس ملفًا منسوخًا من upstream، وليس Standard أو Profile، ولا يدخل في Required Standards أو في Pinned Adoption Control Set. + +يسجل Manifest المجموعة النهائية فقط بوصفها `Resolved Applicable Standards Set`؛ ولا يسجل Candidate Standard غير منطبقة على أنها Applicable Standard. تظل Profile references اللازمة للحل البنيوي ظاهرة في ملفات Profiles المثبتة داخل Control Set، وتظل مدخلات ونتائج resolution قابلة للمراجعة وفق الحقول القائمة. + +وعليه: + +```text +Pinned Adoption Files += +Pinned Adoption Control Set ++ +Pinned Applicable Standards Set + +Local metadata += +STANDARDS_MANIFEST.md +``` + +## 4. Selective Pinned Adoption + +عند إنشاء أو تحديث Adoption Set: + +1. تكون Adoption Standard وProfile manifests والـ Applicable Engineering Standards نسخًا محلية ومثبتة على Adoption Commit محدد. +2. تأتي جميع الملفات المنسوخة من upstream افتراضيًا من **نفس exact upstream commit** حفاظًا على consistency بين Control Plane والروابط والقواعد. +3. يمنع الاعتماد على floating `main` أو أي مرجع متحرك بدل commit محدد. +4. يسجل المشروع في Manifest المستودع upstream والـ commit والـ Profiles والـ Scopes والـ Control Set والـ Applicable Standards وإصداراتها المرتبطة بها. +5. تتم الترقية عبر تغيير reviewed يعيد حل Profiles المستخدمة فقط. +6. لا تنسخ الترقية Standards غير المنطبقة على Scopes المشروع. + +لا يجوز جمع Standards من commits مختلفة إلا بقرار صريح موثق من مالك المشروع، ويجب تسجيل هذا الاستثناء في Manifest مع سببه ونطاقه. + +## 5. Profile Composition Manifests + +كل Profile مستقل ويبدأ افتراضيًا بالإصدار `1.0.0`. يجب أن يوضح ملف Profile، على الأقل: + +- `Profile ID` فريدًا. +- `Profile Version` منفصلًا عن إصدارات Standards. +- `Purpose / Applicability`. +- `Extends`، أو `None` إذا لم يرث Profile آخر. +- `Required Standards` المباشرة التي يضيفها Profile. +- `Conditional Applicability`، مع الإحالة إلى Standard المالكة للشرط. +- `Resolved dependency behavior`. +- `Scope notes`. +- `Precedence notes`. + +Profiles لا تنقل القواعد الهندسية إلى ملفاتها ولا تنشئ مصدرًا موازيًا للحقيقة. كل Profile يعلن الاعتمادات المباشرة فقط؛ أما الاعتمادات الموروثة فتدخل في الحل عبر Transitive Resolution. + +### 5.1 Profile Versioning + +يُفصل إصدار Profile عن إصدار كل Standard: + +- **Patch:** تغيير صياغة أو metadata لا يغير composition. +- **Minor:** إضافة قدرة اختيارية أو شرطية متوافقة لا تغير الالتزامات القائمة. +- **Major:** تغيير Required Standards أو inheritance أو composition بما يغير عقد الاعتماد. + +ملف Profile المفعّل، وكل ملف Profile موروث لازم لحل inheritance، جزء إلزامي من `Pinned Adoption Control Set` ويجب تثبيته محليًا. Profiles غير المفعلة وغير الموروثة لا تُنسخ. لا يعني ذلك إضافة Adoption Standard إلى `Required Standards`؛ فـ Required Standards تظل خاصة بالـ engineering applicability. + +يملك هذا القسم Profile Versioning حصريًا. أما `Standard ID` و`Standard Version` و`Standard Version Format` وانتقالات إصدارات Standards فتخضع للسياسة المركزية [STANDARD_VERSIONING_POLICY_AR.md](governance/STANDARD_VERSIONING_POLICY_AR.md). لا تدخل هذه السياسة في `Pinned Adoption Control Set` أو `Resolved Applicable Standards Set`، ولا يحتاج Consumer إلى نسخها لمجرد Adoption. + +## 6. Scope-Aware Profile Activation + +كل Profile Activation في المشروع يجب أن تحدد Scope صريحًا. يمكن أن يكون Scope: + +```text +/ +Modules/* +Modules/*Slim +Modules/SpecificFeature +``` + +أو قائمة paths محددة. Scope هو نطاق التطبيق، وليس نوعًا حصريًا للمستودع. + +يجوز للمشروع تفعيل عدة Profiles في Repository واحدة، كما يجوز أن تنطبق عدة Activations على الملف نفسه. لا يعني Scope الأكثر تحديدًا إلغاء Scope أوسع تلقائيًا؛ بل تُجمع Profiles المنطبقة، ما لم يوجد استثناء مشروع موثق بسلطة مناسبة. + +عند تنفيذ مهمة، يجب على الوكيل: + +1. تحديد الملفات والمسارات المتأثرة وحقائق الـartifact ذات الصلة، مثل كونه مكتبة مستقلة أو موديولًا قابلًا للاستخراج أو ميزة مرتبطة بـHost. +2. مطابقة المسارات مع Profile Activations وتحديد كل Activation/Scope على حدة. +3. تنفيذ Structural / Transitive Resolution لكل Activation: حل Profiles النشطة والموروثة، وجمع كل مراجع Required Standards المباشرة والموروثة وأي Explicit Additional Standards، والتحقق من سلامة graph والروابط والـmetadata قبل أي تصفية بسبب applicability. +4. بعد نجاح الحل البنيوي، تقييم كل Candidate Standard Reference مقابل Scope وحقائق الـartifact وcanonical Applicability أو Conditional Applicability التي تملكها تلك Standard. +5. أخذ Union للـStandards المنطبقة فقط لتكوين Final Resolved Applicable Standards Set عبر الـActivations المنطبقة. +6. قراءة وتطبيق Standards الموجودة في المجموعة النهائية فقط. +7. تطبيق التعليمات المحلية والاستثناءات الموثقة وفق precedence المشروع. + +إذا عبرت المهمة أكثر من Scope، ينفذ الحل البنيوي وتقييم applicability لكل Activation/Scope بصورة مستقلة، ثم يستخدم Union للـ Final Applicable Standards الناتجة. لا تحذف خصوصية Scope أوسع أو أضيق Profile موروثة من مجموعة المرشحين؛ تظل applicability لكل Standard هي الحاكمة للنتيجة النهائية. + +## 7. Transitive Profile Resolution + +يجب أن يكون inheritance صريحًا وقابلًا للحل دون دورات. إذا كان: + +```text +project-aware-slim-module + extends slim-module +slim-module + extends base-module +base-module + extends composer-package +``` + +تتكون عملية الحل من مرحلتين منفصلتين: + +### Stage 1 — Structural / Transitive Resolution + +ينتج الحل البنيوي مجموعة `Candidate Standard References` من Required Standards المباشرة لكل Profile في سلسلة inheritance، بترتيب dependency، ومن Explicit Additional Standards المصرح بها. هذه مجموعة مرشحين مرحلية وليست Final Resolved Applicable Standards Set، ولا تلزم المشروع بإدراج Required Standards الموروثة مكررًا. + +يجب التحقق من كل مرجع وكل metadata بنيوي مطلوب في هذه المرحلة، قبل تقييم applicability. يظل missing Standard أو Profile أو inherited Profile أو reference أو mandatory metadata، وكذلك inheritance cycle أو structural Manifest mismatch، `Structural Invalidity` حتى لو كانت applicability الخاصة بالـStandard ستستبعده لاحقًا من المجموعة النهائية. لا يجوز استخدام applicability لإخفاء graph أو reference مكسور. + +### Stage 2 — Canonical Standard Applicability + +بعد نجاح Stage 1، تقيم كل Candidate Standard مستقلةً مقابل Activation Scope وحقائق الـartifact الفعلية، وفق canonical Applicability وConditional Applicability المملوكة لتلك Standard. لا يملك Profile أو Manifest توسيع applicability الخاصة بالـStandard أو تضييقها. تدخل الـStandard في `Final Resolved Applicable Standards Set` فقط إذا انطبقت عليها قواعدها canonical. + +لا يجوز إسقاط Candidate Standard موروثة من المرحلة البنيوية لمجرد أن Profile أكثر تحديدًا مفعّل أو مفضل. ويجوز استبعادها من المجموعة النهائية فقط إذا كانت canonical applicability التي تملكها هي تستبعد Scope/الـartifact الفعلي بصورة deterministic. وبهذا لا تتجاوز عبارات Profile مثل “inherited Standards enter the Resolved Set” مرحلة المرشحين أو applicability المملوكة لكل Standard. + +يجب على الـ resolver المفاهيمي أو عملية المراجعة التحقق من: + +- وجود كل Profile مذكور في `Extends`. +- عدم وجود inheritance cycle. +- وجود كل Required Standard المشار إليها فعليًا، حتى إذا لم تدخل لاحقًا المجموعة النهائية. +- وجود كل Explicit Additional Standard reference معلنة وصحتها بنيويًا. +- بقاء كل Standard موروثة ضمن مجموعة المرشحين مهما كانت خصوصية Profile مفعّلة. +- تكوين المجموعة النهائية بتطبيق canonical applicability المملوكة لكل Standard على Scope وحقائق الـartifact. + +إذا استبعدت applicability المملوكة للـStandard مرشحًا بصورة deterministic، فهذا حكم applicability وليس Exception أو deviation: لا يحتاج إلى Exception، ولا يجعل النتيجة `INVALID` أو `OWNER DECISION REQUIRED` بذاته. أما إذا لم تسمح قواعد الـStandard وحقائق الـScope بحسم applicability، فتطبق Resolution Status القائمة في §16 دون افتراض الانطباق. ولا يغير Profile القاعدة التي تملكها Standard أخرى؛ وأي deviation أو override لا يسمح به عقد الـStandard لا يصبح تطبيقًا صحيحًا بمجرد طلبه أو تسجيله في Profile أو Manifest. تسجل الاستثناءات المعتمدة والموثقة فقط في Manifest بعد اكتمال Adoption؛ أما الطلبات والقرارات غير المحسومة فتبقى review evidence. وتخضع النتائج لقواعد §16. + +### مثال توضيحي عام: Project-Aware Slim + +عند تفعيل `project-aware-slim-module`، يظل Stage 1 مطالبًا بحل السلسلة كاملة `project-aware-slim-module → slim-module → base-module → composer-package` والتحقق من كل Profile وRequired Standard reference. بعد ذلك فقط يقيّم Stage 2 كل Standard على حدة. فإذا كان الـScope الفعلي ميزة Host-specific غير قابلة للاستخراج، فإن `COMPOSER_PACKAGE_STANDARD.md §3` لا ينطبق على هذا الـartifact لأنه يقصر نطاقه على مكتبات Composer مستقلة قابلة لإعادة الاستخدام؛ لذلك لا تدخل Composer Package Standard في المجموعة النهائية لذلك الـScope لمجرد inheritance. يظل Composer Profile ومرجعه جزءًا من الحل البنيوي، ولا يتغير inheritance أو أي Profile. هذا تطبيق للقاعدة العامة التي تملكها كل Standard، وليس استثناءً أو special case لاسم Profile. + +## 8. Local Directory Layout وسلامة الروابط + +عند نسخ Pinned Adoption Files إلى المشروع، يجب الحفاظ على البنية النسبية اللازمة لسلامة الروابط بين الملفات المختارة. المثال النهائي التالي يوضح أن Adoption Standard وProfile manifests المفعلة والموروثة جزء من النسخة المحلية، بينما تبقى المعايير الهندسية انتقائية: + +```text +docs/php-engineering-standards/ +├── STANDARDS_MANIFEST.md +└── standards/ + ├── STANDARDS_ADOPTION_STANDARD_AR.md + ├── profiles/ + │ ├── + │ └── + ├── ai/ + │ └── + ├── modules/ + │ └── + ├── packages/ + │ └── + └── testing/ + └── +``` + +تكون `` و`` أسماء الملفات المحلية الفعلية، ولا تعني placeholders لنسخ كل محتوى مجلد `profiles/`. + +لا تُنسخ: + +```text +unused profiles +unused engineering standards +docs/audits/ +docs/decisions/ +``` + +لا يشترط الاعتماد نسخ Folders فارغة، ولا تدخل الملفات التاريخية في Adoption Set. تظل `docs/audits/` و`docs/decisions/` في المستودع المركزي للتاريخ والحوكمة فقط. + +## 9. عقد `STANDARDS_MANIFEST.md` + +يجب أن يحتفظ كل مشروع تابع بملف: + +```text +docs/php-engineering-standards/STANDARDS_MANIFEST.md +``` + +أو بالاسم نفسه تحت local standards root المعتمد للمشروع. الـ Manifest هو inventory وresolver record، وليس Standard جديدة. يجب أن يسجل على الأقل: + +```text +Upstream Repository +Adoption Commit +Adoption Date أو metadata مناسبة وفق سياسة المشروع +Pinned Adoption Control Set +Active Profiles +Profile Version لكل Profile Activation +Scope لكل Profile Activation +Resolved Applicable Standards Set (final only; no non-applicable candidates) +Version لكل Standard +Explicit Additional Standards إن وجدت (مراجع الإدخال؛ لا تثبت وحدها applicability) +Explicit Exceptions/Overrides إن وجدت +``` + +يجب أن تجعل البيانات المسجلة قابلة لمراجعة العلاقة بين كل Profile Activation وScope والـ Control Set والـ Final Resolved Applicable Standards الناتجة عنها. لا تضع في Manifest القواعد الهندسية الكاملة؛ استخدم روابط إلى الملفات المملوكة لها. لا تسجل Candidate Standard غير منطبقة ضمن `Resolved Applicable Standards Set`؛ تظل سلامة مراجعها البنيوية قابلة للتحقق من ملفات Profiles المثبتة أو resolution evidence، وتظل Explicit Additional Standard مدخلًا معلنًا لا يتجاوز applicability canonical. + +يسجل `Explicit Exceptions/Overrides` الاستثناءات المعتمدة والموثقة الداخلة في Adoption مكتملة فقط. لا يمثل هذا الـManifest حالة مقترحة أو غير محسومة؛ تطبق عليه حدود الاكتمال والترقية في §16. + +## 10. تكامل `AGENTS.md` في المشروع التابع + +يكفي أن يشير `AGENTS.md` في المشروع التابع إلى `STANDARDS_MANIFEST.md` وإلى هذا Adoption Standard، بدل سرد كل Standard يدويًا. عند بدء مهمة، يلتزم الوكيل بمسار resolution المناسب لنوع المهمة. + +### 10.1 Normal Engineering Task + +في المهمة الهندسية العادية: + +1. يقرأ الوكيل `STANDARDS_MANIFEST.md`. +2. يحدد Scope الملفات المتأثرة. +3. يحدد Profile Activations المنطبقة المسجلة محليًا. +4. يستخدم الـ Applicable Standards Set المسجلة في Manifest. +5. يمكنه التحقق من composition عبر Profile manifests المحلية المثبتة. +6. يقرأ Applicable Standards فقط. + +في هذا المسار يستخدم الوكيل Final Resolved Applicable Standards المحلية فقط؛ لا يعيد Stage 1 أو Stage 2 ولا يحتاج Candidate Standards غير المنطبقة أو الاتصال بـ upstream. لا يعاد بناء adoption من upstream في كل Task، ولا يحتاج الوكيل الاتصال بـ upstream لإتمام مهمة عادية. + +### 10.2 Adoption / Upgrade / Manifest Validation + +في Adoption أو Upgrade أو Manifest Validation، تظل Profile manifests المحلية المثبتة هي مدخلات Active Profile Activation وinheritance وControl Set. ومنها، مع Explicit Additional Standard references المعلنة، يُبنى Structural / Transitive Resolution ومجموعة Candidate Standard References. أما تعريفات الـStandards المرشحة اللازمة للتحقق البنيوي في Stage 1 وcanonical applicability في Stage 2، فتُقرأ من exact upstream Adoption Commit، ولا يلزم نسخ Candidate Standard غير منطبقة إلى المشروع المحلي. + +يُختار مصدر الـCommit الدقيق كالتالي: + +- **Adoption:** exact upstream Adoption Commit المقترح الذي سيسجل في Manifest بعد اكتمال Adoption. +- **Manifest Validation:** exact `Adoption Commit` المسجل في Manifest لإعادة التحقق من كل Candidate Standard reference وتعريفه وcanonical applicability الخاصة به، ثم مقارنة Final Resolved Applicable Standards Set الناتجة بالـManifest. +- **Upgrade:** exact upstream Adoption Commit الجديد المقترح، مع إعادة حل Profile Activations المسجلة ومقارنة النتيجة المقترحة بالـManifest السابقة دون استبدالها قبل اكتمال Upgrade. + +يجب أن تتطابق Profile manifests المحلية المثبتة مع Control inputs للـAdoption Commit المستخدم وفق قاعدة §4. لا يضيف هذا الإجراء أي Manifest fields؛ يستخدم `Upstream Repository` و`Adoption Commit` الموجودين. إذا تعذر الوصول إلى exact Commit المطلوب لتنفيذ Structural / Transitive Resolution أو Canonical Standard Applicability، فتكون النتيجة حتمًا `Resolution Status = INVALID` وفق §16.3، ولا تنشأ عن عدم توفره Exception؛ ومع عدم وجود deviation مستقلة تكون `Exception State = NONE`. ينطبق ذلك سواء كان الإجراء Adoption أو Upgrade أو Manifest Validation. لا يستخدم floating `main` أو أي مرجع متحرك، ولا يُخمن أي تعريف، ولا ينشأ fallback source. عدم توفر الـCommit ليس `OWNER DECISION REQUIRED` أو Exception أو deviation قابلة للموافقة، ولا يثبت أن Standard مفقودة أو أن محتوى الـCommit broken؛ بل يعني أن required pinned verification input غير متاح، ولذلك لا يمكن إثبات resolution المطلوبة ولا يجوز للمالك تحويل النتيجة إلى `VALID`. + +في Manifest Validation أو Upgrade، تبقى أي Manifest سابقة صحيحة كما هي؛ ولا تنشأ أو تعدل canonical Manifest قبل نجاح إعادة التحقق. مسار الاستعادة الوحيد هو إتاحة exact Commit ثم إعادة تنفيذ Resolution / Validation وإعادة تقييم الحالة. يظل حظر floating refs وحدود Manifest في §16.5 قائمين. + +## 11. Additional Standards + +يجوز للمشروع إضافة Standard مستقلة خارج Profiles كمرشح عندما تنطبق على Scope محدد. يجب أن يكون مرجعها canonical وصحيحًا بنيويًا، وأن تسجل تحت `Explicit Additional Standards` في Manifest كمدخل معلن، وتظل مثبتة إلى نفس Adoption Commit افتراضيًا. بعد ذلك تخضع للمرحلة الثانية نفسها: لا تجعل الإضافة applicability الخاصة بالـStandard أوسع، ولا تدخل المجموعة النهائية إذا كانت canonical applicability تستبعد الـScope أو الـartifact الفعلي. + +لا يجوز استخدام Additional Standards كطريقة غير مباشرة للعودة إلى نسخ كل محتوى `standards/`. يجب أن يكون لكل إضافة سبب applicability ومسار أو Scope واضح. + +## 12. الترقية والمراجعة والتتبع + +تتم ترقية الاعتماد عبر reviewed change تسجل: + +- الـ Adoption Commit الجديد. +- Profiles والإصدارات المستخدمة بعد الترقية. +- إعادة حل Scopes والـ Control Set والـ Applicable Standards Set. +- أي Standard أضيفت أو أزيلت ولماذا. +- أثر الروابط النسبية والاستثناءات. + +الترقية لا تعني Refresh شاملًا للمستودع. يعاد Resolve للـ Profiles المفعلة فقط، وتبقى Standards غير المنطبقة خارج النسخة المحلية. + +## 13. Adoption Precedence + +هذا المعيار يحدد applicability وcomposition، ولا يلغي هرم الأولوية العام في `AI_COLLABORATION_WORKFLOW_AR.md`. عند وجود تداخل: + +1. تنتج Profile Activations مع inheritance مجموعة المرشحين البنيوية. ولا يحذف Profile Standard موروثة من هذه المجموعة لمجرد specificity أو preference أو تفعيل Profile أخرى. +2. بعد اكتمال الحل البنيوي، تحدد canonical applicability التي تملكها كل Standard إن كانت تدخل المجموعة النهائية؛ لا يوسع Profile أو Manifest applicability ولا يلغيها. +3. تخضع Explicit Additional Standards للقاعدة نفسها، ولا يحول إدراجها إلى Manifest المرجع غير المنطبق إلى Standard منطبقة. +4. تطبق تعليمات `AGENTS.md` الخاصة بالمشروع وفق أولوية المشروع، وتكون أي deviations أو overrides مسموح بها صراحةً في العقد واضحة ومسجلة. +5. تبقى تعليمات المالك الحالية والقرارات المعتمدة أعلى من عقد الاعتماد وفق هرم المسؤولية المعمول به، لكنها لا تحول reference أو graph مكسورًا إلى Structural Resolution صحيح. + +عند تعارض غير محسوم بين مصادر ذات أولوية متقاربة، لا يُحسم بالتخمين؛ يجب تسجيله ورفعه للمالك. + +## 14. Invariants + +يجب أن تظل الحقائق التالية صحيحة عند اعتماد أي مشروع: + +```text +Central canonical source: YES +Adoption Standard present locally: YES +Active Profile manifests pinned locally: YES +Inherited Profile manifests pinned locally: YES +Unused Profile manifests copied: NO +Applicable Standards only: YES +Ordinary task requires upstream network: NO +Manifest independently auditable against pinned local Control inputs and its exact recorded upstream Adoption Commit: YES +Same upstream commit by default: YES +Floating main: NO +Full repository snapshot: NO +Historical audits and decisions copied to consumers: NO +Underlying standards remain source of truth: YES +``` + +## 15. Adoption Review Checklist + +قبل قبول Adoption أو Upgrade، يجب التحقق من: + +- [ ] وجود Upstream Repository وAdoption Commit ثابت. +- [ ] وجود Adoption Standard محليًا ضمن Pinned Adoption Control Set. +- [ ] وجود كل Active Profile manifest محليًا ومثبتًا. +- [ ] وجود كل inherited Profile manifest لازمة للحل محليًا ومثبتة. +- [ ] عدم نسخ Profile غير مستخدمة. +- [ ] عدم استخدام floating `main`. +- [ ] عدم نسخ `standards/` بالكامل افتراضيًا أو احتياطيًا. +- [ ] وجود Profile ID وVersion وScope لكل Activation. +- [ ] سلامة inheritance وعدم وجود cycle. +- [ ] وجود وصحة بنيوية لكل مراجع `Required Standards` المباشرة والموروثة في `Stage 1 / Candidate Standard References`؛ يظل أي مرجع Required Standard مفقود أو مكسور `Structural Invalidity` قبل Stage 2. +- [ ] اقتصار `Pinned / Final Resolved Applicable Standards Set` على Standards التي اجتازت canonical applicability الخاصة بها في `Stage 2`. +- [ ] عدم اشتراط إدراج Candidate Standard استُبعدت بصورة deterministic وفق canonical applicability المملوكة لها في مجموعة `Final / Pinned Applicable Standards Set`. +- [ ] تطبيق resolution عابر للـ Profiles دون تكرار يدوي. +- [ ] تطابق Control Set وApplicable Standards Set مع Manifest. +- [ ] عدم حاجة المهمة الهندسية العادية إلى upstream network. +- [ ] الحفاظ على relative links والبنية اللازمة لها. +- [ ] تسجيل Additional Standards والاستثناءات صراحةً. +- [ ] عدم إدخال `docs/audits/` أو `docs/decisions/` في Adoption Set. +- [ ] قراءة الوكيل للـ Standards المنطبقة فقط على Scope المهمة. +- [ ] سلامة البنية قبل تقييم Exceptions، وعدم تحويل Structural Invalidity إلى حالة قابلة للـwaive. +- [ ] تسجيل Resolution Status لكل Profile Activation/Scope بصورة مستقلة، دون إخفاء نتيجة غير صحيحة بنتيجة أخرى. +- [ ] تطبيق أولوية التجميع `INVALID` ثم `OWNER DECISION REQUIRED` ثم `VALID`. +- [ ] الفصل بين Resolution Status وException State واستخدام الحالات الثلاث المحددة لكل منهما فقط. +- [ ] عدم تطبيق Requested Exception أو اعتبارها موافقة. +- [ ] عدم إنشاء أو تحديث canonical Manifest لحالة Adoption/Upgrade غير محسومة، مع إبقاء Manifest صالحة سابقة كما هي أثناء Upgrade غير محسومة. + +## 16. حسم Adoption وفشلها والاستثناءات + +يحدد هذا القسم نتائج Adoption وUpgrade وManifest Validation. لا ينشئ Resolver أو Validator executable، ولا يغير Profile composition أو inheritance أو حقول Manifest القائمة. + +### 16.1 تشخيص كل Profile Activation/Scope + +كل Profile Activation مع Scope محدد وحدة تشخيص مستقلة. يربط كل تشخيص بـ`Profile ID` والـScope والـpinned inputs المستخدمة، وينتج بصورة deterministic `Resolution Status` خاصًا به، مع تسجيل `Exception State` الخاصة به عند انطباقها. + +لا تدمج نتائج Activations مختلفة في تشخيص واحد قبل تسجيل نتيجة كل منها، ولا تسمح نتيجة `VALID` لـActivation بإخفاء نتيجة `INVALID` أو `OWNER DECISION REQUIRED` لـActivation أخرى. وإذا تكرر Profile على Scopes مختلفة، تسجل نتيجة كل Activation/Scope على حدة؛ لا تنشأ `Aggregate Exception State`. + +### 16.2 Overall Resolution Status + +القيم الوحيدة لـ`Resolution Status`، على مستوى Activation/Scope والنتيجة الإجمالية، هي: + +```text +VALID +INVALID +OWNER DECISION REQUIRED +``` + +تحسب النتيجة الإجمالية لكل Activations/Scopes المنطبقة وكل قرارات Adoption المعلقة وفق الترتيب التالي: + +```text +If ANY applicable Activation / Scope is INVALID +→ Overall Resolution Status = INVALID + +Else if ANY applicable Activation / Scope +or any unresolved adoption decision +requires Owner Decision +→ Overall Resolution Status = OWNER DECISION REQUIRED + +Else +→ Overall Resolution Status = VALID +``` + +الأولوية الإلزامية هي: + +```text +INVALID +> +OWNER DECISION REQUIRED +> +VALID +``` + +وجود Owner Decision معلقة لا يغيّر `INVALID` الناتجة عن أي Structural Invalidity أو حالة `INVALID` أخرى إلى `OWNER DECISION REQUIRED`. + +### 16.3 Structural Invalidity غير قابلة للاستثناء + +تشمل Structural Invalidity، على الأقل: + +```text +missing required Standard +missing active Profile +missing required inherited Profile +missing or broken Explicit Additional Standard reference +inheritance cycle +broken required reference +missing mandatory structural metadata +structural Manifest mismatch +``` + +يشمل `structural Manifest mismatch` عدم مطابقة ما يسجله Manifest فعليًا للـresolved Control Set أو Final Resolved Applicable Standards Set الناتجة من المرحلتين أو Profile Activations أو الـpinned structure المطلوبة. لا يعد عدم تسجيل Candidate Standard مستبعدة canonical ضمن Final Applicable Set mismatch؛ لكن يجب أن تظل كل مراجع Profile وRequired Standards قابلة للتحقق بنيويًا قبل تقييم applicability. يراعي فحص التطابق فقط deviations التي يسمح هذا العقد باستثنائها صراحةً؛ فلا يصبح deviation موثق ومسموح Structural Invalidity لمجرد أنه exception. لكن لا يجوز لأي exception أن يتجاوز أي بند من قائمة Structural Invalidity أعلاه؛ ويظل missing required Standard أو Profile أو inheritance أو reference أو metadata المطلوبة Structural Invalidity غير قابلة للـwaive. + +عدم توفر exact upstream Adoption Commit المطلوب لمراجعة أو تنفيذ Structural / Transitive Resolution أو Canonical Standard Applicability يُصنف كفشل تحقق fail-closed، وتكون نتيجته حتمًا `Resolution Status = INVALID`. لا تنشأ عن هذه الحالة Exception؛ وتكون `Exception State = NONE` ما لم توجد deviation مستقلة أخرى تنطبق عليها دورة §16.4. هذا لا يعني أن Standard نفسها مفقودة أو أن محتوى الـCommit broken؛ يعني فقط أن required pinned verification input غير متاح، فلا يمكن إثبات resolution المطلوبة. هذه الحالة ليست Owner Decision أو deviation أو Exception قابلة للموافقة، ولا يملك المالك تحويلها إلى `VALID`. لا تستخدم لها floating ref أو fallback source أو تعريفات مخمّنة. مسار الاستعادة الوحيد هو إتاحة exact Commit ثم إعادة تنفيذ Resolution / Validation وإعادة تقييم الحالة. + +كل Structural Invalidity تنتج `Resolution Status = INVALID`. لا يمكن لـOwner Approval تحويل graph أو structure مكسورة إلى `VALID`، ولا يعد قرار المالك إصلاحًا بنيويًا: + +```text +Owner Decision +≠ +Structural Repair +``` + +المسار الوحيد لإزالة Structural Invalidity هو: + +```text +Detect Structural Invalidity +→ Repair Graph / Structure +→ Re-resolve +→ Re-evaluate +``` + +لا تنشئ Structural Invalidity نفسها Exception؛ ويظل `Exception State = NONE` ما لم توجد deviation أخرى مستقلة وقابلة للاستثناء أصلًا. + +والاستبعاد deterministic وفق canonical Standard applicability في Stage 2 ليس Structural Invalidity أو deviation أو Exception، ولا يحتاج إلى طلب أو موافقة Exception؛ يظل `Exception State = NONE` ما لم توجد deviation مستقلة أخرى. + +### 16.4 Exception State ودورة حياة الاستثناء + +القيم الوحيدة لـ`Exception State` لكل deviation/Activation ذات صلة هي: + +```text +NONE +REQUESTED +APPROVED_AND_DOCUMENTED +``` + +هذه الحالة مستقلة عن `Resolution Status` ولا تستبدلها. لا تنشأ قيمة Aggregate أو حالة رابعة عند وجود عدة Activations أو Exceptions؛ تحتفظ كل واحدة بحالتها، ثم تطبق قواعد التجميع في §16.2. + +تقتصر دورة الاستثناء على deviation أو override يسمح هذا العقد باستثنائها أصلًا، ولا تشمل Structural Invalidity: + +- **Unauthorized deviation:** إذا طُبق deviation قبل استيفاء مسار Request وApproval الصالح، بما في ذلك تطبيق Exception ما زالت `REQUESTED`، تكون النتيجة `Resolution Status = INVALID` و`Exception State = NONE`. لا يحول الاستخدام الفعلي غير المصرح به إلى Exception معتمدة. +- **Requested exception:** يبقى الاستثناء غير المطبق قبل القرار في `Resolution Status = OWNER DECISION REQUIRED` و`Exception State = REQUESTED`. الطلب ليس موافقة؛ لا تطبق الـdeviation ولا تعتبر Adoption مكتملة قبله. والموافقة وحدها دون توثيق السبب والنطاق والسلطة لا تحقق `APPROVED_AND_DOCUMENTED` ولا تسمح بالتطبيق أو الاكتمال؛ إذا لم تطبق الـdeviation بعد، تبقى النتيجة `OWNER DECISION REQUIRED` والحالة `REQUESTED` حتى تكتمل متطلبات الاستثناء. وإذا طُبقت قبل ذلك، تنطبق قاعدة `Unauthorized deviation` أعلاه. +- **Approved exception:** بعد موافقة المالك وتوثيق سبب الاستثناء ونطاقه والسلطة المعتمدة له، تكون `Exception State = APPROVED_AND_DOCUMENTED`. يمكن أن تكون `Resolution Status = VALID` فقط عندما تكون graph سليمة، ولا توجد Structural Invalidity أو Owner Decisions أخرى معلقة، ويسجل الاستثناء في Manifest عند اكتمال Adoption. + +إذا كان المطلوب Owner Decision لا يتعلق بطلب Exception، مثل ambiguity غير محسومة، تكون النتيجة `Resolution Status = OWNER DECISION REQUIRED` و`Exception State = NONE`. + +### 16.5 حدود canonical Manifest أثناء Adoption وUpgrade + +`STANDARDS_MANIFEST.md` هو record لاعتماد مكتمل فقط. لا ينشأ ولا يحدث ليعرض proposed state تكون `Overall Resolution Status` فيها `INVALID` أو `OWNER DECISION REQUIRED`. لا تنشأ Draft Manifest أو أداة/ملف بديل لها؛ تحفظ الحالات المقترحة والقرارات غير المحسومة في review evidence فقط. + +إذا كان للمشروع Manifest سابقة تمثل Adoption صحيحة، ثم أصبحت Upgrade مقترحة `INVALID` أو `OWNER DECISION REQUIRED`، تبقى Manifest المعتمدة الحالية كما هي ولا تستبدل بالحالة المقترحة. لا تثبت Manifest السابقة صلاحية الـUpgrade الجديدة. لا تستبدل بها إلا بعد أن تصبح نتيجة الـUpgrade الجديدة `VALID` وتكتمل Adoption. + +لا يضيف هذا القسم حقولًا جديدة إلى Manifest؛ يسجل الحقول القائمة النتيجة المكتملة والاستثناءات المعتمدة والموثقة فقط. + +### 16.6 Fail-Closed Review Contract + +في Adoption أو Upgrade أو Manifest Validation، يسير الفحص بالترتيب التالي: + +1. تنفيذ Structural / Transitive Resolution فعليًا من ملفات Profiles المحلية المثبتة، مع جمع والتحقق من كل Required Standard references وExplicit Additional Standard references لإنتاج Candidate Standard References. +2. التحقق من Structural Integrity لكل المرشحين والبنية قبل أي تصفية بسبب applicability أو تقييم للاستثناءات؛ يظل المرجع المكسور Structural Invalidity حتى إذا كان متوقعًا استبعاده في المرحلة التالية. +3. تنفيذ Canonical Standard Applicability لكل Candidate Standard مقابل كل Activation/Scope وحقائق الـartifact، وتكوين Final Resolved Applicable Standards Set؛ لا يطبق Profile أو Additional Standard override على scope المعيار الأصلي. +4. تشخيص كل Activation/Scope على حدة، بما في ذلك نتيجة applicability؛ والاستبعاد deterministic لا ينتج حالة Invalid أو Exception. +5. تقييم الاستثناءات المسموح بها وحالتها، دون تطبيق أي Requested Exception. +6. حساب Overall Resolution Status بقواعد §16.2. +7. عدم اعتبار Adoption مكتملة إلا إذا كانت `Overall Resolution Status = VALID`. + +`OWNER DECISION REQUIRED` ليست نجاحًا، و`REQUESTED` ليست موافقة، و`APPROVED_AND_DOCUMENTED` لا تصلح Structural Invalidity. diff --git a/docs/php-engineering-standards/standards/ai/AI_COLLABORATION_WORKFLOW_AR.md b/docs/php-engineering-standards/standards/ai/AI_COLLABORATION_WORKFLOW_AR.md new file mode 100644 index 0000000..197195f --- /dev/null +++ b/docs/php-engineering-standards/standards/ai/AI_COLLABORATION_WORKFLOW_AR.md @@ -0,0 +1,1245 @@ +# معيار التعاون مع وكلاء الذكاء الاصطناعي وإدارة التنفيذ + +## بيانات المعيار + +- **Standard ID:** `std-ai-collaboration-workflow` +- **Standard Version:** `6.0.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` +- **اللغة المعتمدة:** العربية. +- **حالة الاعتماد:** يصبح معتمدًا عند دمجه في الفرع الافتراضي للمشروع. +- **مالك المعيار:** مالك المشروع. +- **سلطة التعديل:** لا يُعدّل هذا المعيار إلا بموافقة صريحة من مالك المشروع ومن خلال تغيير قابل للمراجعة. +- **النطاق:** إدارة العمل بين مالك المشروع، والمساعد القائد، والمنفذ المحلي (Local Executor)، وJules. +- **الهدف:** تحويل التعاون مع وكلاء الذكاء الاصطناعي إلى عملية هندسية منضبطة، قابلة للمراجعة، ومبنية على الأدلة. + +> **القاعدة العليا:** مالك المشروع هو صاحب القرار النهائي في الهدف، والأولوية، والنطاق، والقرارات المعمارية، وصلاحيات Git، والـ Pull Request، والـ Merge. + +--- + +# 1. المرجع الواحد للحقيقة + +هذا الملف هو **المصدر الوحيد للحقيقة للقواعد العامة** الخاصة بتقسيم الأدوار، والتعاون، والتنسيق، وإدارة التنفيذ والمراجعة بين مالك المشروع، والمساعد القائد، والمنفذ المحلي (Local Executor)، وJules. + +> **ملاحظة محددة حول دورة حياة Git:** بينما يدير هذا الملف صلاحيات الأدوار، فإن **المصدر النهائي لدورة حياة الـ Branch و PR و Merge (نموذج الـ Phase Stack)** هو [`../GITHUB_PHASE_STACK_WORKFLOW_AR.md`](../GITHUB_PHASE_STACK_WORKFLOW_AR.md). يجب ألا تُفسّر أي قاعدة في هذا الملف بما يتعارض مع حدود التكامل في Phase Draft أو Execution Batch كما يحددها ذلك المعيار؛ لا تعني كل Phase أو Work Unit دورة GitHub مستقلة. + +مسؤولية المساعد القائد عن المراجعة المباشرة و`Fresh Full Acceptance Review` والحكم الهندسي مملوكة لهذا المعيار؛ ويكتفي Phase Stack بتحديد حدود Git والتكامل والإحالة إلى هذه المسؤولية. + +## 1.1 ما يجب أن يوجد خارجه + +تحتوي ملفات المشروع الأخرى فقط على ما يخص المشروع نفسه، مثل: + +- `AGENTS.md` لتفعيل هذا المعيار وتسجيل الاستثناءات أو القواعد الخاصة بالمشروع. +- المعايير المعمارية ومعايير بناء الموديولات أو المكتبات. +- ADRs والقرارات المعتمدة. +- audits وroadmaps وحالة التنفيذ. +- أوامر الاختبارات والتحليل الساكن الخاصة بالمشروع. + +ممنوع نسخ قواعد هذا المعيار العامة في عدة ملفات؛ لأن النسخ المتكرر يؤدي إلى اختلاف المرجع بمرور الوقت. + +## 1.2 دور `AGENTS.md` + +يجب أن يحقق `AGENTS.md` الجذري ثلاثة أمور فقط فيما يخص هذا المعيار: + +1. إلزام الوكيل بقراءة هذا الملف كاملًا قبل التخطيط أو التنفيذ أو المراجعة. +2. تحديد قواعد أو استثناءات خاصة بالمشروع. +3. تحديد أي `AGENTS.md` إضافية تنطبق على مسارات بعينها. + +إذا كانت هناك قاعدة عامة موجودة هنا، فلا تُعاد صياغتها داخل `AGENTS.md` إلا كاستثناء خاص واضح. + +## 1.3 ترتيب الأولوية عند التعارض + +عند وجود تعارض صريح تكون الأولوية كالتالي: + +1. تعليمات مالك المشروع الحالية في المحادثة أو التكليف الجاري. +2. ملفات `AGENTS.md` المنطبقة على المسار، من الأكثر تخصصًا إلى الجذري. +3. المصادر authoritative الخاصة بالمشروع: المعايير المعمارية، ADRs، القرارات المعتمدة، والعقود العامة. +4. التوجيه التنفيذي المحدد للمهمة، بشرط ألا يخالف المستويات الأعلى. +5. هذا المعيار العام. + +الـ audit والـ roadmap يصفان الحالة والخطة، لكنهما لا يتجاوزان عقدًا عامًا أو قرارًا معماريًا معتمدًا. + +إذا تعذر حسم التعارض بهذا الترتيب، يتوقف المنفذ ويعرض التعارض بدل اختيار تفسير من نفسه. + +--- + +# 2. قاعدة اللغة + +## 2.1 اللغة الأساسية + +التعامل بين مالك المشروع، والمساعد القائد، والمنفذ المحلي (Local Executor)، وJules يكون **بالعربية** افتراضيًا. + +يشمل ذلك: + +- شرح المهمة. +- القرارات والتبريرات. +- أسباب التوقف. +- تقارير التنفيذ. +- نتائج المراجعة. +- وصف وملخص الـ Pull Request. +- توجيهات التصحيح. + +لا يُستخدم تقرير كامل بالإنجليزية إلا بطلب صريح من مالك المشروع. + +## 2.2 المصطلحات التقنية + +تظل العناصر التقنية بصيغتها الأصلية عندما يكون ذلك أدق وأسهل للبحث، مثل: + +- أسماء الملفات والمسارات. +- أسماء الكلاسات والدوال والواجهات. +- أوامر Git والاختبارات. +- أسماء branches وcommits. +- phase names وgap IDs. +- رسائل الأخطاء الفعلية. + +## 2.3 أسلوب التواصل + +يجب أن تكون اللغة: + +- مباشرة. +- محددة. +- مبنية على أدلة. +- خالية من الادعاءات العامة غير المثبتة. + +مرفوض استخدام عبارات مثل «تم كل شيء» أو «الشغل مثالي» دون قائمة ملفات ونتائج تحقق فعلية. + +--- + +# 3. هرم المسؤولية + +ترتيب المسؤولية هو: + +1. **مالك المشروع.** +2. **المساعد القائد.** +3. **المنفذ المكلّف: المنفذ المحلي أو Jules.** + +لا يملك أي مستوى أدنى تغيير قرار صادر من مستوى أعلى. + +## 3.1 مالك المشروع + +مالك المشروع مسؤول عن: + +- تحديد الهدف التجاري أو التشغيلي. +- اعتماد السياسات والقرارات المعمارية. +- تحديد الأولوية. +- السماح أو منع توسيع النطاق. +- التصريح بعمليات Git والـ PR والـ Merge. +- قبول أو رفض تأجيل فجوة أو مرحلة. +- اتخاذ قرار الدمج النهائي. + +## 3.2 المساعد القائد + +المساعد القائد ليس dispatcher للتنفيذ؛ بل يعمل بصفته صاحب المسؤولية الهندسية المباشرة عن فهم الحالة، وتصميم الحل، ومراجعة الناتج، مع بقاء قرار المالك النهائي في المسائل التي يحددها هذا المعيار. + +المساعد القائد يعمل بصفته: + +- Technical Lead. +- Architect ضمن العقود والقرارات المعتمدة. +- Work Coordinator. +- Prompt Author. +- Final Reviewer قبل عرض قرار الدمج على المالك. + +مسؤولياته: + +- إعادة بناء الحالة الفعلية من المستودع والمراجع authoritative المعتمدة ذات الصلة بالمهمة قبل التخطيط أو التفويض. +- اكتشاف الـ gaps والتعارضات والافتراضات غير المثبتة قبل بدء التنفيذ. +- تصميم الحل وتقسيم العمل داخل النطاق والعقود المعتمدة. +- اختيار المهمة التالية حسب الأولوية والتبعيات، لا حسب الرقم فقط. +- كشف التعارضات والملفات المشتركة قبل بدء التنفيذ. +- تقسيم العمل إلى Roadmap Phases وExecution Batches وWork Units غير متداخلة، مع عدم تحويل كل Phase أو Work Unit إلى Branch أو PR مستقلة دون سبب هندسي. +- اختيار المنفذ المناسب. +- كتابة توجيه تنفيذي مغلق الحدود وبالحد الأدنى الكافي من المعلومات، مع اختبار ضرورة كل سطر قبل إرساله. +- مراجعة الكود أو التوثيق، والـ diff أو الـ staged patch، والـ checks، والـ PR بنفسه قبل قبول أي ناتج عندما تكون هذه العناصر متاحة. +- رفض الناتج أو طلب تعديله إذا خالف الواقع أو العقود أو النطاق، حتى لو ادعى تقرير المنفذ نجاحه. +- تصحيح عنوان أو وصف الـ PR عند توفر الصلاحية. +- تصنيف النتيجة: جاهزة، تحتاج تعديلًا، تحتاج follow-up، أو يجب إيقافها. + +### 3.2.1 مسؤولية القرار الهندسي + +- يحسم المساعد القائد القرارات التقنية الطبيعية اللازمة للتنفيذ داخل Scope مغلق وعقود أو قرارات معتمدة، بشرط أن تكون مبنية على الأدلة المتاحة وألا تنشئ سياسة أو public contract أو معمارية جوهرية جديدة. +- إذا كان القرار معماريًا جوهريًا، أو يغير Public Contract، أو يوسع Scope توسعًا مؤثرًا، أو يغير سياسة، أو يتطلب اختيارًا بين بدائل ذات أثر كبير، يعرض المساعد القائد على مالك المشروع الأدلة والبدائل والـ trade-offs والتوصية إن وجدت، ويبقى القرار غير محسوم حتى يعتمد المالك الخيار النهائي. +- لا يقرر المنفذ السياسة أو المعمارية من نفسه، ولا يحول ملاحظة تنفيذية أو تعليق مراجعة إلى قرار أعلى من صلاحياته. +- أي Final Review أو Independent Review إضافي هو طبقة تحقق إضافية، ولا يلغي مسؤولية المساعد القائد عن مراجعته المباشرة للكود أو التوثيق والـ diff والـ PR قبل القبول. + +### 3.2.2 سلطة التنفيذ داخل الـPhase أو الـExecution Batch + +بعد اعتماد Scope الـPhase أو Execution Batch صراحة من مالك المشروع، يملك المساعد القائد **Standing Execution Authority داخل الـPhase أو الـBatch**، عندما تكون الأدوات والصلاحيات متاحة، لإدارة دورة التنفيذ دون الرجوع للمالك عند كل Micro-step. + +تشمل هذه السلطة: + +- تقسيم Work Units وتحديد dependency graph وExecution Waves. +- اختيار المنفذين وتشغيل Work Units المستقلة بالتوازي عندما تثبت شروط الاستقلال ويكون صافي الزمن أقل، أو إعادة استخدام نفس السياق والمنفذ عندما يكون ذلك أسرع. +- فتح وإدارة Branches وPRs اللازمة فقط بحسب حدود العزل والمراجعة والـrollback والتكامل. +- إعادة Verification واعتماد Component. +- **GitHub Squash Merge عبر Component PR إلى Phase Draft عند وجود Draft منفصلة** بعد اعتماد Scope الـPhase أو الـBatch، وفقط بعد: + - direct review للكود أو التوثيق والـdiff والـPR. + - اجتياز Component Gate المطلوبة. + - التحقق من صحة PR base/head ومن عدم وجود blocker. + - التحقق من توافق Component مع أحدث Phase Draft HEAD. + +لا يحتاج هذا الـComponent Merge إلى confirmation جديدة من المالك لكل Component، لأنه داخل Standing Execution Authority المحددة بعد اعتماد Scope الـPhase أو الـBatch. أما Work Units المتتابعة داخل Work Branch واحدة فلا تحتاج Component PR مستقلة لمجرد الحفاظ على رقم Phase أو Component. + +ولا تشمل: + +- تغيير Architecture أو Policy أو Public Contract جوهري. +- توسيع Scope توسعًا مؤثرًا. +- دمج Phase Draft أو Batch Integration Boundary إلى `main`. +- Tag أو Release أو Publish. + +لا تلغي Standing Execution Authority مسؤولية المساعد القائد عن الأدلة والمراجعة المباشرة، ولا تمنح المنفذ Merge Authority تلقائية. + +### 3.2.3 حدود تنفيذ المساعد القائد + +لا يفرض هذا المعيار منفذًا ثابتًا لنوع معين من المهام. يحدد المشروع أو المرحلة أو المهمة أو مالك المشروع المنفذ المناسب، ويظل المساعد القائد مسؤولًا عن ملاءمة التعيين وحدود المهمة ومراجعة الناتج. + +- تعديل PR metadata ومراجعة GitHub جزء من دور المساعد القائد عند توفر الصلاحية. +- لا ينفذ المساعد القائد تغييرات داخل المستودع إلا بتكليف صريح من مالك المشروع، أو وفق صلاحية تنفيذ محددة في تعليمات المشروع أو المهمة، أو وفق Standing Execution Authority داخل Phase بعد اعتماد Scope. +- عند تكليفه بالتنفيذ، يخضع لنفس قواعد النطاق والتحقق وصلاحيات Git المطبقة على أي منفذ. + +### 3.2.4 استلام PR من Jules + +بعد أن ينهي Jules مهمته ويكتب على branch جديدة خاصة بالمهمة الحالية (Jules task branch)، تصبح بيانات الـ PR النهائية مسؤولية المساعد القائد: + +1. يجلب الـ PR الفعلية والـ remote HEAD الحالية. +2. يراجع الـ changed files والـ diff والـ checks والـ base freshness. +3. لا يعتمد وصف Jules أو SHA مذكورة في تقريره باعتبارها نهائية دون تحقق. +4. إذا نجحت المهمة بالكامل، يحدّث المساعد القائد عنوان ووصف الـ PR بالعربية وبالمعلومات النهائية المؤكدة. +5. إذا كانت المهمة غير مكتملة، لا يُجمّل وصف الـ PR؛ بل يطلب التصحيح أو يوقفها. + +هذا الـ handoff طبيعي؛ لأن Jules قد يستطيع الكتابة وفتح PR، لكنه لا يُعتمد عليه لتعديل PR metadata بعد آخر كتابة أو بعد تغير الـ remote HEAD. + +## 3.3 المنفذ المحلي (Local Executor) + +المنفذ المحلي هو منفذ يمكن تكليفه بأي عمل يسمح به تعليمات المشروع أو المرحلة أو المهمة. بيئة المنفذ المحلي المعتمدة **توفر** `git`، و `gh`، و `Docker` / `Docker Compose`، وأدوات لغة المشروع والاختبارات والتحليل. يستخدم المنفذ الأدوات المتاحة وفق حاجة المهمة ولا يُطلب منه تثبيتها كافتراض ابتدائي، وإذا كانت أداة مطلوبة غير متاحة يتوقف ويعرض الدليل. + +قد يُكلّف، بحسب التوجيه الفعلي، بـ: + +- Runtime code. +- Services وRepositories وControllers. +- Contracts وDTOs وEnums. +- Unit وIntegration tests. +- PHPUnit وstatic analysis. +- التنفيذ والاختبار المحلي ومراجعة checkout محلي كامل والـ diff الناتج. + +المنفذ المحلي لا يختار المهمة أو السياسة أو المعمارية من نفسه. + +## 3.4 Jules + +Jules منفذ يمكن تكليفه بمهمة محددة عندما ينص توجيه المشروع أو المرحلة أو المهمة أو قرار مالك المشروع على ذلك، ولا يربط هذا المعيار نوعًا معينًا من العمل به تلقائيًا. + +عند تكليفه، قد تشمل مهمته: + +- lifecycle documentation review مقابل الكود. +- evidence-based audits. +- roadmap updates. +- توثيق القرارات المعتمدة. +- Documentation-only corrections. +- مهام صغيرة واضحة قليلة المخاطر. + +Jules لا يقرر سياسة أو معمارية من نفسه، ولا يحول نطاق المهمة إلى Runtime change أو عمل آخر دون تصريح. + +--- + +# 4. قاعدة اختيار المنفذ + +- لا يحدد هذا المعيار منفذًا ثابتًا حسب نوع المهمة؛ يحدد الاختيارَ توجيه المشروع أو المرحلة أو المهمة أو قرار مالك المشروع. +- يتحقق المساعد القائد قبل التعيين من ملاءمة المنفذ للقدرات المطلوبة، وتعارضات الملفات، والـ dependencies، وصلاحيات Git، وحدود المهمة. +- أي منفذ مكلّف مسؤول عن تنفيذ نطاقه وعرض أدلته، لكنه لا يملك بذلك صلاحية تقرير السياسة أو المعمارية أو قبول ناتجه. +- تظل مراجعة المساعد القائد المباشرة إلزامية مهما كان المنفذ المختار، وتظل قواعد Jules الخاصة مشروطة باستخدام Jules فعليًا في المهمة. + +--- + +# 5. المبادئ غير القابلة للتفاوض + +## 5.1 أحدث حالة فعلية أولًا + +قبل التخطيط أو التنفيذ يجب التحقق من: + +- branch الحالي. +- HEAD الحالي. +- working tree. +- staged state. +- أحدث base branch أو exact base SHA. +- الـ PRs النشطة ذات الصلة. +- الملفات المرجعية الحالية. + +ممنوع استخدام SHA أو تقرير سابق دون إعادة تحقق إذا تحرك المستودع. + +## 5.2 الأدلة قبل الادعاء + +أي claim يجب أن يستند إلى دليل مثل: + +- كود حالي. +- diff فعلي. +- اختبار تم تشغيله. +- ناتج static analysis. +- schema snapshot حالي. +- audit أو roadmap حالي. +- بيانات PR فعلية. + +ممنوع الادعاء بنجاح أمر لم يُشغّل. + +### 5.2.1 لا تخمين ولا افتراض في القرارات الهندسية + +- لا تُبنى القرارات الهندسية على التخمين أو الافتراض غير المثبت. +- أي معلومة يمكن إثباتها من الكود أو المستندات أو العقود أو Git يجب فحصها فعليًا بدل افتراضها. +- إذا لم يوجد دليل كافٍ، تُصنف النقطة كغير محسومة، ولا يملؤها المنفذ أو المساعد القائد من عنده. +- يجوز للمساعد القائد حسم القرار التقني الطبيعي داخل Scope والعقود المعتمدة فقط بعد فحص الأدلة اللازمة؛ أما نقص الدليل فيبقى حالة توقف أو نقطة تُرفع للمالك بحسب نوع القرار. + +## 5.3 الأولوية بالتبعيات لا بالأرقام + +لا تُختار المهمة لأنها التالية رقميًا فقط. + +يجب فحص: + +- ما تعتمد عليه. +- ما الذي تفتحه للمراحل التالية. +- الملفات المشتركة. +- القرارات blocking. +- المخاطر. +- احتمال التعارض أو إعادة العمل. + +## 5.4 منع التداخل + +لا تبدأ مهمتان متوازيتان إذا كانتا: + +- تعدلان الملفات نفسها. +- تملكان المسؤولية نفسها. +- تحتاج إحداهما ناتج الأخرى. +- ستغلقان الفجوة نفسها بطرق مختلفة. + +تُغلق المهمة ذات التبعية أو الملف المشترك أولًا. + +## 5.5 النطاق المغلق + +كل مهمة يجب أن تحدد: + +- ما المملوك لها. +- الملفات المتوقعة. +- السلوك المطلوب. +- خارج النطاق. +- المسارات الممنوع لمسها. +- gaps أو phases غير المشمولة. + +رؤية مشكلة جانبية لا تمنح صلاحية إصلاحها. + +## 5.6 لا توسع دون قرار + +ممنوع إضافة ما يلي دون حاجة مثبتة واعتماد داخل النطاق: + +- abstraction عام. +- generic layer. +- schema أو migration. +- public contract جديد. +- module boundary جديد. +- workflow تشغيلي جديد. + +## 5.7 الحد الأدنى الكافي للـ Prompt + +الـ Prompt الجيد ليس الأطول، بل **الأقصر الذي يمنع الغموض ويكفي للتنفيذ والتحقق**. + +يجب أن يحتوي فقط على المعلومات التي تؤثر في واحد أو أكثر من الآتي: + +- ما الذي سينفذ. +- أين سينفذ. +- ما الممنوع. +- السلوك أو العقد المطلوب. +- الاختبارات والتحقق. +- صلاحيات Git. +- شكل التسليم أو سبب التوقف. + +قواعد الاختصار: + +- لا تكرر قاعدة موجودة في هذا المعيار أو `AGENTS.md`؛ أشِر إلى المرجع فقط. +- لا تنسخ audit أو roadmap أو ADR داخل الـ Prompt؛ اذكر المسار والقرار أو القسم المطلوب قراءته. +- لا تشرح تاريخ المشكلة إلا إذا كان يغيّر الحل المطلوب. +- لا تدرج حالات أو أوامر لا تخص المهمة الحالية. +- احذف أي قسم اختياري لا تستخدمه بدل ترك placeholders أو نص عام. +- استخدم قائمة ملفات ومسارات وأوامر دقيقة بدل فقرات تفسيرية طويلة. +- لا تكرر المعلومة نفسها في الهدف والنطاق وخارج النطاق والتقرير. +- المهمة الصغيرة يجب أن تحصل على Prompt صغير. +- المهمة المعقدة قد تحتاج Prompt أطول، لكن كل قسم فيها يجب أن يغير قرارًا تنفيذيًا أو بوابة تحقق. + +### اختبار الضرورة قبل إرسال الـ Prompt + +يسأل المساعد القائد عن كل سطر: + +> هل حذف هذا السطر يمكن أن يغيّر التنفيذ أو النطاق أو التحقق أو صلاحيات Git أو التقرير؟ + +إذا كانت الإجابة «لا»، يُحذف السطر. + +## 5.8 التوقف الصريح + +يتوقف المنفذ ويعرض الحالة الفعلية إذا وجد: + +- HEAD غير مطابق. +- working tree غير نظيف خلاف المطلوب. +- staged changes سابقة غير مملوكة للمهمة. +- تعليمات متعارضة. +- نقص صلاحية. +- dependency غير متوفرة. +- قرار blocking غير محسوم. +- base لا يمكن الوصول إليها. + +لا يحاول «إصلاح» الحالة من نفسه بعمليات Git غير مصرح بها. + +## 5.9 التوثيق الخفيف لا يعطل Runtime سليمًا + +إذا كان الـWork Unit قيد العمل يحتوي على Runtime واختبارات سليمة، ولكن التوثيق المرتبط مباشرة بـAcceptance الخاصة به لم يكتمل: +- **لا يجوز** فصل التوثيق لتجاوز Acceptance الـRuntime؛ يجب استكمال الـWork Unit بالكامل داخل الـExecution Batch وWork Branch/Phase Draft المعتمدة قبل دمج حد التكامل إلى `main`. +- لا ينشأ Documentation Work Unit مستقلة إلا عند وجود احتياج cross-cutting حقيقي أو ownership أو dependency مستقلة، وليس كمتبقيات لـAcceptance سابقة. +- **يُمنع قطعيًا** دمج Phase Draft أو Batch Integration Boundary إلى `main` قبل اكتمال Documentation وVerification وFinal Review المطلوبة لكل Phase داخلة في الـBatch. + +--- + +# 6. نموذج صلاحيات Git + +> **تنويه إلزامي:** يخضع أي عمل هندسي (Phase أو Execution Batch) على هذا المشروع لنظام Phase Stack الموثق بشكل إلزامي في [`../GITHUB_PHASE_STACK_WORKFLOW_AR.md`](../GITHUB_PHASE_STACK_WORKFLOW_AR.md). يجب تطبيق صلاحيات وعمليات Git المذكورة أدناه بما يتوافق تامًا مع Dependency-Aware Execution وحدود Phase Draft أو Batch Integration Boundary، ولا يجوز لأي قاعدة هنا تجاوز شرط اكتمال الـPhase أو الدمج الجزئي. + +## 6.1 أوامر القراءة + +الأوامر التالية read-only وتُستخدم للتحقق ما لم يمنعها التوجيه: + +```text +git status +git diff +git log +git show +git branch --show-current +git rev-parse +git merge-base +``` + +## 6.2 Review Staging الافتراضي + +Review Staging هو إضافة ملفات المهمة الصريحة فقط إلى الـ staging بعد اكتمال التنفيذ والاختبارات، حتى تصبح الـ patch النهائية كاملة وقابلة للمراجعة، بما فيها محتوى الملفات الجديدة التي لا يظهر محتواها في `git diff` قبل إضافتها. + +Review Staging مسموح افتراضيًا ما لم يمنعه التوجيه صراحة، ويشترط: + +- أن يكون الـ index خاليًا من staged changes قبل بدء المهمة. +- أن تكون ملفات المهمة محددة بالمسار. +- مراجعة `git status --short` والـ unstaged diff قبل الإضافة. +- استخدام مسارات صريحة فقط مع `git add --`. +- عدم استخدام `git add .` أو `git add -A` أو مسارات واسعة. +- عدم إدخال أي ملف خارج النطاق. +- بقاء التغييرات local وstaged وuncommitted ما لم توجد صلاحية Commit منفصلة. + +عدم ذكر Staging في التوجيه يعني تطبيق Review Staging الافتراضي، ولا يعني السماح بالـ Commit. + +## 6.3 الصلاحيات المستقلة + +يجب أن يحدد كل توجيه حالة العمليات التالية: + +- إنشاء branch أو تبديله. +- Commit. +- Push. +- فتح PR. +- Merge. + +كل صلاحية مستقلة: + +- Review Staging لا يعني Commit. +- Commit لا يعني Push. +- Push لا يعني فتح PR. +- فتح PR لا يعني Merge. +- Merge إلى `main` يظل قرار مالك المشروع. +- يجوز للمساعد القائد **GitHub Squash Merge عبر Component PR إلى Phase Draft عند وجود Draft منفصلة** بعد اعتماد Scope الـPhase أو الـBatch، وفق Standing Execution Authority وGates وقواعد Git. + +ولرفع الالتباس الاصطلاحي، يقصد بـ`Merge` في هذا السياق ثلاث عمليات مختلفة: + +- **Component Merge:** GitHub Squash Merge لـComponent PR إلى Phase Draft عند وجود Draft منفصلة، وهو داخل Standing Execution Authority بعد اعتماد Scope واجتياز المراجعة وComponent Gate. لا يلزم هذا الحد عندما تنفذ Work Units المترابطة على Work Branch واحدة. +- **Local `git merge`:** عملية Git محلية لتغيير تاريخ Branch أو مزامنتها، وتظل خاضعة للقسم §6.4 ولا يمنحها Standing Execution Authority تلقائيًا. +- **Phase-to-main / Batch-to-main Merge:** GitHub Squash Merge للـPhase Draft أو Batch Integration Boundary إلى `main`، ويظل قرارًا مستقلًا لمالك المشروع. + +### التنفيذ حتى النهاية (Delivery Completion) +- تحديد العملية بأنها `YES` أو التصريح بها صراحة هو **تصريح تنفيذي كامل** لهذه العملية. +- بعد اجتياز بوابات التحقق، ينفذ المنفذ العمليات المصرح بها بالتتابع حتى آخر خطوة مسموحة. +- مثال: إذا كان Commit وPush وفتح PR مصرحًا بها، ينفذ الثلاثة دون طلب تأكيد إضافي بين كل خطوة. +- ممنوع التوقف للسؤال: + - هل أنفذ Commit؟ + - هل أعمل Push؟ + - هل أفتح أو أنشر PR؟ + - هل أسلّم التغييرات؟ +- يتوقف المنفذ فقط عند: + - blocker فعلي مثبت. + - معلومة إلزامية غير متوفرة ولا يمكن استنتاجها بأمان. + - تعارض مع مصدر أعلى. + - فشل بوابة قبول مطلوبة. +- العملية المحددة بـ `NO` أو غير المصرح بها لا تُنفذ. +- Merge إلى `main` يظل قرارًا مستقلًا لمالك المشروع ولا يُنفذ دون تصريح مباشر خاص بالدمج. +- Component Merge إلى Phase Draft لا يحتاج تأكيدًا جديدًا عند شمول العملية في Standing Execution Authority المعتمدة للـPhase أو الـBatch، ولا يتجاوز ذلك صلاحية الدمج إلى `main`. + +## 6.4 العمليات التي تحتاج تصريحًا صريحًا + +ممنوع تنفيذ أي من العمليات التالية دون تصريح مباشر للعملية المحددة: + +```text +git fetch +git pull +git switch +git checkout +git restore +git restore --staged +git stash +git reset +git reset --hard +git clean +git rebase +git merge +git cherry-pick +git revert +git branch -d +git branch -D +git push --force +git push --force-with-lease +``` + +حظر `git merge` المحلي أعلاه لا يمنع **GitHub Squash Merge عبر Component PR إلى Phase Draft عند وجود Draft منفصلة** عندما تكون العملية مشمولة بStanding Execution Authority واجتازت بوابات القبول. أما الوحدات المترابطة داخل Work Branch واحدة فلا تحتاج Component PR مستقلة. لكن Standing Execution Authority لا تمنح تلقائيًا تصريحًا عامًا لأي عملية Git محلية واردة في القائمة، مثل `git rebase` أو `git cherry-pick` أو `git reset` أو `git restore`؛ تظل كل واحدة منها محتاجة إلى الصلاحية المناسبة. وبالعكس، فإن التصريح بعملية Git محلية أو باستخدام `git merge` في تكليف محدد لا يمنح صلاحية GitHub Merge، ولا صلاحية الدمج إلى `main`. + +الأمر `git switch -c` أو `git checkout -b` مسموح فقط عندما ينص التوجيه على إنشاء branch بعد نجاح baseline verification. + +إذا كان الـ index غير نظيف عند بداية المهمة، يتوقف المنفذ بدل تغييره. + +## 6.5 منع amend وإعادة كتابة التاريخ + +`git commit --amend` **ممنوع في دورة العمل المعتمدة**. + +أي تصحيح بعد Commit يتم من خلال **Commit جديد مستقل** يوضح التعديل. لا يُعاد كتابة Commit سابقة، ولا تُستخدم force-push لإخفاء تاريخ المراجعة. + +يسري ذلك على المنفذ المحلي وJules والمساعد القائد عندما يُكلّف بالتنفيذ. + +## 6.6 بوابة Review Staging + +قبل Review Staging يجب عرض: + +```bash +git status --short +git diff --name-status +git diff --stat +git diff --check +git diff --cached --name-status +``` + +إذا ظهر أي staged change سابق، يتوقف المنفذ ولا يغيّر الـ index. + +بعد ذلك تُضاف ملفات المهمة بمسارات صريحة فقط: + +```bash +git add -- path/to/file-one path/to/file-two +``` + +بعد Review Staging يجب عرض: + +```bash +git status --short +git diff --cached --name-status +git diff --cached --stat +git diff --cached --check +git diff --cached +git diff --name-status +git diff --stat +``` + +الـ `git diff --cached` هو مرجع الـ patch الكاملة للمراجعة بعد staging. وجود unstaged changes بعده يجب تفسيره، ولا يجوز إخفاؤه. + +إذا كان Commit مسموحًا، تُراجع نفس بوابة الـ staged scope مباشرة قبل تنفيذه. إذا لم يكن Commit مسموحًا، تظل الملفات local وstaged وuncommitted للمراجعة. + +## 6.7 منع التكدس وإدارة جولات التصحيح + +يجب الالتزام بالقواعد التالية لضمان استمرار أو تبديل الـ session بشكل صحيح: + +**يستمر العمل في نفس Jules session/chat ونفس branch والـ PR عندما:** +* يكون المطلوب تصحيحًا أو استكمالًا داخل نفس المهمة والنطاق. +* تظل Jules مالكة للـ branch وقادرة على الكتابة عليها. +* تكون branch ancestry والـ PR base صحيحتين. +* تظل الـ PR واضحة وقابلة للمراجعة. +* يتم طلب التصحيح عبر top-level PR conversation comment أو Reply عادي داخل نفس PR بمنشن صريح `@jules`. +* كل تصحيح بعد Commit يتم في Commit جديدة، بدون amend أو force-push. + +**تبدأ Jules Session جديدة عندما:** +* تكون المهمة الجديدة نطاقًا مستقلًا عن المهمة الحالية. +* تتغير المهمة أو acceptance criteria إلى عمل مستقل. +* تفقد الـ session الاستيعاب أو تكرر أخطاء سبق حسمها. +* تصبح الـ PR متكدسة أو غير موثوقة للمراجعة. +* تكون ancestry مبنية من source branch خاطئة. +* تكون الـ PR أو branch السابقة مرفوضة أو superseded ولا يجوز استخدامها كـ base أو مصدر تنفيذ. + +**قاعدة التوقف الإلزامي:** +إذا لم تستطع Jules فتح أو الوصول إلى أو التحقق من الـ canonical branch أو الـ intended parent PR، تتوقف فورًا. + +ممنوع في هذه الحالة: +* الاستمرار من checkout أخرى. +* الرجوع تلقائيًا إلى `main`. +* محاكاة الحالة من branch مختلفة. +* تشغيل الاختبارات أو إنشاء PR اعتمادًا على مصدر غير متحقق منه. + +هذا المسار لا يمنح صلاحيات Git ضمنية. إنشاء branch وCommit وPush وفتح PR و`cherry-pick` أو أي نقل للتغييرات يظل خاضعًا للقسمين `6.3` و`6.4`. + +### إعداد Jules Session والنشر + +اختيار مصدر Jules يحدث **قبل إرسال الـ Prompt**: + +- من الواجهة: اختيار Repository ثم Starting branch. +- من الـ API: تحديد `sourceContext.githubRepoContext.startingBranch`. + +الـ Prompt يذكر expected branch والـ exact source SHA للتحقق والتوقف فقط؛ ولا يستطيع تغيير Starting branch أو إصلاح ancestry بعد بدء الـ Session. + +أي صلاحية عامة مصرح بها لعمليات `git switch` أو `git checkout` (كالمذكورة في §6.3 و §6.4) لا تمنح Jules الصلاحية لتغيير Source Context أو Starting Branch الخاصة بالـ Session. +إذا كان العمل يتطلب Starting Branch مختلفة، يُمنع معالجة ذلك داخل نفس الـ Session عبر أوامر Git؛ بل يجب إيقاف الـ Session وبدء واحدة جديدة من المصدر الصحيح. (هذا لا يغير قواعد المنفذ المحلي). + +عند بدء Jules Session متتابعة: + +1. تُثبت latest remote HEAD للـ source branch. +2. تُختار Repository وStarting branch الصحيحتان قبل إرسال الـ Prompt. +3. يتحقق الـ Prompt من branch والـ exact SHA، ويتوقف عند أي اختلاف دون fallback إلى `main`. +4. تنفذ Jules النطاق المعزول فقط ثم تعمل Commit وPush وفق الصلاحيات. +5. إذا كانت base المطلوبة غير `main`، تستخدم Jules **Publish Branch فقط** ولا تستخدم Publish PR. +6. إذا كانت base المقصودة `main`، يمكن استخدام Publish PR فقط عند وجود تصريح صريح. + +> **ملاحظة تشغيلية (Maatify Workflow Policy):** تقييد `Publish PR` بالـ `main` base وإلزام Jules باستخدام `Publish Branch` للفروع الأخرى هو **سياسة سير عمل خاصة بـ Maatify** لحماية الـ branch ancestry والـ Phase Stack، وليس قيدًا تقنيًا ثابتًا في منتج Jules. المساعد القائد هو من يتولى إنشاء أو تصحيح topology الـ PR من GitHub بعد التحقق من الفروع المنشورة. + +### بوابة القدرة الفعلية + +بعد النشر يجب التحقق من GitHub الفعلي أن: + +- remote branch مبنية من exact source HEAD. +- `merge-base` هي source HEAD المطلوبة. +- changed files والـ diff تعرضان النطاق المقصود فقط. +- base الـ PR صحيحة إن وُجدت. +- طريقة النشر تطابق base المطلوبة. + +إذا كانت ancestry خاطئة، يُرفض الناتج ولا يُصلح بتغيير base. أما إذا كانت ancestry صحيحة والخطأ في base الـ PR فقط، فيمكن تغيير base أو إغلاق PR وفتح بديلة من **نفس head branch**. لا تُحذف branch قبل إنشاء البديلة والتحقق منها. + +### استعادة baseline بعد تعثر session + +**عند تعثر استمرار نفس الـ branch/session (فقدان السياق أو كسر القواعد) أثناء العمل على مكوّن (Component) غير مكتمل:** + +- **لا يُدمج** الجزء السليم من الـ Component غير المكتمل إلى الـ Phase Draft بأي شكل. +- **لا يُنشأ** Component جديد لاستكمال بقية الـ acceptance؛ يظل الـ Component الحالي يعتبر فاشلًا وغير مكتمل. +- تُغلق أو تُستبدل الـ PR أو الـ branch الفاشلة حسب القواعد. +- تبدأ محاولة بديلة وجديدة لنفس الـ Component بأكمله انطلاقًا من أحدث Phase Draft HEAD المعتمد (الـ baseline المعتمدة السابقة). +- لا يدخل إلى Phase Draft إلا Component مكتمل بالكامل وفق dependency graph وGates المعتمدة. + +## 6.8 تسمية Work Branch + +- تصف تسمية الفرع نطاق العمل أو الـPhase أو Work Unit أو الـfeature/fix، وتتبع naming convention الخاصة بالمشروع أو بيئة التنفيذ. +- لا يفرض المساعد القائد prefix عامًا مرتبطًا بأداة أو منفذ بعينه، مثل `codex/` أو `jules/` أو اسم vendor/agent. +- يجوز للمشروع أو بيئة التنفيذ فرض convention محلية، لكن لا تتحول إلى قاعدة عامة مرتبطة بهوية المنفذ. +- لا يعاد تسمية الفروع الموجودة بأثر رجعي لمجرد تطبيق هذه القاعدة. +- هذه القاعدة تخص تسمية الفرع فقط؛ لا تغيّر أدوار المنفذ المحلي أو Jules أو ملكية Jules لفرع مهمته كما تحددها الأقسام ذات الصلة. + +--- + +# 7. دورة العمل القياسية + +## المرحلة 1 — إعادة بناء الحالة الحالية + +يجمع المساعد القائد: + +- latest base SHA. +- حالة PRs ذات الصلة. +- المصادر authoritative الحالية. +- gaps المفتوحة والمغلقة. +- الملفات المتوقع تداخلها. + +## المرحلة 2 — اختيار المهمة التالية + +يتم الاختيار وفق: + +1. الأولوية. +2. التبعيات. +3. المخاطر. +4. عدم التداخل. +5. قابلية المراجعة والـ rollback. + +## المرحلة 3 — تحديد المنفذ + +- يحدد التوجيه الفعلي للمشروع أو المرحلة أو المهمة أو قرار مالك المشروع المنفذ لكل مكوّن، ولا يفترض نوع المنفذ من نوع العمل وحده. +- يتحقق المساعد القائد من ملاءمة المنفذ وحدود التكليف قبل إرساله، ولا يمنحه ذلك صلاحية تقرير السياسة أو المعمارية. +- المساعد القائد لا ينفذ داخل المستودع إلا بتكليف صريح، وتبقى مسؤوليته الهندسية والمراجعة المباشرة قائمة سواء نفذ غيره أو نفذ هو بتكليف. + +## المرحلة 4 — بناء التوجيه وتجهيز مسار التنفيذ + +يُكتب Prompt بالحد الأدنى الكافي. وفي مهام Jules يُطبق إعداد الـ Session خارج الـ Prompt وفق القسم `6.7`. + +## المرحلة 5 — التنفيذ + +المنفذ يعمل داخل الحدود فقط. + +## المرحلة 6 — التحقق وReview Staging + +تُشغّل الأوامر المطلوبة فعليًا. بعد نجاح التحقق، تُضاف ملفات المهمة الصريحة فقط إلى الـ staging وفق بوابة Review Staging، ما لم يمنع التوجيه ذلك صراحة. + +## المرحلة 7 — مراجعة المساعد القائد + +لا يُعتمد تقرير المنفذ أو ادعاء نجاحه وحده. يراجع المساعد القائد بنفسه الكود أو التوثيق، والـ diff أو الـ staged patch، والـ checks، والـ PR والمراجع المعتمدة ذات الصلة قبل قبول الناتج، ويرفضه أو يطلب تعديله عند وجود مخالفة. + +أي Final Review أو Independent Review إضافي يضيف طبقة تحقق مستقلة ولا يحل محل هذه المراجعة المباشرة. + +## المرحلة 8 — Commit وPush وPR + +تحدث وفق صلاحيات Git المحددة في التوجيه، أو وفق Standing Execution Authority المعتمدة للـPhase أو الـExecution Batch بالنسبة لوحدات العمل و**GitHub Squash Merge عبر Component PR إلى Phase Draft عند وجود Draft منفصلة**، وكل تصحيح بعد Commit يُضاف في Commit جديد. **GitHub Squash Merge للـPhase Draft أو Batch Integration Boundary إلى `main`** يظل قرار مالك المشروع. نشر Jules واختيار Publish Branch أو Publish PR يخضعان للقسم `6.7`. + +## المرحلة 9 — مراجعة PR وmetadata handoff + +تشمل scope وdiff وbase freshness والـ checks والـ threads. بعد مهمة Jules الناجحة، يتولى المساعد القائد تثبيت العنوان والوصف النهائيين للـ PR من الحالة الفعلية. + +تستمر التصحيحات الطبيعية داخل نفس PR. في مهام Jules تُرسل الملاحظات على نفس المهمة عبر top-level PR conversation comment أو Reply عادي داخل نفس PR بمنشن صريح `@jules` وفق القسم `11.1`. عند التكدس أو فقدان الاستيعاب يُطبق مسار الاستعادة في القسم `6.7`. + +بعد إنشاء أي PR تُراجع `base` و`head` و`merge-base` و`changed files`. يُصلح خطأ الـ base من نفس head branch فقط عندما تكون ancestry صحيحة؛ أما branch المبنية من مصدر خاطئ فتُستبدل بbranch جديدة من المصدر الصحيح. + +## المرحلة 10 — قرار الدمج + +مالك المشروع هو صاحب القرار النهائي. + +## المرحلة 11 — follow-up + +تُعالج الملاحظات داخل Work Unit أو Work Branch المفتوحة إن كانت تخص Acceptance الخاصة بها، أو تُجمع في Consolidated Required-Fix Component/Batch عند الحاجة إلى تغيير مستقل. تُراجع وتُدمج إلى Phase Draft أو Batch Integration Boundary وفق dependency graph وGates، ولا يجوز أبدًا استخدامها لتمرير حد التكامل إلى `main` قبل اكتمال جميع متطلبات الـPhases الداخلة فيه. + +--- + +# 8. بناء Prompt بالحد الأدنى الكافي + +## 8.1 النواة الإلزامية لكل مهمة + +كل Prompt تنفيذي يحتاج فقط إلى: + +1. **المراجع:** `AGENTS.md` والمسارات authoritative اللازمة للمهمة. +2. **Baseline:** branch وexact SHA وحالة working tree والـ index. +3. **الهدف:** نتيجة واحدة واضحة. +4. **النطاق:** الملفات أو الحدود المملوكة، وخارج النطاق الضروري فقط. +5. **Acceptance:** السلوك والاختبارات أو التحقق المطلوب. +6. **Git:** الصلاحيات المستقلة. +7. **التسليم:** الأدلة التي يجب عرضها أو سبب التوقف. + +## 8.2 الوحدات الاختيارية + +تضاف فقط عند الحاجة: + +- migration forward/rollback/reapply. +- concurrency وlocks وCAS. +- public API compatibility. +- provider outcome mapping. +- schema invariants. +- PR title/body/commit message. +- توثيق lifecycle/audit/roadmap. + +إذا لم تكن الوحدة جزءًا من المهمة، لا تظهر في الـ Prompt. + +## 8.3 ما لا يوضع داخل الـ Prompt + +- شرح كامل للنظام موجود أصلًا في مستند مرجعي. +- تكرار قواعد هذا المعيار. +- نتائج قديمة لا تستخدم كـ baseline. +- قائمة طويلة من ملفات ممنوعة لا يمكن أن تتأثر أصلًا. +- حالات اختبار غير مرتبطة بالسلوك المتغير. +- تعليمات تقرير تكرر acceptance criteria حرفيًا. + +## 8.4 التناسب مع حجم المهمة + +- تعديل سطر توثيقي: Prompt قصيرة جدًا. +- تعديل Service محدود: Prompt متوسطة. +- تغيير مالي أو أمني متعدد الحالات: Prompt أطول بقدر العقود والمخاطر الفعلية فقط. + +لا يوجد حد كلمات ثابت؛ المعيار هو **نسبة المعلومات المؤثرة إلى الحجم**. + +--- + +# 9. قالب المنفذ المحلي المختصر + +> استخدم النواة التالية، وأضف وحدة اختيارية فقط عند الحاجة. + +````markdown +أنت تعمل داخل الـ local checkout للمشروع `{{REPOSITORY}}`. + +اقرأ: +- `AGENTS.md` +- `{{TASK_REFERENCES}}` + +## Baseline + +```bash +git branch --show-current +git rev-parse HEAD +git status --short +git diff --cached --name-status +``` + +المطلوب: `{{BASE_BRANCH}}` عند `{{BASE_SHA}}`، working tree وindex بالحالة `{{EXPECTED_STATE}}`. +إذا اختلفت الحالة، توقف واعرضها دون محاولة إصلاح. + +## المهمة + +`{{EXACT_GOAL}}` + +النطاق: +- `{{OWNED_PATHS}}` + +خارج النطاق: +- `{{ONLY_RELEVANT_OUT_OF_SCOPE}}` + +Acceptance: +- `{{REQUIRED_BEHAVIOR}}` +- `{{REQUIRED_TESTS_OR_CHECKS}}` + +## Git + +- Branch: `{{BRANCH_PERMISSION}}` +- Review Staging: `YES` للمسارات الصريحة فقط. +- Commit: `{{YES_OR_NO}}` +- Push: `{{YES_OR_NO}}` +- PR: `{{YES_OR_NO}}` +- Amend / force-push / Merge: `NO` + +نفّذ جميع العمليات المحددة بـ YES حتى آخر خطوة مصرح بها، بعد نجاح بواباتها. +لا تطلب تأكيدًا إضافيًا لتنفيذ Commit أو Push أو فتح PR إذا كانت مصرحًا بها صراحة. + +بعد التحقق: + +```bash +git add -- {{EXPLICIT_TASK_FILES}} +git diff --cached --name-status +git diff --cached --stat +git diff --cached --check +``` + +اعرض: starting SHA، changed files، ملخص التنفيذ، نتائج الاختبارات والتحليل، staged diff checks، وحالة Git الفعلية. +```` + +### وحدات المنفذ المحلي الاختيارية + +أضف نصًا قصيرًا فقط عندما تحتاج المهمة إلى واحد من الآتي: + +- **Concurrency:** الـ lock/CAS/uniqueness invariant المطلوب واختباره. +- **Migration:** forward/rollback/reapply والأدلة المطلوبة. +- **Provider outcomes:** مصدر التصنيف والـ exhaustive routing. +- **Public contract:** ما يجب ألا يتغير. +- **Docs:** الملفات التي تتغير والحالة التي يجب تسجيلها. + +--- + +# 10. قالب Jules المختصر + +> **إعداد خارج الـ Prompt:** قبل إرسال القالب، اختر `{{REPOSITORY}}` و`{{STARTING_BRANCH}}` من Jules UI، أو عيّن `sourceContext.githubRepoContext.startingBranch` في الـ API. + +````markdown +أنت تعمل على `{{REPOSITORY}}`، ويجب أن تكون الـ Session قد بدأت من `{{STARTING_BRANCH}}` عند exact source SHA `{{BASE_SHA}}`. + +اقرأ: +- `AGENTS.md` +- `{{TASK_REFERENCES}}` + +قبل التعديل تحقق من branch والـ exact source SHA. إذا لم تتطابق، توقف دون fallback إلى `main` ودون محاولة إصلاح ancestry. + +أنشئ branch جديدة تخص هذه المهمة فقط (Jules task branch): +`{{JULES_TASK_BRANCH}}` + +لا تكتب على branch أو PR branch أنشأها منفذ آخر. + +## المهمة + +`{{EXACT_GOAL}}` + +المسموح تعديله: +- `{{ALLOWED_FILES}}` + +ممنوع: +- `{{ONLY_RELEVANT_FORBIDDEN_SCOPE}}` + +الدقة المطلوبة: +- كل claim من الكود أو schema أو مصدر authoritative حالي. +- `{{TASK_SPECIFIC_EVIDENCE_RULE}}` + +## Git والنشر + +- Commit: `{{YES_OR_NO}}` +- Push: `{{YES_OR_NO}}` +- Publish Branch: `{{YES_OR_NO}}` +- Publish PR: `{{YES_OR_NO}}` +- PR Base: `{{PR_BASE}}` +- Amend / force-push / Merge: `NO` +- أي تصحيح بعد Commit يكون Commit جديدًا. + +- إذا كانت العملية `YES` تُنفذ بعد نجاح بواباتها دون طلب تأكيد جديد. +- كسياسة خاصة بـ Maatify: `Publish PR: YES` لا يُستخدم إلا عندما تكون `PR Base` هي `main`. +- عندما تكون `PR Base` غير `main` يجب أن يكون `Publish PR: NO`، ويُستخدم `Publish Branch: YES` عند التصريح. + +اعرض: Starting branch، starting SHA، branch المنشورة، commits، remote HEAD، remote merge-base، changed files، `git diff --check`، وطريقة النشر، وPR URL إن وجدت. +```` + +### وحدات Jules الاختيارية + +أضف فقط ما يلزم للمهمة: + +- الفرق بين behavior وgap وdecision وinactive capability. +- نص التصحيح المطلوب حرفيًا عند التصحيح المحدد. +- commit message وPR title عند السماح بـ Publish PR. +- أوامر tests/analysis إذا كانت المهمة الصغيرة تشمل كودًا. + +--- + +# 11. ملكية Jules وحدود Git + +## 11.1 ملكية Branch (Jules Task Branch) وتصحيحات PR + +Jules يكتب فقط على branch **خاصة بمهمته الحالية (Jules task branch)**. +هذا المصطلح تنظيمي يعني أن الـ branch أُنشئت بواسطة الـ task أو الـ session الحالية لـ Jules، وليس ادعاءً بملكية تقنية على مستوى GitHub. + +- لا يُطلب منه تعديل branch أنشأها المنفذ المحلي أو المساعد القائد أو Jules task/session أخرى. +- إذا كان التصحيح داخل نفس مهمة Jules ونفس PR والـ branch الخاصة بها، يُرسل عبر **top-level PR conversation comment أو Reply عادي داخل نفس PR بمنشن صريح `@jules`**. +- كل تصحيح ينتج Commit جديدة؛ amend وforce-push ممنوعان. +- لا يستخدم `@jules` لنقل PR إلى منفذ جديد أو لتعديل branch لا تخص نفس المهمة. +- عند استخدام Jules لمتابعة PR feedback، يجب استخدام `Reactive Mode` بحيث لا تتحول المناقشات أو التعليقات العادية إلى أوامر تنفيذية غير مقصودة. +- **PR feedback does not expand task scope:** أي تعليق أو استخدام لـ `@jules` يسمح فقط بتصحيح أو استكمال نفس المهمة (acceptance criteria الحالية)، ولا يمنح نطاقًا أو قرارًا معماريًا جديدًا. +- عند تغير النطاق، أو بدء Session جديدة، أو فقدان الاستيعاب، يُستخدم المسار المتتابع في القسم `6.7`. + +هذه الآلية خاصة بمهام Jules، ولا تغيّر مسار المنفذ المحلي أو صلاحيات المساعد القائد. + +## 11.2 Commits والنشر + +يمكن السماح لـ Jules بإنشاء branch وCommit وPush أو Publish PR، لكن كل صلاحية مستقلة. إعداد Starting branch وطريقة النشر يتبعان القسم `6.7`، وMerge يظل ممنوعًا على Jules. + +## 11.3 PR metadata handoff + +عندما تُفتح PR إلى `main`، تكتب Jules عنوانًا ووصفًا أوليين. وعندما تكون base غير `main`، تنشر branch فقط ويفتح المساعد القائد PR الصحيحة بعد التحقق. + +بعد النشر: + +- يعرض Jules branch والـ commits والـ remote HEAD وأي PR URL. +- يجلب المساعد القائد الحالة البعيدة الفعلية ويراجع PR بالكامل. +- يثبت المساعد القائد العنوان والوصف النهائيين عند نجاح المهمة. + +المرجع هو GitHub الفعلي وقت المراجعة، لا SHA أو metadata قديمة في تقرير المنفذ. + +## 11.4 التعديلات التلقائية للمستودع (Autonomous Repository Mutations) + +أي أتمتة لـ Jules يمكنها إنشاء أو تعديل Branch أو Commit أو PR تلقائيًا خارج التوجيه المباشر (مثل CI auto-fixing أو scheduled tasks) تكون **غير مستخدمة افتراضيًا** في المشاريع الخاضعة لهذا المعيار. +لا يُسمح بتفعيلها إلا بقرار صريح من مالك المشروع، ويجب ألا تتجاوز في عملها: +- النطاق المحدد للمهمة (task scope). +- قواعد ملكية الـ Branch. +- dependency graph وExecution Waves لنظام Phase Stack. +- سلطة الدمج (merge authority) الخاصة بالمالك. + +## 11.5 سياق وذاكرة Jules (Jules Memory) + +أي ذاكرة (Memory) أو سياق سابق قد يحتفظ به Jules ليس مصدرًا معتمدًا (authoritative). +لا يجوز الاعتماد عليه لتجاوز أو كبديل عن: +1. تعليمات مالك المشروع الحالية. +2. التوجيهات في ملف `AGENTS.md`. +3. المعايير والقرارات المعتمدة الحالية للمشروع. +4. الحالة الفعلية الحالية للمستودع. +5. توجيه المهمة (Prompt) الحالي. + +--- + +# 12. التقرير النهائي + +## 12.1 قاعدة التقرير + +التقرير لا يعيد كتابة الـ Prompt. يعرض الأدلة والنتيجة فقط. + +## 12.2 تقرير المنفذ المحلي + +```markdown +## الحالة +- Starting SHA / Branch / Index before work + +## التنفيذ +- النتيجة والعقود المحفوظة + +## الملفات +- Exact staged changed-file list + +## التحقق +- Focused/full tests بالأعداد +- Static analysis +- `git diff --cached --check` + +## Git +- Staged / Commit / Push / PR / Merge +- ما ظل خارج النطاق +``` + +## 12.3 تقرير Jules + +```markdown +## المرجع +- Repository وStarting branch +- Audited source SHA +- Jules task branch (الـ branch الخاصة بالمهمة الحالية) + +## التعديل +- الملفات والنتيجة المبنية على الأدلة + +## التحقق +- `git diff --check` +- Changed files +- Remote merge-base + +## Git والنشر +- Commits بالترتيب +- Remote HEAD +- Publish Branch أو Publish PR +- PR URL إن وجدت +- Metadata handoff المطلوبة +``` + +--- + +# 13. بوابات القبول + +## 13.1 مسؤولية القبول والمراجعة المباشرة + +- تقرير المنفذ دليل يُراجع، وليس قرار قبول. +- لا يصبح أي ناتج مقبولًا لمجرد وجود تقرير نجاح أو اجتياز بعض الـ checks. +- يجب على المساعد القائد مراجعة الكود أو التوثيق، والـ diff أو الـ staged patch، والـ checks، والـ PR والمراجع authoritative ذات الصلة بنفسه قبل إعلان الجاهزية أو التوصية بالقبول. +- إذا خالف الناتج الواقع أو العقود أو النطاق أو الأدلة، يرفضه المساعد القائد أو يطلب تعديله، ولو كانت نتيجة المنفذ أو تقريره تدعي النجاح. +- أي Final Review أو Independent Review إضافي هو طبقة تحقق إضافية، ولا يلغي مسؤولية المساعد القائد عن المراجعة المباشرة والقبول المشروط بالأدلة. + +### 13.1.1 Fresh Full Acceptance Review بعد remediation + +بعد أي remediation تغيّر حالة سبق رفضها أو طلب تعديلها، وقبل دمجها إلى أي Integration Boundary، يجب على المساعد القائد تنفيذ `Fresh Full Acceptance Review` للحالة النهائية المتراكمة. يجوز التحقق أولًا من أن blocker أو finding المحددة أُصلحت، لكن: + +```text +Fix verification != final acceptance review +``` + +تراجع المراجعة مقابل أحدث base وHEAD، وتشمل accumulated diff كاملًا، والـarchitecture والـcontracts والـscope، وclaims التوثيق، والاختبارات والأدلة، والـCI/checks، وحالة release عند انطباقها، وكل remediation سابقة وأي تعارضات جديدة. لا تقتصر على آخر Commit أو patch أو ملف أو finding. إذا تحركت Integration Draft أو `main` أثناء العمل، يعاد تقييم أثر التغييرات على الفرع والمراجعة؛ تتم المزامنة عند وجود أثر مادي، أو يثبت reviewer عدم التأثر وفق Phase Stack. + +يجب أن يوضح evidence الحكم النهائي على الأقل: base ref وSHA، وHEAD ref وSHA، وأن الحالة المتراكمة كاملة روجعت، والـremediations التي أُخذت في الحسبان، والـchecks المتأثرة التي أُعيد تشغيلها، وحالة Full Applicable Integration Gate عند boundary المناسبة، والحكم النهائي. لا يفرض ذلك نموذج تقرير واحدًا أو ملفًا دائمًا جديدًا. بعد micro-fix يعاد تشغيل الـchecks المتأثرة حسب المخاطر؛ أما Full Applicable Integration Gate فتكون عند boundary ذات معنى وفق `GITHUB_PHASE_STACK_WORKFLOW_AR.md` و`CI_WORKFLOW_STANDARD.md`، ولا تعني المراجعة الكاملة إعادة مصفوفة CI المكلفة بعد كل تعديل صغير. + +## 13.2 تنفيذ الكود + +لا يعتبر التنفيذ جاهزًا للمراجعة إلا إذا تحقق حسب نطاق المهمة: + +- السلوك المطلوب موجود. +- حالات الفشل والحواف المرتبطة بالتغيير مغطاة. +- الاختبارات المطلوبة ناجحة. +- static analysis ناجح. +- `git diff --check` نظيف قبل staging. +- Review Staging تحتوي ملفات المهمة فقط. +- `git diff --cached --check` نظيف. +- staged patch كاملة ومفهومة. +- لا توجد public contracts مكسورة دون تصريح. + +## 13.3 التوثيق + +- كل claim مطابق للحالة الحالية. +- لا يوجد تناقض مع مصدر authoritative. +- التعديل محصور في الملفات المسموحة. +- `git diff --check` نظيف. +- لا يوجد Runtime داخل Documentation-only PR. +- الـ branch هي Jules task branch (خاصة بالمهمة الحالية) إن كان Jules هو المنفذ. +- Starting branch وطريقة النشر متوافقتان مع القسم `6.7`. +- لا amend أو force-push. +- وصف PR النهائي يُثبته المساعد القائد بعد نجاح المراجعة. + +## 13.4 Pull Request + +قبل التوصية بالدمج يجب التأكد من: + +1. PR state وdraft status مقصودان. +2. base وHEAD وmerge-base وbehind/ahead معلومة. +3. تبعية الـ branch للمهمة (Jules task branch) والـ changed files والـ diff داخل النطاق. +4. checks والـ review threads وتاريخ commits مفهومة. +5. وصف PR النهائي مبني على remote state. +6. في مهام Jules، إعداد Starting branch وطريقة النشر مطابقان للقسم `6.7`. +7. أي استخدام لـ `@jules` يخص نفس المهمة ونفس PR والـ branch وفق القسم `11.1`. +8. عند خطأ base، فُصل بين خطأ metadata وخطأ ancestry، ولم تُحذف branch قبل التحقق من البديل. +9. القرار النهائي معروض على مالك المشروع. + +--- + +# 14. Follow-ups والأنماط المرفوضة + +## 14.1 Follow-up مناسبة + +إذا ظهرت ملاحظات أثناء مراجعة Phase أو Execution Batch تقتضي Follow-up، تُعالج داخل Work Unit أو Work Branch المفتوحة أو تُجمع في Consolidated Required-Fix Component/Batch عند الحاجة إلى تغيير مستقل، وتُدمج إلى حد التكامل وفق dependency graph عندما تكون: + +- صغيرة. +- غير مانعة لصحة الـ Draft. +- خارج الـ acceptance criteria الأساسية للـ Components السابقة (لا تُستخدم كعذر لتمرير Component غير مكتمل). +- لا تسبب تداخلًا مؤثرًا مع Work Unit أخرى أو Gate لاحقة. + +يجب أن يكتمل التغيير، يُراجع، وتجتاز Work Unit أو Consolidated Required-Fix Component/Batch الـGates المطلوبة قبل دمجه إلى حد التكامل. لا تستخدم Follow-up لتجاوز شرط اكتمال الـPhase أو الـBatch قبل الدمج إلى `main`، ولا لإخفاء test failure أو Runtime bug أو contract مكسور. + +## 14.2 أنماط مرفوضة + +- Prompt مفتوحة مثل: «راجع النظام وحسنه». +- Prompt طويلة تعيد نسخ المستندات المرجعية. +- تكرار القاعدة نفسها في عدة أقسام. +- إضافة أقسام لا تخص المهمة. +- دمج gaps غير مترابطة. +- فرض Strict Sequential Stack عالميًا رغم غياب dependency أو overlap مؤثر. +- الوثوق في التقرير دون patch. +- قبول ناتج لم يراجعه المساعد القائد مباشرة لمجرد وجود تقرير نجاح أو Final/Independent Review. +- ملء معلومة غير مثبتة بالتخمين بدل تصنيفها كغير محسومة. +- تقرير المنفذ للسياسة أو المعمارية من نفسه. +- تعديل ملفات مشتركة في مهام متوازية. +- `git add .` أو `git add -A`. +- amend أو force-push. +- كتابة Jules على branch لا تخص مهمته الحالية. +- اعتبار وصف Jules الأولي نهائيًا. +- الاعتماد على الـ Prompt لتغيير Jules Starting branch بعد بدء Session. +- استخدام Publish PR من Jules عندما تكون base المطلوبة غير `main`. +- استخدام `@jules` خارج نفس مهمة Jules ونفس PR والـ branch. +- فتح session أو branch أو PR جديدة لكل رسالة أو تصحيح بسيط دون وجود تكدس فعلي. +- الاستمرار في تكديس جولات ونطاقات جديدة داخل PR أصبحت صعبة المراجعة بدل عزل الجولة التالية. +- قبول branch متتابعة ذات ancestry مبنية فعليًا من `main` رغم الادعاء بأنها مبنية من source branch. +- دمج PR متتابعة ما زالت تستهدف base خاطئة بدل تصحيحها بعد إثبات سلامة ancestry. +- اعتبار تغيير base أو فتح PR جديدة من نفس head branch علاجًا لbranch ذات ancestry خاطئة. +- حذف head branch قبل إنشاء PR البديلة والتحقق من base والـ diff. +- الاستمرار في session فقدت الاستيعاب الصحيح وأصبحت جولات التصحيح فيها تصلح آثار الجولات السابقة. +- دمج حالة فاشلة أو غير متماسكة لمجرد إنشاء baseline جديدة. +- قيام المساعد القائد بدور المنفذ دون تكليف. + +--- + +# 15. اعتماد المعيار في أي مشروع + +آلية اختيار وتوزيع وتثبيت المعايير مملوكة حصريًا لـ [STANDARDS_ADOPTION_STANDARD_AR.md](../STANDARDS_ADOPTION_STANDARD_AR.md). لا يعيد هذا المعيار نسخ قواعد Adoption العامة، بل يوضح فقط علاقة AI Collaboration بعقد الاعتماد. + +عند استخدام نظام Selective Adoption، توجد `STANDARDS_ADOPTION_STANDARD_AR.md` دائمًا ضمن **Pinned Adoption Control Set** المحلية، وتوجد معها Profile manifests المفعلة وكل Profile manifests الموروثة اللازمة لحل inheritance. هذه الملفات ليست اختيارية ولا تُضاف إلى `Required Standards` الخاصة بأي Profile. + +عند تفعيل Profile `repository-governance` على Scope معين، تدخل AI Collaboration وPhase Stack في **Pinned Applicable Standards Set** لذلك الـ Scope؛ ولا يعني ذلك أن Package أو Module standards تصبح منطبقة تلقائيًا. يظل `STANDARDS_MANIFEST.md` هو **Local Resolver Record** الذي يصف النتيجة. + +يطبق الوكيل إجراءات Normal Engineering Task أو Adoption / Upgrade / Manifest Validation كما يحددها [STANDARDS_ADOPTION_STANDARD_AR.md](../STANDARDS_ADOPTION_STANDARD_AR.md)، ويقرأ Applicable Standards فقط. لا يغير هذا العقد منع floating `main` أو اعتماد same exact upstream commit الافتراضي. + +--- + +# 16. حوكمة التعديل والإصدار + +## 16.1 Standard Versioning + +تخضع هوية هذا المعيار وStandard Version وتصنيف أثر تغييره حصريًا لـ[STANDARD_VERSIONING_POLICY_AR.md](../governance/STANDARD_VERSIONING_POLICY_AR.md). يطبق أي تعديل تصنيف `Change Nature` و`Compatibility Impact` وقاعدة الانتقال المحددة في السياسة المركزية. + +## 16.2 متطلبات تعديل المعيار + +أي تعديل يجب أن: + +- يحصل على موافقة صريحة من مالك المشروع. +- يمر عبر branch وPR قابلين للمراجعة ما لم يقرر المالك غير ذلك. +- يوضح سبب التغيير وأثره. +- يثبت أو يحدّث Standard Version وفق تصنيف الأثر ومسار Version Finalization المحددين في [STANDARD_VERSIONING_POLICY_AR.md](../governance/STANDARD_VERSIONING_POLICY_AR.md). +- يراجع `AGENTS.md` للتأكد من عدم وجود تكرار أو تعارض. + +--- + +# 17. سجل تغييرات المعيار + +## `5.3.0` + +- تثبيت `Fresh Full Acceptance Review` بعد remediation للحالة المتراكمة، مع إثبات base/HEAD والأدلة والحكم النهائي، وفصلها عن فحص إصلاح finding وعن توقيت Full Integration Gate. +- اعتماد تسمية فروع محايدة عن المنفذ، وفق وصف النطاق أو الـPhase أو Work Unit أو feature/fix واتفاق المشروع أو البيئة؛ دون تغيير أدوار Local Executor أو Jules. + +## `5.2.0` + +- مواءمة صلاحيات التنفيذ مع `Execution Batch` وإضافة قاعدة `Phase ≠ Branch ≠ PR`. +- تفضيل إعادة استخدام السياق والمنفذ على فتح sessions أو Branches أو PRs متعددة لمجرد parallelism. +- حصر Branches وPRs في الحدود التي تضيف عزلًا أو reviewability أو rollback أو safe integration، مع إبقاء Merge إلى `main` للمالك. + +## `5.1.0` + +- استبدال عقد `Central Canonical + Pinned Local Copy` العام في قسم الاعتماد بإحالة إلى `STANDARDS_ADOPTION_STANDARD_AR.md`. +- مواءمة اعتماد AI Collaboration مع Profile `repository-governance` وScope-aware Profile Resolution و`STANDARDS_MANIFEST.md`. +- تثبيت أن هذا التغيير لا يغير Roles أو Merge Authority أو Git Model أو إصدار Phase Stack. + +## `5.0.0` + +- مواءمة صلاحيات ودورة عمل المساعد القائد مع Dependency-Aware Phase Train وExecution Waves بدل Strict Sequential Stack. +- تثبيت Standing Execution Authority داخل الـPhase بعد اعتماد Scope، بما يشمل إدارة Work Units وGates وSquash Merge إلى Phase Draft، مع إبقاء `main` وTag وRelease وPublish ضمن سلطة المالك. +- مواءمة قواعد التوثيق وFollow-up وRequired Fixes مع Vertical Work Units وConsolidated Required Fixes وGates غير المنشئة لـPR عند عدم وجود تغيير مستودع. +- تثبيت أن Phase Stack الإصدار `2.0.0` هو المرجع الحالي لدورة حياة Phase Draft والـWaves والدمج. + +## `4.0.0` + +- تثبيت المساعد القائد كـ Technical Lead / Architect / Reviewer صاحب مسؤولية هندسية مباشرة عن إعادة بناء الحالة، واكتشاف الـ gaps والتعارضات، وتصميم الحل، وكتابة التوجيه، ومراجعة الناتج وقبوله أو رفضه. +- إضافة قاعدة صريحة تمنع التخمين والافتراض، وتلزم بفحص ما يمكن إثباته وتصنيف ما لا يملك دليلًا كافيًا كغير محسوم. +- فصل القرارات التقنية الطبيعية داخل العقود المعتمدة عن القرارات المعمارية أو التغييرات الجوهرية التي يعرضها المساعد القائد على مالك المشروع لاعتمادها. +- إزالة التعيين العام الثابت بين نوع المهمة ومنفذ بعينه، وربط اختيار المنفذ بتعليمات المشروع أو المرحلة أو المهمة أو قرار المالك. +- توضيح أن Final/Independent Review طبقة تحقق إضافية ولا تلغي المراجعة المباشرة للمساعد القائد، وأن تقرير النجاح لا يكفي لقبول الناتج. + +## `3.1.0` + +- توضيح حدود Git لـ Jules لمنع تغيير الـ Starting Branch داخل نفس الـ Session. +- ضبط مصطلح `Jules task branch` ليعكس التبعية التنظيمية للمهمة الحالية وليس ملكية تقنية. +- تصنيف قاعدة Publish PR كسياسة سير عمل (Maatify Workflow Policy) لحماية الـ Phase Stack. +- إضافة قواعد جديدة لاستخدام `Reactive Mode` ومحدودية النطاق عند التعامل مع ملاحظات PR. +- حظر التعديلات التلقائية للمستودع (Autonomous Repository Mutations) بشكل افتراضي، وعدم اعتماد Memory كمرجع authoritative. + +## `3.0.0` + +- تغيير نموذج Git الأساسي بالكامل لاعتماد نظام الـ Phase Stack الموثق في [`GITHUB_PHASE_STACK_WORKFLOW_AR.md`](../GITHUB_PHASE_STACK_WORKFLOW_AR.md) كمرجع إلزامي وحيد لدورة حياة الـ Branches والـ PRs والـ Merges. +- مواءمة قواعد الـ Follow-up والاستعادة (Recovery) لتنصبّ في الـ Phase Draft بشكل تسلسلي صارم وتمنع دمج أي جزء من مكوّن غير مكتمل أو تجاوز شروط اكتمال المرحلة (Phase Completeness). +- تعديل قواعد التثبيت المحلي (Pinned Local Copy) لتشمل إرفاق ملف الـ Phase Stack مع استقلال الـ metadata للحفاظ على سلامة الروابط. + +## `2.1.0` + +- اعتماد إكمال جميع خطوات التسليم (Commit, Push, Publish PR) المصرح بها دون إعادة طلب التأكيد. + +## `2.0.0` + +- تعميم دور المنفذ المحلي (Local Executor) بدل حصره في Codex. +- تحديث قواعد استمرار الـ session وبدء session جديدة لـ Jules لضمان التوافق وتجنب التكدس. + +## `1.4.0` + +- اعتماد نموذج `Central Canonical + Pinned Local Copy` لآلية نقل وتحديث المعيار في المشاريع، واشتراط ترقيته عبر PR مستقلة. + +## `1.3.0` + +- فصل إعداد Jules Session عن نص الـ Prompt. +- اعتماد Publish Branch للـ base غير `main`، وPublish PR فقط عندما تكون `main` هي الهدف المقصود. +- اعتماد top-level PR conversation comment أو Reply عادي داخل نفس PR بمنشن صريح `@jules` لتصحيحات نفس مهمة Jules ونفس PR والـ branch. +- إبقاء مسارات المنفذ المحلي والمساعد القائد دون تغيير. + +## `1.2.0` + +- اعتماد استمرار نفس session والـ branch والـ PR للتصحيحات الطبيعية داخل نفس النطاق. +- منع فتح sessions وPRs جديدة لمجرد كل رسالة أو ملاحظة مراجعة صغيرة. +- تعريف سيناريو التكدس الفعلي الذي يبرر بدء session وbranch متتابعة من أحدث remote HEAD للـ PR المفتوحة. +- تثبيت أن مسار الاستعادة لا يمنح صلاحيات Git ضمنية، وأن source branch والـ base والعمليات المسموحة تُحدد صراحة في التوجيه. +- إضافة بوابة remote verification للـ ancestry والـ merge-base والـ PR base بدل الاعتماد على تقرير محلي. +- توثيق توقف Jules عند فساد ancestry دون الرجوع إلى `main`، وإعادة استخدام branch نفسها عندما تكون ancestry صحيحة والخطأ في PR base فقط. +- إضافة بوابة تفرق بين خطأ PR base القابل للإصلاح من نفس head branch وخطأ ancestry الذي يتطلب branch جديدة من المصدر الصحيح. +- منع حذف head branch قبل إنشاء PR البديلة والتحقق منها. +- اعتماد إنهاء session عند فقدان الاستيعاب، ودمج آخر جزء سليم فقط عند اجتيازه بوابات القبول قبل بدء session جديدة للمتبقي. + +## `1.1.0` + +- اعتماد Review Staging الافتراضي للمسارات الصريحة. +- إبقاء Commit وPush وPR وMerge صلاحيات مستقلة. +- منع `git commit --amend` واعتماد Commit جديد لكل تصحيح. +- تثبيت اقتصار Jules على branch الخاصة بمهمتها فقط. +- تثبيت handoff PR metadata من Jules إلى المساعد القائد بعد نجاح المراجعة. +- اعتماد قاعدة Minimum Sufficient Prompt وتقليل القوالب إلى نواة إلزامية ووحدات اختيارية. + +## `1.0.0` + +- الإصدار الأول للأدوار ودورة التنفيذ وقوالب المنفذ المحلي وJules وبوابات المراجعة. + +--- + +# 18. الخلاصة التنفيذية + +- **مالك المشروع:** يقرر الهدف والأولوية والنطاق والسياسات والدمج. +- **المساعد القائد:** يعيد بناء الحالة الفعلية، يكتشف الـ gaps والتعارضات، يصمم الحل داخل العقود، يكتب Prompt بالحد الأدنى الكافي، ويراجع الكود أو التوثيق والـ diff والـ PR بنفسه قبل قبول أي ناتج. +- **Phase ≠ Branch ≠ PR:** الـRoadmap Phase حد قبول منطقي، والـExecution Batch حد تسليم، والـWork Branch/PR حدود Git لا تنشأ إلا عندما تضيف عزلًا أو مراجعة أو rollback أو تكاملًا آمنًا؛ يجوز أن تضم Batch واحدة عدة Phases مترابطة. +- **Phase Execution:** تُدار عبر dependency graph وExecution Batches وExecution Waves؛ يفضل إعادة استخدام السياق، ولا يستخدم التوازي إلا عندما يكون صافي الزمن أقل بعد احتساب كلفته، ولا يدخل `main` إلا حد تكامل يغطي الـPhases الداخلة في الـBatch بعد اجتياز Phase Integration Gate. +- **Standing Execution Authority:** بعد اعتماد Scope الـPhase أو الـBatch، يدير المساعد القائد الوحدات والـGates وBranch/PR boundaries اللازمة فقط، مع بقاء الدمج إلى `main` للمالك. +- **المنفذ المكلّف:** ينفذ النطاق المحدد ويعرض الأدلة، ولا يقرر السياسة أو المعمارية من نفسه؛ يحدد المشروع أو المرحلة أو المهمة أو مالك المشروع من ينفذ كل نوع من العمل. +- **Jules عند تكليفه:** يبدأ من Repository وStarting branch محددتين قبل الـ Prompt، وينفذ على branch خاصة بمهمته الحالية (Jules task branch). +- **نشر Jules:** Publish Branch للـ base غير `main`؛ Publish PR فقط عند استهداف `main`. +- **تصحيح Jules:** عبر top-level PR conversation comment أو Reply عادي داخل نفس PR بمنشن صريح `@jules` لنفس المهمة ونفس PR والـ branch فقط. +- **Review Staging:** مسموح افتراضيًا للمسارات الصريحة، مع بقاء التغييرات local وstaged وuncommitted. +- **Amend:** ممنوع؛ كل تصحيح Commit جديد. +- **جولات التصحيح:** تستمر داخل نفس PR ما دامت واضحة وداخل النطاق؛ session وbranch متتابعة تستخدم فقط عند ظهور تكدس فعلي وبتصاريح Git صريحة. +- **التحقق البعيد:** ancestry وmerge-base وPR base تُثبت من GitHub الفعلي، لا من تقرير محلي فقط. +- **تصحيح base:** إذا كانت ancestry صحيحة يمكن إصلاح أو استبدال الـ PR من نفس head branch؛ إذا كانت ancestry خاطئة تلزم branch جديدة من المصدر الصحيح. +- **تعثر session:** يُمنع دمج أي جزء سليم من مكوّن غير مكتمل، بل تُلغى محاولة المكوّن وتبدأ محاولة جديدة له من أحدث Draft HEAD. +- **العربية:** لغة التواصل والتوجيه والتقارير ووصف الـ PR افتراضيًا. +- **Prompt:** أقصر صياغة تكفي للتنفيذ والتحقق، دون نسخ أو تكرار أو معلومات لا تؤثر في المهمة. +- **الأدلة:** مطلوبة قبل قبول أي ادعاء، ولا تخمين في القرارات؛ ما لا يملك دليلًا كافيًا يبقى غير محسوم. +- **المراجعة:** تقرير النجاح لا يكفي، وأي Final/Independent Review إضافي لا يلغي مسؤولية المساعد القائد عن مراجعته المباشرة. +- **التبعيات وعدم التداخل:** يسبقان الترتيب الرقمي. +- **هذا الملف:** المصدر الواحد للحقيقة للقواعد العامة للعملية والتنسيق، بينما `GITHUB_PHASE_STACK_WORKFLOW_AR.md` هو المصدر لدورة حياة Git. +- **قرار الدمج:** يظل دائمًا لمالك المشروع. diff --git a/docs/standards/CI_WORKFLOW_STANDARD.md b/docs/php-engineering-standards/standards/packages/CI_WORKFLOW_STANDARD.md similarity index 60% rename from docs/standards/CI_WORKFLOW_STANDARD.md rename to docs/php-engineering-standards/standards/packages/CI_WORKFLOW_STANDARD.md index ad0df3b..a9fbb0e 100644 --- a/docs/standards/CI_WORKFLOW_STANDARD.md +++ b/docs/php-engineering-standards/standards/packages/CI_WORKFLOW_STANDARD.md @@ -1,5 +1,11 @@ # CI Workflow Standard +## Standard Metadata + +- **Standard ID:** `std-ci-workflow` +- **Standard Version:** `1.1.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` + This document outlines the standard CI workflow architecture for any standalone Composer package in the Maatify ecosystem. It ensures a consistent, high-quality testing and static analysis baseline across all packages without coupling to any specific project. ## 1. Normative Language @@ -12,6 +18,33 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S ## 2. Canonical CI Architecture +This standard governs CI execution and enforcement. The testing architecture and regression protection requirements are exclusively governed by the [Testing Standard](../testing/TESTING_STANDARD.md). +Repositories with required system/E2E suites MUST execute them as CI gates appropriate to that repository. CI MUST make it impossible to treat a required failing E2E/system suite as successful verification. + +### 2.1 Local Quality-Gate Parity + +For every applicable required quality gate in this Standard, the repository MUST document a local command or command sequence that runs the same verification contract. This includes Composer validation and dependency resolution, platform requirements, PHP syntax, PHPStan, code style, whitespace, applicable test suites, schema verification, Composer audit, workflow lint, and the Consumer Verification Harness. + +Every CI gate MUST invoke a repository-owned command or script, or a documented command sequence, that a developer can run locally to prove the same verification contract. Runner-specific service provisioning, environment setup, dependency matrices, and job orchestration MAY differ, but MUST NOT change what the gate verifies. Workflow YAML MAY coordinate those concerns; it MUST NOT be the only place where a maintainer can discover or understand the verification logic. A repository MUST document the prerequisites and service setup needed to run each applicable gate locally. + +Local parity means that the gate is runnable locally with equivalent verification semantics; it does not require a developer workstation to reproduce the GitHub runner. This Standard does not require one universal command or Composer script name. The repository MUST use its actual maintained commands and document the mapping from local invocation to CI invocation. GitHub CI remains the final evidence for the integrated runner environment. + +### 2.2 Consumer Verification Harness Gate + +The [Testing Standard](../testing/TESTING_STANDARD.md) owns Consumer Verification Harness applicability and evidence semantics. This Standard owns only its CI execution and enforcement. + +When the Harness is required for an artifact, CI MUST execute the Harness defined by the Testing Standard as a required applicable gate using the repository-owned local invocation documented under §2.1. CI orchestration MUST preserve the clean-state and repeatability requirements in the Testing Standard, and the executed Harness MUST prove production autoload. For a Base Module, the Harness MUST consume the Module Artifact Root's Composer contract as the dependency; the Host root MUST NOT substitute for the Artifact Root, as defined by the [Composer Package Standard](COMPOSER_PACKAGE_STANDARD.md). + +The Harness gate MUST fail closed. Missing or incomplete setup, unavailable required dependencies or services, and an unexpected skip MUST fail verification when the Harness is relevant. The gate MUST NOT be hidden behind `continue-on-error`, `|| true`, or a silent skip. Applicable real-service requirements continue to follow Section 11, and baseline CI MUST NOT require production secrets. + +Repositories using change-relevance detection for an applicable Harness MUST configure it from that Harness's actual implementation. Changes to the consumer project, fixture, template, script, or other files that affect its verification MUST make the Harness relevant. This Standard does not define a universal Harness path list. + +### 2.3 Affected Checks and Full Integration Gate + +After a small remediation or micro-fix, CI MAY run the affected checks selected by risk instead of repeating an expensive full matrix, provided all checks directly related to the changed contract still run. Risk-based selection MUST NOT remove evidence for the behavior, compatibility, or integration boundary changed by the fix. + +At a meaningful integration boundary, CI MUST run the full applicable verification set for the integrated change. Boundaries include closing a substantial Work Unit or Phase, moving an Integration Draft to its next stage when its changed contract is affected, final acceptance for the integration boundary, and changes that expand compatibility or integration behavior. The full set includes all applicable required quality, dependency, PHP-version, test, real-service, package, and workflow checks defined by this Standard. + Repositories MAY organize their workflows into multiple files (e.g., separating `quality`/`static analysis`, `tests`, `integration`, and `dependency compatibility`). However, workflows MUST have: * stable workflow names @@ -24,6 +57,7 @@ The standard does not mandate one exact number of workflow files. ## 3. Required-Check-Safe Path Scoping A workflow or job used directly as a branch-protection required check **MUST always report a conclusion** for every protected pull request. +As a **Maatify Operational Policy** supported by GitHub's context evaluation constraints, repositories MUST rely on a stable aggregate gate rather than requiring individual matrix child jobs. A directly required workflow MUST NOT disappear because of top-level path filtering. ### Allowed Models @@ -53,14 +87,14 @@ Examples of relevant paths: * `composer.json` * `composer.lock` * `phpstan.neon` -* `phpunit.xml` or `phpunit.xml.dist` +* Actual test-runner configuration files used by the repository (for example, `phpunit.xml` or `phpunit.xml.dist` when PHPUnit is used) * `.php-cs-fixer.php` * `.github/workflows/.yml` Rules: * Include `composer.lock` ONLY when the repository tracks it. * Never require a reusable library to add `composer.lock` solely for CI path filtering. -* Include the actual PHPUnit configuration filename used by the repository. +* Include the actual test-runner configuration files used by the repository when they affect test execution. * Include package-owned schema and SQL fixture paths used by Integration tests. * Include the workflow itself and all quality-tool configuration files that affect it. * Documentation changes SHOULD trigger heavy checks only when the workflow validates documentation code blocks, generated files, or examples. @@ -110,7 +144,7 @@ On the minimum supported PHP version, CI MUST run an appropriate resolution such composer update --prefer-lowest --prefer-stable --no-interaction --prefer-dist --no-progress ``` Then run the relevant static and test checks. -The lowest-dependency job MUST NOT silently pass through `continue-on-error`, `allow-failure`, or `|| true`. If a package cannot support its declared lower bounds, the dependency constraint MUST be corrected. +Note that `composer update --prefer-lowest --prefer-stable` tests the lowest resolved bounds but does not guarantee compatibility with every version within the range. The lowest-dependency job MUST NOT silently pass through `continue-on-error`, `allow-failure`, or `|| true`. If a package cannot support its declared lower bounds, the dependency constraint MUST be corrected. ## 7. PHP Version Compatibility @@ -147,17 +181,19 @@ The standard MUST require, where applicable: * MUST NOT use `ignoreErrors`. * MUST NOT use inline suppressions merely to make CI pass. * **Code style**: When a supported formatter configuration (e.g., `.php-cs-fixer.php`) exists, CI MUST run a non-mutating check (e.g., `vendor/bin/php-cs-fixer fix --dry-run --diff`). CI MUST NEVER rewrite and commit formatting automatically during a required verification job. -* **Full test suite**: Where separate Unit, Regression, and Integration suites exist, run each explicitly. CI MUST also run the complete PHPUnit suite in at least one canonical environment. +* **Whitespace verification**: CI MUST detect and fail on applicable whitespace defects such as trailing whitespace, malformed whitespace introduced in tracked text/source files, or equivalent repository-specific whitespace integrity failures. A canonical Git-aware verification such as `git diff --check` MAY be documented as an accepted/basic mechanism where appropriate, provided it works correctly for the actual comparison context. This must be treated as a real required quality check, separate from generic code-style formatting. +* **Complete maintained applicable test suite**: CI MUST run the complete maintained test suite using the repository's actual test runner and tooling. Where separate Unit, Regression, and Integration suites exist, each MUST run explicitly. A runner failure MUST fail CI deterministically; a missing required runner, configuration, dependency, or setup MUST fail closed. * **Example syntax validation** * **Composer security audit** * **Workflow syntax/lint validation** ## 9. Composer Security Audit -CI MUST perform a non-interactive security audit after successful dependency resolution, for example: +CI MUST perform a non-interactive security audit after successful dependency resolution. Note that bare `composer audit` does not guarantee failure for abandoned packages because it is influenced by the configuration (e.g., `ignore`, `report`, or `fail`) and `report` does not enforce a non-zero exit. However, as a **Maatify Internal Policy**, ignoring vulnerabilities and abandoned packages is forbidden, and CI MUST remain fail-closed. Therefore, CI MUST use an explicit enforcement command such as: ```bash -composer audit --no-interaction +composer audit --no-interaction --abandoned=fail ``` +or an equivalent explicit Composer configuration. The repository MUST define an explicit policy for: * security advisories @@ -180,7 +216,11 @@ Once a repository contains GitHub Actions workflows, CI MUST validate workflow s Packages that own persistence or external-service behavior MUST use the real supported service in Integration CI. -* SQLite substitution is FORBIDDEN for MySQL-owned behavior. +* The central standard does not enforce a unified Database engine or Database version across all projects. +* Each package or project defines its actual database contract from its authoritative sources and current schema. +* CI verification MUST use the actual engine owned by the project. +* Pinning a CI service image to an explicit version is for reproducibility, and does not make that version the central compatibility contract of the project. +* SQLite substitution is FORBIDDEN for MySQL/MariaDB-owned behavior when it cannot prove the same contract. * In-memory or mocked substitutes are FORBIDDEN when they cannot prove the real storage contract. * Service images MUST use explicit supported versions or immutable digests, never `latest`. * Services MUST have health checks or deterministic readiness checks. @@ -198,20 +238,20 @@ Packages that own persistence or external-service behavior MUST use the real sup ## 12. Workflow Security and Supply-Chain Hardening -Workflows MUST require least privilege: +As a **Maatify Internal Policy**, workflows MUST require least privilege: ```yaml permissions: contents: read ``` -unless an additional permission is explicitly required and documented; only the minimum necessary permission may be granted. +unless an additional permission is explicitly required and documented; only the minimum necessary permission may be granted. Note that this is not a GitHub default, but a strict Maatify operational security policy. `contents: read` is the normal verification baseline. Workflows may use a narrower permission set when possible. Any broader/additional permission requires explicit justification. Rules: * Baseline verification workflows MUST NOT receive write permissions. * MUST NOT use `pull_request_target` to execute untrusted pull-request code. * MUST NOT expose repository or environment secrets to untrusted fork code. -* Every externally sourced GitHub Action MUST be pinned to an immutable full commit SHA. This includes GitHub-owned actions such as actions under the `actions/*` organization. -* Every external reusable workflow MUST be pinned to an immutable full commit SHA. +* As a **Maatify Internal Policy**, every externally sourced GitHub Action MUST be pinned to an immutable full commit SHA. This includes GitHub-owned actions such as actions under the `actions/*` organization. +* As a **Maatify Internal Policy**, every external reusable workflow MUST be pinned to an immutable full commit SHA. * Human-readable comments MAY document the corresponding release/tag. * Floating branches and tags such as `main`, `master`, `latest`, `v1`, `v2`, or other mutable references MUST NOT be used in required workflows. * Local actions stored within the same repository are resolved from the checked-out repository commit and are not required to use an external SHA reference. @@ -221,8 +261,8 @@ Rules: ## 13. Execution Reliability -* Every required job MUST define an appropriate `timeout-minutes`. -* Every required workflow architecture MUST define an explicit concurrency and cancellation policy. +* As a **Maatify Internal Policy**, every required job MUST define an appropriate `timeout-minutes`. +* As a **Maatify Internal Policy**, every required workflow architecture MUST define an explicit `concurrency` and `cancel-in-progress` policy. * `concurrency` MAY be configured at workflow level or job level according to the architecture. * Job-level concurrency groups MUST be scoped so matrix siblings and independent required jobs do not cancel one another. * Pull-request superseded runs SHOULD be cancelled. @@ -266,8 +306,9 @@ The final gate MUST: * have a stable name that does not contain variable matrix values * be the check selected in branch protection -Repositories MUST NOT require individual matrix child jobs directly. -The gate MUST NOT hide `failure`, `cancelled`, `timed_out`, `action_required`, `startup_failure`, or equivalent unsuccessful states. +As a **Maatify Internal Policy**, repositories MUST NOT require individual matrix child jobs directly; a stable aggregate gate MUST be used instead to avoid matrix ambiguity. +The gate MUST inspect `needs.*.result` which returns one of `success`, `failure`, `cancelled`, or `skipped`. The `skipped` state is only acceptable when an approved relevance detector proves the job was intentionally bypassed; any unexpected `skipped` state for a relevant job MUST fail the gate. The gate MUST NOT hide `failure` or `cancelled` or equivalent unsuccessful states. +When a Consumer Verification Harness is required and relevant, its job MUST be included among the upstream requirements inspected by the stable aggregate gate. A skipped Harness job is acceptable only when the approved relevance detector proves it is not relevant. ## 17. Trigger Events @@ -283,7 +324,7 @@ Scheduled dependency-drift verification MAY be added for reusable libraries. This standard distinguishes between universal rules and repository-specific values. * **Universal rules**: PHPStan max, real Integration services, minimum/latest PHP coverage, stable required gates, Composer validation, no hidden failures, least privilege. -* **Repository-specific values**: exact PHP versions, exact service versions, actual PHPUnit configuration filename, actual suite names, schema paths, environment variable names, service ports, package-owned trigger/table names, whether `composer.lock` is tracked. +* **Repository-specific values**: exact PHP versions, exact service versions, actual test-runner configuration files, actual suite names, schema paths, environment variable names, service ports, package-owned trigger/table names, whether `composer.lock` is tracked. Repository-specific values MUST be documented by each package, but MUST NOT be hardcoded into the universal standard. @@ -300,10 +341,11 @@ Any standalone Composer package in the Maatify ecosystem MUST verify the followi * [ ] PHP syntax passes * [ ] PHPStan max passes with zero suppressions * [ ] code-style dry-run passes when configured +* [ ] explicit whitespace verification passes * [ ] Unit suite passes where applicable * [ ] Regression suite passes where applicable * [ ] Integration suite uses real services where applicable -* [ ] full PHPUnit suite passes where PHPUnit/tests are applicable +* [ ] complete maintained applicable test suite passes using the repository's actual test runner and tooling * [ ] example PHP files pass syntax validation where examples exist * [ ] minimum supported PHP is tested * [ ] latest supported PHP is tested @@ -317,3 +359,6 @@ Any standalone Composer package in the Maatify ecosystem MUST verify the followi * [ ] branch protection requires stable gates only * [ ] no continue-on-error or hidden failures exist * [ ] package-created service/database state is cleaned up where Integration tests create such state +* [ ] every applicable required gate has a documented local invocation with the same verification contract as its CI invocation +* [ ] a required Consumer Verification Harness runs as a fail-closed gate, preserves clean-state repeatability, and is included in the stable aggregate gate when relevant +* [ ] meaningful integration boundaries run the full applicable verification set, while reduced runs still include every check tied directly to a changed contract diff --git a/docs/standards/COMPOSER_PACKAGE_STANDARD.md b/docs/php-engineering-standards/standards/packages/COMPOSER_PACKAGE_STANDARD.md similarity index 79% rename from docs/standards/COMPOSER_PACKAGE_STANDARD.md rename to docs/php-engineering-standards/standards/packages/COMPOSER_PACKAGE_STANDARD.md index d7d66aa..1610471 100644 --- a/docs/standards/COMPOSER_PACKAGE_STANDARD.md +++ b/docs/php-engineering-standards/standards/packages/COMPOSER_PACKAGE_STANDARD.md @@ -1,6 +1,12 @@ # Maatify Composer Package Standard -**Maatify Standalone PHP Composer Library Standard — v1** +**Maatify Standalone PHP Composer Library Standard** + +## Standard Metadata + +- **Standard ID:** `std-composer-package` +- **Standard Version:** `2.0.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` This document defines the canonical `composer.json` contract for standalone, reusable PHP libraries in the Maatify ecosystem. @@ -66,6 +72,8 @@ It does **not** govern: - `CI_WORKFLOW_STANDARD.md` governs how Composer contracts are verified through strict validation, dependency resolution, platform checks, audit, and quality gates. - `LIBRARY_PRESENTATION_STANDARD.md` governs public presentation and consistency between Composer metadata, README, Packagist, and GitHub. +The definition and evidence for a package/version being Published are owned by [`LIBRARY_PRESENTATION_STANDARD.md` Section 14](LIBRARY_PRESENTATION_STANDARD.md#14-first-stable-release-lifecycle-and-security-presentation-states). This Standard consumes that publication state when applying package identity rules and MUST NOT establish a conflicting publication source or definition. + No Standard SHOULD duplicate the detailed rules owned by another Standard. Cross-references MUST be used instead. --- @@ -88,6 +96,8 @@ It does not automatically apply to: Those package types require a separate profile or Standard. +For an extractable Base Module, this Standard applies to the Module's Artifact Root even while it is located inside a Host repository. The Artifact Root MUST contain its own `composer.json`; a Host root `composer.json` MAY provide in-project autoloading but MUST NOT replace the Artifact Root's Composer contract. + ### 3.1 Root-Package Context Some Composer fields are root-only, including `require-dev`, `autoload-dev`, `repositories`, `config`, `scripts`, `minimum-stability`, and `prefer-stable`. @@ -98,6 +108,8 @@ Rules for those fields govern the library repository while it is being developed ## 4. Core Composer Contract Principles +*Note: Composer technically allows other forms for many of these configurations, but Maatify adopts a stricter Profile to ensure consistency and reliability across the ecosystem.* + 1. `composer.json` is a public package contract, not an internal installation note. 2. Every directly used runtime dependency MUST be declared directly. 3. A package MUST NOT rely on a transitive dependency as though it were direct. @@ -107,8 +119,8 @@ Rules for those fields govern the library repository while it is being developed 7. The PHP constraint is a public compatibility promise. 8. The production autoload mapping is part of the public runtime contract. 9. Composer scripts MUST map to real, maintained commands. -10. Published versions MUST come from VCS tags; the `version` field MUST NOT be committed. -11. Reusable Maatify libraries MUST NOT commit `composer.lock`. +10. Published versions MUST come from VCS tags; as a **Maatify Internal Policy**, the `version` field MUST NOT be committed. +11. As a **Maatify Internal Policy**, reusable Maatify libraries MUST NOT commit `composer.lock`. 12. A release-ready package MUST pass `composer validate --strict`. 13. Package metadata MUST match the repository, runtime, documentation, and CI claims. 14. Composer configuration MUST NOT hide unsupported platform assumptions. @@ -128,15 +140,15 @@ Templates in this Standard use the following placeholders: - `{PACKAGE_DESCRIPTION}`: A concise and technically accurate package description. - `{ROOT_NAMESPACE}`: The PSR-4 root namespace without the final separator. - `{TEST_NAMESPACE}`: The test namespace root without the final separator; normally `{ROOT_NAMESPACE}\Tests`. -- `{MINIMUM_PHP_VERSION}`: The minimum supported PHP minor, such as `8.2`. -- `{MINIMUM_PHP_PATCH_VERSION}`: The root development baseline, such as `8.2.0`. +- `{MINIMUM_PHP_VERSION}`: The minimum supported PHP minor, such as `8.4`. +- `{MINIMUM_PHP_PATCH_VERSION}`: The root development baseline, such as `8.4.0`. - `{LICENSE_SPDX}`: The approved SPDX license identifier. - `{PRIMARY_DOMAIN_KEYWORD}`: The main searchable domain term for the library. - `{RUNTIME_EXTENSION_NAME}`: A directly required PHP extension name without the `ext-` prefix. - `{RUNTIME_PACKAGE_NAME}`: A direct runtime package in `vendor/package` form. - `{RUNTIME_PACKAGE_CONSTRAINT}`: The approved stable constraint for a runtime package. -- `{PHPUNIT_CONSTRAINT}`: The approved PHPUnit constraint compatible with the supported PHP range. -- `{PHPSTAN_CONSTRAINT}`: The approved PHPStan constraint. +- `{PHPUNIT_CONSTRAINT}`: The latest stable PHPUnit constraint compatible with the supported PHP range, used only in PHPUnit-specific illustrative examples. +- `{PHPSTAN_CONSTRAINT}`: The latest stable PHPStan constraint. - `{CS_FIXER_CONSTRAINT}`: The approved PHP CS Fixer constraint. - `{README_FILE}`: A non-default README path when the package intentionally does not use `README.md`. - `{SECURITY_POLICY_URL}`: A stable absolute URL to the package security policy when supplied in Composer support metadata. @@ -206,9 +218,36 @@ Rules: - Spaces and uppercase characters are forbidden. - Underscores SHOULD NOT be used even though Composer may accept them. - The slug MUST reflect the library's actual responsibility. -- The Composer package slug SHOULD match `{REPOSITORY_SLUG}`. -- A mismatch requires a documented distribution reason. -- Renaming a published package is a compatibility and distribution change, not presentation polish. + +For package-identity applicability, a Pre-Stable package identity is a `Published Pre-Stable identity` when at least one exact Pre-Stable version under the same Composer package name being assessed has previously attained Published state as defined by [LIBRARY_PRESENTATION_STANDARD.md Section 14](LIBRARY_PRESENTATION_STANDARD.md#14-first-stable-release-lifecycle-and-security-presentation-states). The version currently under development, including the version represented by repository `HEAD`, does not itself need to be Published. Publication under Section 14 remains specific to the exact package identity and version; this section uses the existence of at least one such previously Published version under the same Composer package name to determine identity-level applicability. + +For every new Maatify PHP package and every Pre-Stable package identity that is not a Published Pre-Stable identity under this definition, the current naming policy below applies in full: + +Here, `{domain}` is the package's lowercase `kebab-case` domain slug under the rules above. + +- The Composer package name MUST be exactly `maatify/php-{domain}`. +- When the package has its own repository, its repository slug MUST be exactly `php-{domain}`. +- The same lowercase `kebab-case` `{domain}` slug MUST be used in both identities, so the Composer package slug MUST match the dedicated repository slug exactly. +- `php-` MUST prefix the repository slug and the package slug after `maatify/`; alternative placement, distribution exceptions, and documented deviations are not permitted. + +For a Published Pre-Stable identity, its current Composer package name and repository identity remain subject to assessment against the current naming requirements in this section, including `maatify/php-{domain}` and the matching `php-{domain}` repository slug when applicable. Publication alone MUST NOT make an identity compliant, grandfathered, or permanently exempt. Published state changes only the decision process for a proposed identity migration or rename; it MUST NOT alter the current-compliance assessment. Publication also MUST NOT create an automatic preservation entitlement for an identity that does not meet current policy. + +When a Published Pre-Stable identity does not meet current naming policy, this Standard MUST NOT trigger an automatic breaking rename solely to correct that mismatch. Before any rename affecting its Composer package name or repository identity, the required path is: + +```text +Published Pre-Stable Identity Detected +→ Downstream Impact Review +→ Owner Decision +→ Approved Action +``` + +The downstream impact review MUST identify, where applicable, whether the current identity is actually externally consumable; what a Composer package identity change and a repository identity change could affect; any consumer, distribution, or install-contract references that could break; and the evidence the Owner will use to decide whether to retain, migrate, or rename the identity. This review does not prescribe an alias, `replace` rule, deprecation timeline, migration release, redirect, or consumer-specific action. The Standard does not predetermine the Owner's decision. + +A claim that a package violated a naming requirement when it was historically created or published MUST be supported by authoritative evidence that the requirement existed, was authoritative, and applied to that artifact at that time. Without that evidence, there MUST be `NO RETROACTIVE VIOLATION CLAIM`. This does not make an identity compliant with current policy. + +When the current decision can be made from the package's current state, publication state, downstream impact, and current policy, historical archaeology is not required. If the decision actually depends on an unproven historical fact and cannot be resolved without it, the result is `OWNER DECISION REQUIRED`; historical facts MUST NOT be inferred. + +A Stable published PHP package and its repository MUST retain their existing identities unless a separate migration, compatibility, and distribution decision approves a rename. This Standard MUST NOT trigger an automatic rename of a Stable published package. ### 7.2 Package Display Name @@ -406,7 +445,7 @@ Rules: ## 12. Version Source and Release-Derived Fields -The following field MUST NOT be committed: +As a **Maatify Internal Policy**, the following field MUST NOT be committed: ```json "version": "1.0.0" @@ -495,12 +534,16 @@ The `require` field MUST contain only direct runtime contracts. The canonical minimum form is: ```json -"php": ">={MINIMUM_PHP_VERSION}" +"php": "^{MINIMUM_PHP_VERSION}" ``` Rules: -- The minimum MUST be the oldest PHP minor genuinely supported. +- For newly created Maatify PHP libraries/modules governed by the current engineering baseline, the minimum PHP version MUST NOT be lower than PHP 8.4. +- The canonical new-package Composer constraint is `^8.4` or the equivalent placeholder form resolving to PHP 8.4. +- The minimum MUST be the oldest PHP minor genuinely supported within the permitted baseline/compatibility policy; it MUST NOT allow new work to move below PHP 8.4. +- Existing already-published packages MUST retain their currently declared PHP compatibility constraint until an approved compatibility/breaking version boundary permits changing it. +- Existing packages are NOT required to convert an existing `>=...` constraint to caret syntax merely because the new-package canonical form is now `^8.4`. - The constraint is a public compatibility promise. - Every released PHP minor included by the constraint MUST be treated according to `CI_WORKFLOW_STANDARD.md`. - The minimum MUST NOT be increased merely because a developer uses a newer local PHP version. @@ -554,6 +597,8 @@ The `require-dev` field is reserved for direct development, analysis, formatting Common categories include: +The following is an illustrative dependency set for a repository that actually uses PHPUnit and installs it through Composer. It is not a universal tool list; each repository MUST declare only the tools it actually uses. + ```json "require-dev": { "friendsofphp/php-cs-fixer": "{CS_FIXER_CONSTRAINT}", @@ -564,15 +609,19 @@ Common categories include: Rules: -- Every tool executed directly by repository scripts or CI MUST be declared directly. -- The repository MUST NOT rely on a transitive installation of a tool. +- Every test runner, framework, or other tool executed directly by repository scripts or CI MUST be declared as a direct development dependency when Composer is the means by which the repository installs it. +- A tool that is not installed through Composer MUST NOT be given a fictitious Composer dependency; its provisioning, versioning, and execution MUST instead be deterministic and repository-owned under the CI contract. +- The repository MUST NOT rely on a transitive installation of a directly executed tool. - Development tools MUST NOT be placed in `require`. - Runtime dependencies MUST NOT be placed only in `require-dev`. - Tool constraints MUST remain compatible with the minimum supported PHP version when the tool runs there. - An unused tool or a tool with no maintained configuration MUST be removed. -- PHPUnit is REQUIRED when PHPUnit tests exist. -- PHPStan is REQUIRED by the Maatify package quality profile. +- A repository with testable behavior or maintained tests MUST maintain a reproducible test-execution strategy; its declared dependencies and maintained configuration MUST match the runner and tooling actually used. +- PHPUnit MAY be selected as the repository's test runner. When selected and installed through Composer, it MUST be declared directly in `require-dev` with a constraint compatible with the repository's declared PHP contract. PHPUnit is not universally required. +- PHPStan is REQUIRED by the Maatify package quality profile and MUST use the latest stable version compatible with the repository's declared PHP contract. +- `dg/bypass-finals` MAY be used as a development-only test tool when a repository has a legitimate documented need to test/mock concrete final classes and that choice is consistent with its test architecture. When used, it belongs in `require-dev`. - A code-style tool is REQUIRED when formatting is an enforced repository check. +- Tool constraints MUST NOT hardcode patch releases as permanent policy. - Tool major-version upgrades require a compatibility review. - Development packages MUST be alphabetically sorted. @@ -761,7 +810,7 @@ Canonical script names, when the corresponding capability exists, are: - `test:regression` runs the Regression suite. - `test:integration` runs the Integration suite. -Example: +Example for a repository whose actual test runner is PHPUnit; other maintained runner commands MUST be represented by the repository's actual scripts and configuration: ```json "scripts": { @@ -920,7 +969,11 @@ The canonical stable profile is: Rules: -- A release-ready library MUST use `stable` as its minimum stability. +As a **Maatify Internal Policy**, release-ready libraries MUST explicitly enforce the following two rules together: +- `minimum-stability` MUST be `stable`. +- `prefer-stable` MUST be enabled (`true`). + +Additional rules: - `dev`, `alpha`, `beta`, or `RC` minimum stability is forbidden for a stable release. - Per-package flags such as `@dev`, `@alpha`, `@beta`, or `@RC` are forbidden without a documented temporary exception. - `prefer-stable` MUST NOT be treated as permission to retain unstable requirements. @@ -933,7 +986,7 @@ Rules: For reusable libraries governed by this Standard: -> **`composer.lock` MUST NOT be committed.** +> **As a Maatify Internal Policy, `composer.lock` MUST NOT be committed.** Rules: @@ -1016,7 +1069,7 @@ This template contains no empty fields: } }, "require": { - "php": ">={MINIMUM_PHP_VERSION}" + "php": "^{MINIMUM_PHP_VERSION}" }, "config": { "optimize-autoloader": true, @@ -1032,7 +1085,7 @@ This template contains no empty fields: ### 28.2 Test-Enabled Extension -Add only when test classes and direct development tools exist: +The following is an optional example for a repository that selects PHPUnit as its actual test runner and installs it through Composer. PHPUnit is not a universal requirement; when a repository uses different tooling, its direct dependencies and script commands MUST reflect that actual tooling. ```json { @@ -1066,7 +1119,7 @@ Add only direct runtime contracts: "require": { "ext-{RUNTIME_EXTENSION_NAME}": "*", "{RUNTIME_PACKAGE_NAME}": "{RUNTIME_PACKAGE_CONSTRAINT}", - "php": ">={MINIMUM_PHP_VERSION}" + "php": "^{MINIMUM_PHP_VERSION}" } } ``` @@ -1128,7 +1181,9 @@ Automated verification of latest dependencies, lowest dependencies, platform req - [ ] Package name uses the `maatify` vendor. - [ ] Package name is lowercase and uses `kebab-case`. -- [ ] Package slug matches the repository slug or the difference is documented. +- [ ] A new package, or a Pre-Stable package identity for which no exact Pre-Stable version under that same Composer package name has ever attained Published state, uses Composer name `maatify/php-{domain}` and, when it has its own repository, repository slug `php-{domain}`; no documented deviation is permitted. Version publication is determined by Library Presentation Standard §14. +- [ ] A Published Pre-Stable identity is assessed against current naming policy, is not compliant or preserved solely because it was published, and is not renamed before downstream impact review and an Owner Decision. +- [ ] A Stable published package and its repository retain their existing identities unless a separate migration, compatibility, and distribution decision approves a rename. - [ ] Description accurately states the current package purpose. - [ ] Keywords are focused, relevant, lowercase, and non-duplicated. - [ ] `php` and `maatify` keywords are present. @@ -1139,7 +1194,7 @@ Automated verification of latest dependencies, lowest dependencies, platform req - [ ] Canonical Maatify author metadata is present. - [ ] Support URLs point to the current repository. - [ ] Security reporting is not directed to public issues. -- [ ] No `version` field is committed. +- [ ] As a Maatify Internal Policy, no `version` field is committed. ### Autoload @@ -1186,12 +1241,12 @@ Automated verification of latest dependencies, lowest dependencies, platform req ### Stability, Distribution, and Validation -- [ ] `minimum-stability` is `stable`. -- [ ] `prefer-stable` is enabled. +- [ ] As a Maatify Internal Policy, `minimum-stability` is `stable`. +- [ ] As a Maatify Internal Policy, `prefer-stable` is enabled. - [ ] No custom repository exists without approval. - [ ] No credentials, local paths, or private task URLs exist. - [ ] `vendor/` is not committed. -- [ ] `composer.lock` is not committed. +- [ ] As a Maatify Internal Policy, `composer.lock` is not committed. - [ ] Package archive rules preserve runtime source and required legal metadata. - [ ] `composer validate --strict` succeeds. - [ ] Composer metadata matches README, package reference, GitHub metadata, and CI claims. diff --git a/docs/standards/LIBRARY_PRESENTATION_STANDARD.md b/docs/php-engineering-standards/standards/packages/LIBRARY_PRESENTATION_STANDARD.md similarity index 64% rename from docs/standards/LIBRARY_PRESENTATION_STANDARD.md rename to docs/php-engineering-standards/standards/packages/LIBRARY_PRESENTATION_STANDARD.md index 442e41f..ed29d76 100644 --- a/docs/standards/LIBRARY_PRESENTATION_STANDARD.md +++ b/docs/php-engineering-standards/standards/packages/LIBRARY_PRESENTATION_STANDARD.md @@ -1,5 +1,11 @@ # Maatify PHP Library Repository Presentation Standard +## Standard Metadata + +- **Standard ID:** `std-library-presentation` +- **Standard Version:** `1.0.1` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` + ## 1. Normative Language The key words "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. @@ -18,7 +24,7 @@ This Standard is responsible for governing: * Release-facing documentation state. * Author and ecosystem identity. * GitHub description, topics and PR metadata. -* Final Release Candidate presentation review. +* SemVer Release Candidate presentation and first Stable release readiness. It explicitly does **not** govern: * Runtime architecture. @@ -31,9 +37,11 @@ It explicitly does **not** govern: ### Relationship to other standards: * `PACKAGE_BUILDING_STANDARD.md`: Governs library building, code architecture, and the package contract. -* `COMPOSER_PACKAGE_STANDARD.md`: Governs Composer metadata, dependencies, autoloading, scripts, configuration, stability, and lock-file policy. +* `COMPOSER_PACKAGE_STANDARD.md`: Governs Composer metadata, dependencies and Composer stability constraints, autoloading, scripts, configuration, and lock-file policy. * `CI_WORKFLOW_STANDARD.md`: Governs CI, quality gates, and automated testing. +This Standard owns the release-facing lifecycle and first Stable readiness. Composer stability constraints govern dependency resolution; they do not define release eligibility or publication state. + Each Standard has clear boundaries and must not duplicate the content of another. ## 3. Applicability @@ -78,7 +86,7 @@ The examples in this Standard use canonical placeholders. When applying these te * How to install or access it. 3. The presentation MUST NOT claim features, support, or a quality status that is not proven. 4. The shared identity MUST NOT erase the functional differences between libraries. -5. A Release Candidate MUST be visually and documentarily ready before creating a Tag. +5. A SemVer Release Candidate MUST be presented against its actual pre-release version before its tag and distribution are published. 6. Copying the README or governance files from another library without replacing all names and links is strictly forbidden. 7. The GitHub-rendered appearance is the ultimate reference, not just the raw Markdown source. 8. Presentation changes MUST NOT alter runtime contracts. @@ -134,12 +142,14 @@ By default, the README header MUST contain: Badges MUST be divided into logical groups. ### 8.1 Package Status -For a Final Release Candidate of a Composer library published or intended to be published on Packagist, the following MUST be prepared: +For a Composer library published or intended for Packagist that is preparing publication of a SemVer pre-release, preparing its first Stable release, or has at least one published Stable version, the following badge markup MUST be prepared: * Latest Version. * PHP Version. * License. * PHPStan Level Max (as long as it is actually proven in the project). +During first Stable Release Preparation, badge markup is prepared internally. A live `Latest Version` badge MUST NOT be displayed until a Stable version has actually been published. A published pre-release MAY be shown only as an explicitly labeled pre-release according to Section 8.4. + ### 8.2 Documentation Clear badges or links MUST be prepared for: * Changelog. @@ -154,18 +164,13 @@ Where applicable, the following MUST be prepared: * Maatify Ecosystem. * Install. -### 8.4 Release Candidate Rule -> Final Release Candidate MUST include the complete release-facing badge set before Tag creation when the package is intended to be published immediately after owner approval. +### 8.4 SemVer Pre-release Badge Rule +When Packagist is the selected package registry, badge markup for an intended SemVer pre-release or Stable release MAY be prepared before its tag is created when publication is planned immediately after owner approval. Preparing markup does not create a release or establish that a Release Candidate exists. Live Packagist badges MUST NOT be exposed before the package is actually published and the version name is valid. This rule applies only when Packagist is the library's selected package registry or when immediate Packagist publication is part of the approved release plan. -It is forbidden to remove: -* Latest Version. -* Monthly Downloads. -* Total Downloads. - -simply because the first Tag has not been created yet, provided the task is preparing the Final Release Candidate for direct publication after approval. -However, it is forbidden to write an incorrect text claim that a version is already published before it happens. +However, before the package actually exists on Packagist, Packagist Version, PHP, License, and Downloads badges MUST NOT be displayed live, because Shields will render them as `not found` (even though the endpoint returns HTTP 200). +Before the first Stable Tag, a version badge MUST NOT be labeled `Latest Version` if no Stable release exists. The default Packagist version badge cannot be relied upon to display pre-releases without configuration. Using the `include_prereleases` parameter is optional and only permitted when there is an explicit decision to display a pre-release clearly labeled as such, not as Stable. ### 8.5 Badge Style This standard does not force `style=for-the-badge` on the README. @@ -188,6 +193,8 @@ Every Badge MUST: ## 9. Canonical Composer / Packagist Badge Templates +*Note: The following live templates MUST ONLY be exposed when the conditions described in Section 8.4 are met.* + ### Package Status ```markdown [![Latest Version](https://img.shields.io/packagist/v/{COMPOSER_PACKAGE_NAME}.svg)](https://packagist.org/packages/{COMPOSER_PACKAGE_NAME}) @@ -328,15 +335,43 @@ They are NOT automatically added to: * `LICENSE` Unless a subsequent decision alters this Standard. -## 14. SECURITY Presentation States +## 14. First Stable Release Lifecycle and SECURITY Presentation States + +**Publication State Definition:** For this Standard and cross-Standard use, a package/version is Published only when that exact package identity and exact version are externally resolvable and installable by an external consumer through an actual recognized Composer distribution source. Packagist MAY be such a source, but it is not the only possible source. A branch, commit, tag, GitHub Release, Draft PR, successful CI run, local path repository, documentation claim, or Git tag without evidence of external Composer resolution and installation does not by itself establish Published state. This definition clarifies publication state and does not replace or weaken the release lifecycle, exact tagged RC installation, Consumer Verification Harness, two independent Real Host validations, release evidence, or owner release authorization below. + +### 14.1 First Stable Release Gate + +This gate applies only to a package that has never published a Stable release. Its required sequence is: + +```text +Development +→ SemVer RC +→ Consumer Verification Harness +→ Real Host Validation in 2+ independent projects/Hosts +→ Stable +``` + +A SemVer Release Candidate (RC) MUST be an actual SemVer pre-release of the intended Stable version, such as the tag `v1.0.0-rc.1`. It MUST be published and resolvable by an external consumer through the package's approved distribution channel. For a Composer library, consumers MUST be able to resolve and install that exact tagged version through its actual Composer distribution source. A branch, Draft PR, successful CI run, documentation state, local path repository, or unpublished tag MUST NOT be treated as a SemVer RC. -There are three defined states for the Security Policy: +For this first-Stable sequence, the Consumer Verification Harness MUST verify the exact published RC after it becomes externally consumable. The Harness's test semantics remain owned by the [Testing Standard](../testing/TESTING_STANDARD.md). Real Host Validation MUST then use that same RC in at least two independent real projects/Hosts. Reusing one Harness twice or testing multiple environments of one Host does not satisfy the two-Host requirement. Release readiness MUST retain verifiable evidence that identifies the RC version and each Host validation. -### 14.1 Development State -When no approved version and no Final Release Candidate exist, the file MAY state that there is currently no supported release line. +CI success and Consumer Verification Harness success alone MUST NOT authorize the first Stable release. Until the published RC, Harness, and both independent Host validations have passed, the package MUST remain Pre-Stable. The two-Host requirement applies only before the first Stable release; it is not retroactive for packages that already have a published Stable release and MUST NOT be repeated as a condition for later patch, minor, or Stable releases. -### 14.2 Final Release Candidate State -When the library is prepared for direct release upon owner approval, the Security Policy MUST be prepared for the target release format: +Tagging, releasing, publishing, and owner approval remain governed by the applicable release controls. This Standard does not authorize those actions. + +### 14.2 Development State +When neither a SemVer RC nor a Stable release has been published, `SECURITY.md` MAY state that there is currently no supported Stable release line. When a SemVer RC has been published, Section 14.3 applies; an RC does not become a Stable release or a supported Stable line. + +### 14.3 Published SemVer RC State +A SemVer RC exists only after its actual pre-release version and tag are published and available to external consumers through the approved distribution channel. `SECURITY.md` MUST describe that version as a pre-release and MUST NOT present the target Stable version as already published. A SemVer RC does not establish a new supported Stable line; existing published Stable support lines remain governed by the actual support policy. + +### 14.4 Stable Release Preparation State +After the SemVer RC, Consumer Verification Harness, and Real Host Validation steps in Section 14.1 have passed, release-facing files MAY be prepared internally for the target Stable version and date while awaiting owner approval and publication. This state MUST be called Stable Release Preparation or release preparation; it MUST NOT be called a Release Candidate. Until the Stable tag is published and the version is available through the approved distribution channel, the files and their PR metadata MUST NOT claim that the Stable version exists, is published, or is already supported. The target Stable support wording MUST be synchronized with the actual policy before publication. + +### 14.5 Published Stable State +After the Stable tag is published and the version is available to consumers through the approved distribution channel, the Security Policy enters the Published Stable State. It MUST be prepared for the actual supported release lines. + +For one supported major line, a `SECURITY.md` section MAY use: ```markdown ## Supported Versions @@ -346,7 +381,8 @@ The actively supported release line is `{SUPPORTED_MAJOR_LINE}`. Security fixes are provided in the latest stable release within the supported `{SUPPORTED_MAJOR_LINE}` line. Users should upgrade to the latest available `{SUPPORTED_MAJOR_LINE}` version before reporting a vulnerability. ``` -A table MAY be used: +A table MAY be used when it accurately represents the published support policy: + ```markdown | Version | Supported | |---------|-----------| @@ -354,16 +390,7 @@ A table MAY be used: | Older lines | No | ``` -The Final Release Candidate presentation sets up the final state before the Tag, provided that: -* There is a clear release intent. -* Approval of the polish immediately precedes the release. -* If the version or date changes before publication, the files MUST be updated before the Tag. - -### 14.3 Published Stable State - -After the first stable Tag is published, the Security Policy enters the Published Stable State. - -In this state, `SECURITY.md` MUST: +In the Published Stable State, `SECURITY.md` MUST: - describe only release lines that are currently supported by published stable releases - identify every supported major line when more than one major line is actively supported @@ -371,25 +398,34 @@ In this state, `SECURITY.md` MUST: - remove any wording that describes the package as unreleased, pre-release, or awaiting publication - remain synchronized with the actual support policy whenever a supported line is added, replaced, or retired -The Supported Versions wording from Section 14.2 MAY remain unchanged after publication when it accurately describes the published stable state. - -A future release line MUST NOT be presented as actively supported before its first stable Tag exists, except during the explicitly approved Final Release Candidate transition defined in Section 14.2. +A future release line MUST NOT be presented as actively supported before its first Stable Tag exists. SemVer RC and Stable Release Preparation states do not establish Stable support. Publishing a patch or minor release within an already supported major line does not require a Security Policy change unless the file names an exact version, changes the support scope, or otherwise becomes inaccurate. If support for a release line is withdrawn, `SECURITY.md` MUST be updated as part of the same owner-approved release or governance change that withdraws support. +### 14.6 Major Version Preservation + +This rule applies to packages that have published a Stable release; it does not extend the first-Stable release gate in Section 14.1. A Stable package MUST preserve its current Major version whenever the intended change can reasonably be delivered compatibly. + +A Major release MUST be used only for a genuine breaking public-contract change that cannot reasonably be contained through an additive API, a deprecation cycle, a compatibility adapter or shim, a migration path, or a staged replacement. + +Internal refactors, implementation cleanup, documentation or presentation changes, naming normalization by itself, and compatible additive capabilities MUST NOT justify a Major version bump. + +When a breaking public-contract change makes a Major release unavoidable, its compatibility impact and migration path MUST be explicit, reviewed decisions. The Major bump MUST NOT follow automatically from a modernization, refactor, cleanup, or naming change. + ## 15. CHANGELOG Presentation Standard The CHANGELOG MUST follow these rules: * Keep a Changelog format. * Semantic Versioning. * `[Unreleased]` MUST always be present at the top. -* The final version and its date MUST be present. +* Every published release MUST have its exact version and release date. * Release links MUST be at the bottom of the file. * Do not list features that do not exist. * Do not describe future changes as already implemented. -* A Final Release Candidate MAY carry the final version number and date before the Tag, provided publication will occur immediately after approval. +* A SemVer RC entry MUST use its exact pre-release version and matching release date/tag, such as `1.0.0-rc.1`. +* Stable Release Preparation MAY stage the target Stable version and planned date in an internal release PR after the first-Stable gates pass. Before its Stable tag is published, the entry MUST remain clearly a preparation and MUST NOT imply that the Stable release already exists. ### Template: ```markdown @@ -493,19 +529,15 @@ Topics or descriptions MUST NOT claim features that do not exist. ## 20. Pull Request Presentation Metadata -Any PR for a Final Release Candidate MUST contain: -* A Title reflecting the target release. +Any PR preparing publication of a SemVer RC or Stable Release Preparation MUST contain: +* A Title identifying the exact RC target or target Stable version and the actual release-preparation state. * A Body describing the actual changes. * A Scope confirmation. -* A Release-control statement. -* Confirmation that no Merge, Tag, or automatic Release is performed. -* No outdated wording that contradicts the branch state. +* For a first-Stable Release Preparation PR, verifiable references to the published RC, Consumer Verification Harness, and both independent Host validations. +* A release-control statement confirming that no Merge, Tag, Release, or distribution publication occurs without owner approval. +* Accurate wording that distinguishes an unpublished target version, a published SemVer RC, and a published Stable release. -The PR body MUST NOT state: -`no release exists` -`date omitted` -`pre-release state retained` -if the files inside are formatted as a final release. +PR metadata MUST NOT describe a prepared target version as already published. If a Stable Release Preparation is pending its Stable tag, the body MUST say that the Stable release is not yet published, identify the actual published RC, and state that Stable publication awaits owner approval. Version and date wording MUST match what is known; an unknown date MUST NOT be represented as a committed release date. If the PR scope changes, the Title and Body MUST be updated to remain an accurate historical record. @@ -542,8 +574,16 @@ When using another library as a visual reference, the implementer MUST NOT copy: An explicit search for reference repository names MUST be conducted before submission. -## 23. Final Release Candidate Checklist +## 23. Release Presentation and First Stable Readiness Checklist +* [ ] The first-Stable gate is applied only when the package has no previously published Stable release. +* [ ] The SemVer RC is an actual tagged pre-release of the target Stable version and is resolvable by an external consumer through the approved distribution channel. +* [ ] The Consumer Verification Harness passed against that exact published RC. +* [ ] Real Host Validation passed against that same RC in at least two independent projects/Hosts, and verifiable evidence for both is retained. +* [ ] The same Harness was not counted twice, and two environments of one Host were not counted as two projects/Hosts. +* [ ] Stable Release Preparation is identified as preparation, not as another Release Candidate. +* [ ] Before the Stable tag and release exist, README, CHANGELOG, SECURITY, badges, and PR metadata do not claim a published or supported Stable version. +* [ ] The two-Host gate is not imposed on already-Stable packages or later patch, minor, or Stable releases. * [ ] README header and Maatify identity are present. * [ ] Required badges exist and point to the current package. * [ ] Packagist badges are complete when the library uses or is being prepared for immediate publication on Packagist. @@ -559,7 +599,7 @@ An explicit search for reference repository names MUST be conducted before submi * [ ] Author block uses visible `
` line breaks. * [ ] The canonical PHP-library footer is the final README element. * [ ] Composer and GitHub metadata are accurate. -* [ ] PR title and body match the actual release-candidate state. +* [ ] PR title and body match the actual published RC or Stable Release Preparation state. * [ ] No foreign package names or URLs remain. * [ ] No `composer.lock` was introduced when the library does not track it. * [ ] CI Gate is successful. diff --git a/docs/standards/PACKAGE_BUILDING_STANDARD.md b/docs/php-engineering-standards/standards/packages/PACKAGE_BUILDING_STANDARD.md similarity index 54% rename from docs/standards/PACKAGE_BUILDING_STANDARD.md rename to docs/php-engineering-standards/standards/packages/PACKAGE_BUILDING_STANDARD.md index 74e3824..64bf5c4 100644 --- a/docs/standards/PACKAGE_BUILDING_STANDARD.md +++ b/docs/php-engineering-standards/standards/packages/PACKAGE_BUILDING_STANDARD.md @@ -1,6 +1,13 @@ # PACKAGE_BUILDING_STANDARD -**Maatify Standalone Composer Package Building Standard — v1** +**Maatify Standalone Composer Package Building Standard** + +## Standard Metadata + +- **Standard ID:** `std-package-building` +- **Standard Version:** `1.4.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` + This document is the law for building any new standalone Composer package in the Maatify ecosystem. Read it fully before writing a single line of code. @@ -8,28 +15,61 @@ Read it fully before writing a single line of code. ## 1. The Package Contract +This standard applies generally to all PHP/Composer reusable libraries in the Maatify ecosystem. + Every package must be: - **Standalone** — runs isolated from host applications (depends only on explicit Composer/runtime dependencies) with no knowledge of the host project internals - **Installable** — packaged as a `composer require` library - **Host-agnostic** — never FKs or JOINs on host tables. Host provides IDs; package trusts them. Host applications wire dependencies themselves. -- **PDO-based** — all persistence uses PDO directly. No ORM, no external query builder. - Small internal SQL fragment builders are allowed only for repeated package-local query logic. - **PHPStan max** — zero errors at level max before the package is considered done +### PHP 8.4 Baseline + +PHP 8.4 is the minimum baseline for newly created Maatify PHP libraries, reusable modules, and new standalone PHP work. An already published package MUST retain its declared compatibility contract until raising the minimum PHP version is permitted by the package's compatibility/versioning policy. + +### Persistence Conditional Applicability + +All rules in this Standard concerning PDO, SQL, `schema/`, migrations, transaction handling, Ordering/Pagination, PDO hydration, database integration, and database-focused testing apply only when the package owns SQL persistence or SQL database behavior. + +A package without persistence or database behavior is not required to use PDO, provide `schema/`, define migrations, or implement database-specific architecture or tests. When a package does own persistence or database behavior, all applicable persistence requirements in this Standard remain mandatory. For SQL persistence, these requirements include direct PDO usage, no ORM, and no external query builder. Small internal SQL fragment builders are allowed only for repeated package-local query logic. + +### Default SQL Persistence Profile + +The default SQL persistence profile is MySQL/MariaDB-compatible and uses direct PDO. + +A package MAY define a different or additional persistence backend, including non-SQL storage, as part of its documented persistence contract. A claimed backend MUST be explicitly documented, actually implemented, and protected by real persistence verification/tests applicable to that backend. + +Additional backends are package-specific and MUST NOT be required of any package. + +PDO driver availability alone does not establish database support. + +### Scope and Ownership + +- This file owns runtime architecture, package structure, and package-specific testing applicability. +- [`TESTING_STANDARD.md`](../testing/TESTING_STANDARD.md) owns the general testing strategy, observable-behavior evidence, regression-protection model, and Consumer Verification Harness contract; this Standard defines Package-readiness applicability and MUST NOT duplicate the Harness's detailed requirements. +- [`COMPOSER_PACKAGE_STANDARD.md`](COMPOSER_PACKAGE_STANDARD.md) owns `composer.json`, dependency declarations, and version constraints. +- [`CI_WORKFLOW_STANDARD.md`](CI_WORKFLOW_STANDARD.md) owns workflow and check execution. +- [`LIBRARY_PRESENTATION_STANDARD.md`](LIBRARY_PRESENTATION_STANDARD.md) owns README structure, badges, and release-facing files. + +These standards MUST use cross-references and MUST NOT duplicate each other's detailed rules. + --- ## 2. Required Maatify Runtime Dependencies To maintain standalone Composer package boundaries and a framework-agnostic architecture while ensuring ecosystem consistency, packages must rely on the provided Maatify shared packages rather than defining package-local duplicates. -- **Exceptions:** Package exceptions must depend on `maatify/exceptions` +- **Exceptions:** When a package defines package-owned exception classes, they MUST use the appropriate stable hierarchy from `maatify/exceptions`, available from `v1.0.0`. + - `MaatifyException` is the abstract root base class. + - `ApiAwareExceptionInterface` is the general public contract. + - The package marker interface remains package-owned and extends `\Throwable`. Repository: https://github.com/Maatify/exceptions -- **Clock/Date-Time:** Clock and date-time contracts must depend on `maatify/shared-common` +- **Clock/Date-Time:** A package that requires a clock abstraction MUST depend on `maatify/shared-common` and consume `ClockInterface`, available from `v1.0.0`. `SystemClock` is a production implementation available from `v1.0.0`, but it is not mandatory for every consumer. No shared Frozen/Test Clock is claimed by this Standard. Repository: https://github.com/Maatify/SharedCommon -- **Persistence Utilities:** Packages that require reusable PDO row-position/display-order management or pagination capabilities must depend on `maatify/persistence` +- **Persistence Utilities:** Packages that require reusable PDO row-position/display-order management (available from `v1.0.0`) or pagination capabilities (available from `v1.1.0`) must depend on `maatify/persistence`. Repository: https://github.com/Maatify/persistence **Rule:** Packages MUST NOT define package-local duplicates of a capability that is available through a stable public API in a Maatify shared package. This prohibition includes exception hierarchies, clock abstractions, PDO row-position/display-order mechanics, and PDO pagination mechanics. @@ -52,17 +92,17 @@ Repository presentation, governance-document identity, release-facing metadata, Composer package metadata, dependency declarations, autoloading, scripts, configuration, stability, and lock-file policy MUST follow [COMPOSER_PACKAGE_STANDARD.md](COMPOSER_PACKAGE_STANDARD.md). -Every package must contain these files at its root (the repository root is the package root): +Every package must contain these files at its package root (the repository root for a standalone package; for an in-project Base Module, the Artifact Root defined in [`MODULE_BUILDING_STANDARD.md`](../modules/MODULE_BUILDING_STANDARD.md)): ``` ├── README.md ← installation, quick examples, what it does / does not ├── CHANGELOG.md ← Keep a Changelog; release history begins at [1.0.0] -├── {PACKAGE_NAME}_PACKAGE_REFERENCE.md ← canonical stable package contract (e.g. EVENT_LOGGING_MODULE_REFERENCE.md) +├── {PACKAGE_NAME}_PACKAGE_REFERENCE.md ← canonical stable package contract (e.g. EXAMPLE_PACKAGE_REFERENCE.md) ├── composer.json ← governed by COMPOSER_PACKAGE_STANDARD.md ├── phpstan.neon ← governed by Section 21 ├── src/ ← all PHP source code ├── tests/ ← if applicable -├── schema/ ← if the package owns SQL schema +├── schema/ ← if applicable (only when the package has SQL persistence or SQL database behavior) └── docs/ ← detailed architecture, integration, roadmap, and audit documents ``` @@ -99,11 +139,11 @@ A multi-domain package still has one canonical root Package Reference unless a d Pattern: `Maatify\{PackageName}\` ``` -Maatify\EventLogging\ +Maatify\LibraryExample\ Maatify\{NextPackage}\ ``` -*Note: Host app namespaces such as `App\`, `Athar`, or `EP4N` are strictly forbidden.* +*Note: Host app namespaces such as `App\`, `HostApp`, or `OtherApp` are strictly forbidden.* ### Type Naming Convention @@ -130,32 +170,25 @@ New packages and unpublished APIs MUST NOT introduce alternative names that omit ## 5. Directory Structure Inside `src/` +The default organizing principle is: + +```text +Domain → Capability → Layer ``` -src/ -├── {Domain}/ ← subpackage / domain boundary -│ ├── Exception/ -│ ├── Contract/ -│ ├── DTO/ -│ ├── Infrastructure/Repository/ -│ └── Service/ -│ -├── Common/ ← framework-neutral shared primitives only -│ -├── Factory/ ← optional, only if framework-agnostic -│ -└── Provider/ ← optional, only if framework-agnostic -``` -- **No mandatory `Admin/Customer`**: Domain boundaries should reflect logical separation. -- **No mandatory `Bootstrap`**: Host apps are responsible for wiring. -- **No framework-specific ServiceProvider/Bindings**: E.g., no Laravel/Slim/PHP-DI bindings inside the package. +Organize first around meaningful domain boundaries, then around capabilities within each domain, and introduce layers inside a capability when its size or responsibilities need them. This is a design direction, not a required directory template: small packages MUST NOT add empty or ceremonial folders just to match a diagram. + +`Common/` is appropriate only for genuinely shared, framework-neutral primitives. The Host owns application bootstrap, container bindings, and framework-specific providers; conditional construction entry points are governed by Section 18. + +Packages MUST NOT impose `Admin/Customer` directories where those are not real domain boundaries. Package runtime exclusions are defined in Section 15. --- ## 6. Schema Rules -- Allowed when the package owns persistence. -- Table prefix: `maa_{package_short_name}_` (e.g. `maa_event_logging_`) +These rules, including `schema/`, database structure, database tests, and migrations, are conditionally applicable **only** when the package has SQL persistence or SQL database behavior. + +- Table prefix: `maa_{package_short_name}_` (e.g. `maa_library_example_`) - Every table needs: `PRIMARY KEY (id)`, proper indexes, meaningful COMMENTs on columns. - All policies (soft delete, display order, FK behavior, uniqueness) documented in the SQL header. - Domain-local schema files are allowed (e.g. `src/{Domain}/Database/`). @@ -210,7 +243,7 @@ This exception: - MUST remain package-specific and MUST NOT be copied into new packages - MUST be reconsidered only during a separately approved, meaningful future major release -A major release MUST NOT be created solely to rename a legacy marker. +Release-version selection, including whether a legacy marker rename warrants a Major release, is governed by [`LIBRARY_PRESENTATION_STANDARD.md`](LIBRARY_PRESENTATION_STANDARD.md). ### Example: Package-Defined Storage Exception @@ -231,19 +264,35 @@ Call sites MUST NOT construct generic or semantically misleading exceptions mere ### Fail-Open / Fail-Closed Behavior Behavior must stay domain-specific: -- **Authoritative Domains** (e.g. `AuthoritativeAudit`) are fail-closed where required by the domain. +- **Authoritative Domains** (e.g. `{AuthoritativeDomain}`) are fail-closed where required by the domain. - **Non-Authoritative Domains** may fail-open only at an explicitly documented boundary. - **Repositories and Read Queries** must never silently swallow storage failures. ### What the package catches and converts +- `PDOException::getCode()` represents the SQLSTATE, not a Driver-specific error code. +- SQLSTATE Class `23` is a broad category for Integrity Constraint Violations (e.g., Duplicate Key, Foreign Key, Explicit NULL), not just duplicates alone. +- It is forbidden to blindly map all `23xxx` errors to an `AlreadyExists` or Duplicate exception. +- Semantic conversion is permitted only when there is documented Driver-specific evidence proving a Duplicate Key violation. +- `PDOException::$errorInfo` might be `null`, so you must check for the existence of `[1]` safely before using it. +- The MySQL/MariaDB driver uses code `1062` to identify a Duplicate Key. Any other Driver or DBMS must use its own official documented code and must not blindly copy `1062`. +- Any error not explicitly classified by a documented evidence must propagate as-is. +- Retain the `previous` exception when your wrapping exception contract supports it, but do not invent a new named constructor signature solely for that purpose. + +*Note: The following example is Driver-specific to MySQL/MariaDB. It is not a general rule for all PDO drivers.* + ```php -// SQLSTATE 23xxx = integrity constraint violation (duplicate key) } catch (\PDOException $e) { - if (str_starts_with((string) $e->getCode(), '23')) { + $driverCode = isset($e->errorInfo[1]) + ? (int) $e->errorInfo[1] + : null; + + // MySQL/MariaDB duplicate-key driver code. + if ($driverCode === 1062) { throw {Domain}CodeAlreadyExistsException::withCode($command->code); } - throw $e; // anything else → propagate as-is + + throw $e; } ``` @@ -276,6 +325,10 @@ If a semantic conversion wraps the original throwable, the original should be re ## 8. Command Rules +For public contracts accepting IDs as raw `int|string` input, accept only a canonical positive integer representation. Reject floats, booleans, null, signs, whitespace, leading zeroes, decimal notation, and scientific notation; check bounds before casting to `int`. + +For strict, known-format date-only input, use `\DateTimeImmutable::createFromFormat()` and require an exact round-trip string match so normalization or overflow is rejected. Inspecting `getLastErrors()` MAY provide an additional check. This does not prohibit general free-form date-time parsing with `\DateTimeImmutable`. + Commands are self-validating value objects: ```php @@ -299,17 +352,21 @@ final readonly class CreateSomethingCommand Rules: - `final readonly` — always -- Validation only in the constructor — no business logic +- A Command represents mutation or action intent. It validates its input contract in the constructor and MUST NOT perform business orchestration. +- Query, search, and list filters use a `Criteria` or another explicit query contract; result or data snapshots use DTOs. An object representing execution intent MUST NOT be named a DTO. +- A small operation with one or two typed inputs MAY use typed parameters directly when a Command would add no meaningful contract. - Display-order inputs MUST follow Section 16; `CreateCommand` and `UpdateCommand` do not accept `display_order` -- Image inputs MUST follow Section 17; `CreateCommand` and `UpdateCommand` do not accept `image` -- Host IDs (e.g. `methodId`, `currencyId`) must be validated with `>= 1` guard +- Host IDs (e.g. `methodId`, `currencyId`) MUST follow the canonical positive-ID contract in this section. +- Image/media inputs MUST follow the conditional ownership and assignment contract in Section 17; this Standard does not require every domain to have an image field or a dedicated image operation. - Monetary and fixed-precision decimal inputs MUST follow Section 19 -- Date/time strings must be validated with `new \DateTimeImmutable($value)` in a try/catch +- General/free-form date-time strings MUST be validated with `new \DateTimeImmutable($value)` in a try/catch; strict known-format date-only inputs follow the round-trip rule defined earlier in this section. --- ## 9. DTO Rules +DTOs represent data snapshots or results and MUST NOT be used as substitutes for Commands or other execution-intent contracts. Query filters belong in a `Criteria` or another explicit query contract, not in a result DTO. + ```php final readonly class SomethingDTO implements \JsonSerializable { @@ -425,6 +482,12 @@ Package: maatify/persistence Repository: https://github.com/Maatify/persistence ``` +### Domain Query and Pagination Ownership + +The Package owns its domain query semantics, including searchable fields, filters, matching and escaping behavior, count semantics, and the public result contract. `maatify/persistence` owns only the reusable pagination and ordering mechanics exposed by its stable public API, as detailed below. + +Management list/search collections that do not have a clearly bounded small maximum MUST provide pagination from the start. A Host MUST NOT load an unbounded result set and paginate it after retrieval. The Package owns the alignment of count and data queries and the meaning of each page; shared mechanics remain delegated to the stable `maatify/persistence` API. + ### Non-Duplication Rule A consumer package MUST NOT create a local replacement for stable ordering or pagination behavior provided by `maatify/persistence`. @@ -473,14 +536,23 @@ The consumer Repository / Service may: The consumer MUST NOT reproduce ordering SQL shifts, transaction ownership, scope locking, identifier validation, or persistence exception behavior locally. +**Integration Boundaries:** +- `getNextPosition()` does not start a transaction or acquire a lock. When concurrency correctness is required, the caller owns both the transaction and the appropriate locking strategy. It alone returns `MAX + 1`. +- `moveWithinScope()` owns a transaction and refuses to run in an active PDO transaction. +- Non-positive movement values are rejected before clamping. Clamping is to the maximum existing position. +- Soft-delete filtering is supported when `deletedAtColumn` is configured and disabled when it is `null`. +- Do not duplicate full public signatures; refer to `maatify/persistence`. + ### Pagination Integration -After a stable `maatify/persistence` release publishes the Pagination API, paginated Repository / QueryReader operations MUST delegate reusable pagination mechanics to the stable public API under: +Paginated Repository / QueryReader operations MUST delegate reusable pagination mechanics to the stable public API under: ```text Maatify\Persistence\Pdo\Pagination ``` +`PdoPaginator` does not own a transaction and can run inside a caller-owned transaction without modifying its state. + The consumer remains responsible for domain-owned concerns: - mandatory security, tenant, ownership, visibility, and soft-delete constraints @@ -524,86 +596,52 @@ Exact class signatures, internal formulas, SQL assembly rules, exception classif ## 12. Translation Pattern -### Always support both paths +Translation support is **CONDITIONAL**, not a universal Package requirement. A Package MUST implement translation only when translation is part of its actual domain contract. Packages without a translation requirement MUST NOT add translation APIs, fields, persistence, joins, or fallback behavior solely to conform to this Standard. -```php -// Path 1: with translation (for apps using a translation system) -listByLanguageId(int $languageId): CollectionDTO +### Domain-Owned Translation Contract -// Path 2: base name only (for apps without a translation system) -listWithoutTranslation(): CollectionDTO -``` +When translation is part of the domain, the Package Reference and Architecture for that Package are authoritative for: -### JOIN Guard — critical for avoiding duplicate rows +- ownership of localized fields +- translation identity +- fallback semantics +- mutation semantics +- query contracts, including result cardinality, filtering, and search behavior -```php -// ONLY join translations when languageId is explicitly provided. -// Without this guard: if a method has 2 translations (ar + en), -// a JOIN without language filter returns 2 rows per method. - -if ($languageId !== null) { - $joinSql = 'LEFT JOIN maa_something_translations t - ON t.something_id = s.id - AND t.language_id = :language_id'; - $translationSelect = 'COALESCE(t.name, s.name) AS name, - COALESCE(t.image, s.image) AS image'; - $params['language_id'] = $languageId; -} else { - $joinSql = ''; - $translationSelect = 'NULL AS translated_name, NULL AS translated_image'; -} -``` +The general Package Standard must not force a package to invent localized base fields, fallback behavior, actor-specific query shapes, or mutation semantics that are not part of its domain contract. -### COALESCE Fallback Chain +Accordingly, this Standard does not require any particular translation implementation, including: -```sql --- Always in customer queries: -COALESCE(t.name, s.name) AS name -- translated → base -COALESCE(t.image, s.image) AS image -- translated → base +- a base localized value +- `listWithoutTranslation()` +- `language_id` specifically +- `COALESCE(translated, base)` fallback +- Upsert as the only mutation +- fixed Admin/Customer query shapes +- fixed search fields +- comparison with a base name --- Admin findById (no language): select s.name directly — no JOIN needed -``` +### Unified Same-Shape Content Pattern -### Upsert Pattern — always, never separate INSERT + UPDATE +Translation remains optional. When localized and non-localized values are the same concept with the same shape, a unified content relation that supports `language_code = NULL` and non-NULL language codes is the preferred pattern over a base relation plus a structurally duplicate translations relation. -```sql -INSERT INTO maa_something_translations - (something_id, language_id, name) -VALUES - (:something_id, :language_id, :name) -ON DUPLICATE KEY UPDATE - name = VALUES(name), - updated_at = NOW() -``` +`NULL` represents the exact NULL-language scope; it MUST NOT mean fallback to or from a specific language unless the domain contract says so explicitly. A separate translation relation remains appropriate when structure, lifecycle, identity, or cardinality materially differs. This preference MUST NOT create a translation capability in a domain that does not need one. -Requires `UNIQUE KEY (something_id, language_id)` on the translation table. - -### Admin Translation List — LEFT JOIN on base table - -```sql -SELECT - t.id, - t.something_id, - t.language_id, - t.name, - t.image, - t.created_at, - t.updated_at, - s.name AS base_name, -- shown alongside translation for admin comparison - s.image AS base_image -FROM maa_something_translations t -LEFT JOIN maa_something s ON s.id = t.something_id -{$whereSql} -ORDER BY t.something_id ASC, t.language_id ASC -``` +### Host-Owned Language Identity + +If language or locale identity is owned by the Host, the Package MUST NOT create a foreign key to, or a JOIN with, Host tables, in accordance with the Package isolation rules. The Package must use only the identity and integration contract exposed to it without coupling its persistence to Host table structure. + +### Translation Query Cardinality -### Global Search Scope +Any query whose contract promises one row per entity MUST constrain the translation relation to one logical translation identity before joining, or avoid joining translations. An unrestricted JOIN that can return multiple translations for one entity is not permitted for a single-row-per-entity contract. A query may return multiple translations only when its contract explicitly defines a translation collection and its result shape supports that cardinality. -| Context | Search fields | -|---|---| -| Admin main list | Base table fields only (`s.name`, `s.code`) — never join translations for search | -| Admin translation list | Translation fields only (`t.name`) — that IS the translation table | -| Customer list | No search — customer receives a filtered, ordered list only | +### Translation Persistence Invariants + +If the Package owns persistence for translations: + +- the logical translation identity MUST be documented in the Package Reference or Architecture +- the persistence schema MUST enforce that identity with uniqueness constraints appropriate to the domain contract +- the mutation behavior MUST follow the domain contract; this Standard does not prescribe Upsert or any other single mutation strategy --- @@ -611,8 +649,9 @@ ORDER BY t.something_id ASC, t.language_id ASC Responsibility: - **Business orchestration** lives in Services -- **Validation** lives in Commands and DTO filters +- **Input validation** lives in Commands; query filters are validated by their `Criteria` or query contract - **SQL** lives in Repositories or package-local/domain-local SQL support builders +- **Display formatting** does not belong in Repositories or query layers; those layers return raw domain/database values for the Host's presentation layer. ```php // Command service — throws NotFoundException when repo returns false @@ -646,8 +685,7 @@ Services **never**: Some business modules may choose actor-specific namespaces (e.g., `Admin\` vs `Customer\`). -However, **infrastructure packages** like `event-logging` should use their real package/domain boundaries instead. -For example, in `event-logging`, the six logging domains (e.g., `AuthoritativeAudit`, `BehaviorTrace`) serve as the public architectural boundaries rather than arbitrary Admin/Customer folders. +However, infrastructure packages such as `{PACKAGE_SLUG}` should use their actual package/domain boundaries instead. For example, `{DomainOne}` and `{DomainTwo}` may serve as public architectural boundaries rather than arbitrary Admin/Customer folders. --- @@ -655,6 +693,8 @@ For example, in `event-logging`, the six logging domains (e.g., `AuthoritativeAu Packages that have persisted data intended to be viewed, searched, audited, monitored, or reported by host applications should expose framework-agnostic PHP read/query contracts where applicable. +When management and consumption are distinct domain use cases, the Package MUST expose a Management API and a Consumer API with separate contracts. Management APIs may support administrative search, filters, statuses, deleted-state visibility, and pagination. Consumer APIs expose only records valid under the Package's domain visibility invariants; the Host MUST NOT be left to reproduce those invariants through generic filters. If the two uses are not meaningfully distinct, a Package MUST NOT create duplicate APIs merely to satisfy this pattern. + **Important:** This refers strictly to **PHP-level APIs** (e.g., PHP interfaces and DTOs), not HTTP APIs. These contracts may cover (where applicable and appropriate for the package's domain): @@ -691,15 +731,15 @@ The package-level integration contract is: - shifting, clamping, scope locking, transaction ownership, identifier validation, and persistence exception behavior MUST remain delegated to `maatify/persistence` - a consumer MUST NOT reproduce or fork the Ordering engine locally -Exact class names, method signatures, transaction behavior, and Runtime semantics are owned by the stable `maatify/persistence` public API and `PERSISTENCE_PACKAGE_REFERENCE.md`. +Exact class names, method signatures, transaction behavior, and Runtime semantics are owned by the stable `maatify/persistence` public API and [PERSISTENCE_PACKAGE_REFERENCE.md](https://github.com/Maatify/persistence/blob/main/PERSISTENCE_PACKAGE_REFERENCE.md). ### Deferred Hard-Delete Ordering Compaction The stable `maatify/persistence` Ordering API currently does not expose a hard-delete compaction operation. -The package-specific decision to preserve scoped ordering compaction as a future candidate is recorded in [ADR 0002 — Ordering Hard-Delete Compaction](../adr/0002-ordering-hard-delete-compaction.md). +The package-specific decision to preserve scoped ordering compaction as a future candidate is recorded in [ADR 0002 — Ordering Hard-Delete Compaction](https://github.com/Maatify/persistence/blob/main/docs/adr/0002-ordering-hard-delete-compaction.md). Its status is `Accepted — Deferred`. Compaction is not implemented, has no stable API or release target, and is not part of Pagination `v1.1.0`. -Until a stable Runtime API is separately approved, implemented, released, and recorded in `PERSISTENCE_PACKAGE_REFERENCE.md`: +Until a stable Runtime API is separately approved, implemented, released, and recorded in [PERSISTENCE_PACKAGE_REFERENCE.md](https://github.com/Maatify/persistence/blob/main/PERSISTENCE_PACKAGE_REFERENCE.md): - consuming projects retain ownership of entity deletion and project-specific hard-delete orchestration - consumers MUST NOT claim or depend on an unreleased Persistence compaction API @@ -708,15 +748,19 @@ Until a stable Runtime API is separately approved, implemented, released, and re --- -## 17. Image Rules +## 17. Image and Media Rules + +Image and media support is conditional. A domain MUST NOT be required to introduce an image field or Media subsystem merely to comply with this Standard. + +### Simple Image Value -- An `image` column is `VARCHAR(255) NULL` and stores a path or URL only, never binary data -- `image` MUST NOT be accepted by `CreateCommand` or `UpdateCommand` -- image changes MUST be exposed through dedicated package operations rather than generic update commands -- the Command Repository image-update operation MUST return `bool` to report whether the target row existed and was updated -- a Service MAY expose a `void` image-update operation and convert a Repository `false` result into the approved not-found exception -- `null` clears the image by setting the column to `NULL` -- translation-image updates MUST follow the same Repository `bool` / Service `void` layer contract +A scalar path or URL is appropriate only when the domain treats the image as a simple value and does not require media lifecycle, roles, scopes, ordering, a default assignment, processing, or storage ownership. In that case the Package Reference defines the value and mutation semantics. This Standard does not impose `VARCHAR(255)`, null-clearing behavior, or a dedicated operation as universal rules. + +### External Media Asset and Domain Assignment + +When the domain requires media lifecycle, roles, scopes, ordering, default assignments, processing, or explicit storage ownership, it MUST use an external Media Asset and domain-assignment boundary. The Host/Media system owns upload, storage, processing, and media lifecycle. The Package stores only a stable external media identity (for example, `media_asset_id`) and MUST NOT add Host foreign keys, joins, repositories, or module dependencies to resolve it. The Package owns the assignment semantics it needs, such as role, exact scope, ordering, default, and assignment lifecycle. + +Assignment identity fields MUST remain stable under generic updates. A role registry is Package-owned only when role identity or its lifecycle/status is part of the Package's domain invariants. Nullable assignment scopes follow the exact-scope rule in Section 24; `NULL` MUST NOT imply a wildcard or fallback. --- @@ -726,7 +770,9 @@ Until a stable Runtime API is separately approved, implemented, released, and re Rules: - No Slim/Laravel/Symfony/PHP-DI bindings as package requirements. -- Optional factories or providers are allowed, but they must be strictly framework-agnostic. +- A framework-neutral Factory or Builder is appropriate when internal wiring is non-trivial; a thin public Facade/API may be appropriate when multiple public capabilities make discovery or construction materially clearer. +- These construction patterns are conditional, not boilerplate. A Factory MUST NOT become a Service Locator, and neither a Factory nor a Facade may depend on a framework container. +- Optional Providers, when useful, must be strictly framework-agnostic. - Host applications are fully responsible for wiring dependencies through their own container or runtime environment. --- @@ -792,12 +838,31 @@ parameters: ``` Repositories MUST configure PHPStan from their actual package-owned paths and MUST NOT reference a non-existent path merely to copy this example. Existing package-owned tests MUST NOT be excluded from static analysis. +No PHPStan baseline, `ignoreErrors`, or inline suppression is permitted merely to make CI green. + +### Final Classes and Test Doubles + +- Test Doubles MUST target interfaces or replaceable contracts by default, not concrete `final` classes. +- A `final` keyword MUST NOT be removed from a class solely to facilitate testing. +- When testing a class that depends on a concrete final class: + 1. Use a real instance if it is deterministic and suitable for testing. + 2. Or test via a Mock/Fake for the collaborators or external boundaries that it depends on. + 3. Create an interface only when replaceability is a true runtime requirement, not just to satisfy a single test. +- Production design must not be weakened solely for testing; `final` and `readonly` must not be removed merely to make mocking easier. +- Interfaces must not be invented solely for a one-off test when runtime replaceability is not a real architectural requirement. +- Prefer testing through real deterministic instances or proper replaceable collaborators/contracts. +- The package `dg/bypass-finals` is NOT a Central Baseline and NOT a general requirement for Maatify projects. +- `dg/bypass-finals` MAY be used as a development-only test tool when a repository has a legitimate documented need to test/mock concrete final classes and that choice is consistent with its test architecture. +- Its use must never justify PHPStan suppressions, baselines, or weakening production architecture. ### Testing Strategy +- The core testing strategy and regression-protection rules are exclusively governed by the canonical [Testing Standard](../testing/TESTING_STANDARD.md). +- For code with testable behavior, appropriate automated tests are required. - Packages that own persistence, database, or external-service behavior MUST define appropriate Integration coverage. Unit and Regression suites remain required where applicable. - Package-owned test behavior, fixtures, and suite responsibilities belong to the package architecture and reference documentation. - CI execution requirements — including real-service provisioning, MySQL/SQLite enforcement, PHP matrices, cleanup/repeatability checks, and example syntax validation — are governed exclusively by [`CI_WORKFLOW_STANDARD.md`](CI_WORKFLOW_STANDARD.md). +- Package readiness requires the complete maintained and applicable test suite to be covered by the appropriate CI quality gate, using the repository's actual maintained test runner and tooling. CI execution and failure enforcement are governed by [`CI_WORKFLOW_STANDARD.md`](CI_WORKFLOW_STANDARD.md). ### PDO fetch results — always annotate @@ -862,15 +927,55 @@ Compliance requires the repository's CI to pass the current Compliance Checklist - [ ] CI workflows exist, pass, and satisfy the current Compliance Checklist in `CI_WORKFLOW_STANDARD.md` - [ ] Package-owned runtime and test architecture is represented in CI where applicable -- [ ] `README.md` written with installation steps and quick examples -- [ ] `CHANGELOG.md` follows `LIBRARY_PRESENTATION_STANDARD.md`, retains `[Unreleased]` at the top, and begins release history at `[1.0.0]` +- [ ] `README.md`, `CHANGELOG.md`, and other release-facing files comply with `LIBRARY_PRESENTATION_STANDARD.md`. - [ ] `{PACKAGE}_PACKAGE_REFERENCE.md` complete — full API, design rules, extension guide - [ ] `composer.json` complies with [COMPOSER_PACKAGE_STANDARD.md](COMPOSER_PACKAGE_STANDARD.md). +- [ ] The consumer workflow and examples meet the requirements in Section 25. +- [ ] The standalone Package has the reproducible Consumer Verification Harness required by [TESTING_STANDARD.md](../testing/TESTING_STANDARD.md). - [ ] Every public service/repository capability intended for infrastructure substitution has a matching contract (interface) - [ ] Domain-specific failure semantics are documented - [ ] Transaction catch blocks rethrow the original `\Throwable` after rollback — never swallow - [ ] Business orchestration lives in Services, validation in Commands/filters, SQL in Repositories -- [ ] Schema docs align with MySQL/domain-owned tables, no generic `logs` or `event_logs` tables +- [ ] Schema/persistence documentation aligns with the package's declared persistence backend and domain-owned storage structures, with no generic `logs` or `event_logs` storage - [ ] Framework-agnostic boundaries preserved: no host app namespaces, no framework bindings required - [ ] No generic logger, recorder, or repository - [ ] Docs reflect current exception rules, package-defined exceptions use `maatify/exceptions`, and any clock/date-time contract uses `maatify/shared-common` instead of a local duplicate + +## 24. Domain Ownership, External References, and Lifecycle + +The Package Reference or Architecture MUST make ownership explicit for each domain capability and persisted concept: + +- what the Package owns and enforces as a domain invariant +- what the Host owns +- which values are stored only as stable external identities +- which external concepts the Package does not interpret or manage the lifecycle of + +A Package MUST create an internal Registry only when the identity, lifecycle, status, or validity of that concept is part of the Package's own invariants. A Host-owned concept that the Package does not own is represented by a stable external ID or key; the Package MUST NOT acquire ownership merely because it stores or receives that value. + +Standalone Packages and Base Modules MUST NOT depend on Host foreign keys, Host-owned table joins, Host repositories, or Host modules. Where the Package does not own semantic validation of an external identity, that validation remains with the Host. + +Nullable scope fields use exact-scope semantics: `NULL` means only the exact NULL scope. It MUST NOT mean wildcard, fallback, all, default, any language, or any platform unless the domain contract explicitly defines that meaning. + +For each entity or assignment, the Package Reference MUST distinguish stable identity fields from mutable business fields, lifecycle fields, and ordering fields. Generic updates MUST NOT change stable identity. Soft Delete is optional and SHOULD be used only when domain history, restore behavior, or identity invariants require it; it is not a universal capability. When a lifecycle is used, its identity, uniqueness, restore, and deletion semantics MUST be documented. + +## 25. Runtime Workflow, Transactions, Concurrency, and Clock + +Each reusable Package MUST document a realistic consumer workflow in its Package Reference, Architecture, or practical Usage Guide. The documented workflow MUST show the consumer path: + +```text +Host Input → Public API → Domain Service → Integration Boundary → Observable Result +``` + +Examples MUST demonstrate supported construction/wiring, a basic workflow, public API use, and the applicable integration boundaries. They illustrate the contract; the Package Reference and this Standard remain the sources of normative rules. + +When a domain invariant spans multiple operations, the Package MUST identify the transaction owner and the required transaction, locking, and concurrency boundaries. It MUST state whether an outer transaction is supported when that affects callers. Race-prone invariants—such as ordering, hierarchy, unique defaults, or lifecycle transitions—require concurrency verification when concurrent access is realistic for the domain. The Testing Standard owns the general testing evidence model. + +Packages MUST NOT change the global timezone. When the Package needs a clock abstraction, it MUST use the established Clock contract described in Section 2. The Host owns timezone policy unless the domain contract explicitly assigns a different policy to the Package. Repositories MUST NOT silently reinterpret timestamps. + +## 26. Extensible Content Fields Pattern + +Extensible content fields are conditional and are appropriate only when a domain needs variable content fields alongside its stable core fields. They MUST NOT be added merely to anticipate possible future extension. + +When this pattern applies, the domain contract may define a stable `field_key`, a value and typed format, exact optional scopes, deterministic ordering, lifecycle, and uniqueness according to actual domain invariants. Identity fields and scopes that define assignment identity MUST remain stable under generic updates. + +The Host owns the meaning and administration of `field_key`, including editor configuration, sanitization, rendering, and fallback, unless the Package's own domain explicitly owns those semantics. The Package MUST NOT create a Field Definition Registry solely because it stores a `field_key`; the Registry rule in Section 24 still applies. diff --git a/docs/php-engineering-standards/standards/profiles/COMPOSER_PACKAGE_PROFILE.md b/docs/php-engineering-standards/standards/profiles/COMPOSER_PACKAGE_PROFILE.md new file mode 100644 index 0000000..c141b34 --- /dev/null +++ b/docs/php-engineering-standards/standards/profiles/COMPOSER_PACKAGE_PROFILE.md @@ -0,0 +1,38 @@ +# Composer Package Profile + +## Profile Metadata + +- **Profile ID:** `composer-package` +- **Profile Version:** `1.0.0` +- **Purpose / Applicability:** مكتبات PHP/Composer المستقلة القابلة لإعادة الاستخدام والتوزيع ضمن منظومة Maatify. +- **Extends:** `None` + +## Required Standards + +هذه هي الـ Standards المباشرة لهذا Profile: + +- [Package Building Standard](../packages/PACKAGE_BUILDING_STANDARD.md) +- [Composer Package Standard](../packages/COMPOSER_PACKAGE_STANDARD.md) +- [CI Workflow Standard](../packages/CI_WORKFLOW_STANDARD.md) +- [Library Presentation Standard](../packages/LIBRARY_PRESENTATION_STANDARD.md) +- [Testing Standard](../testing/TESTING_STANDARD.md) + +لا ينقل هذا Profile محتوى أي Standard إلى ملف Profile. + +## Conditional Applicability + +تظل قواعد Persistence وDatabase وPDO وSchema والمigrations والاختبارات التابعة لها مشروطة بامتلاك الحزمة Database/Persistence behavior، كما يملكها [PACKAGE_BUILDING_STANDARD.md](../packages/PACKAGE_BUILDING_STANDARD.md). الحزمة التي لا تمتلك هذا السلوك لا تُلزم بهذه القواعد المشروطة. + +## Resolved Dependency Behavior + +لا يرث هذا Profile Profile آخر. يدخل Required Standards الخمسة في Resolved Set عند تفعيله، ثم تضاف Additional Standards المصرح بها في Manifest فقط. + +عند تفعيل هذا Profile، يجب تثبيت ملفه محليًا ضمن `Pinned Adoption Control Set`؛ وتثبت كذلك ملفات Profiles الموروثة اللازمة للحل، بينما لا تُنسخ Profiles غير المفعلة. + +## Scope Notes + +يجب تفعيل Profile على Scope يمثل مكتبة Composer أو مسارها الفعلي. لا يجعل تفعيله Standards الموديولات أو الحوكمة منطبقة تلقائيًا. + +## Precedence Notes + +هذا الملف composition manifest. تفاصيل Package وComposer وCI وPresentation وTesting تظل مملوكة للملفات الأصلية، وآلية التفعيل والتثبيت مملوكة لـ [STANDARDS_ADOPTION_STANDARD_AR.md](../STANDARDS_ADOPTION_STANDARD_AR.md). diff --git a/docs/php-engineering-standards/standards/profiles/REPOSITORY_GOVERNANCE_PROFILE.md b/docs/php-engineering-standards/standards/profiles/REPOSITORY_GOVERNANCE_PROFILE.md new file mode 100644 index 0000000..429b1de --- /dev/null +++ b/docs/php-engineering-standards/standards/profiles/REPOSITORY_GOVERNANCE_PROFILE.md @@ -0,0 +1,35 @@ +# Repository Governance Profile + +## Profile Metadata + +- **Profile ID:** `repository-governance` +- **Profile Version:** `1.0.0` +- **Purpose / Applicability:** إدارة التعاون، دورة Phase، والحوكمة التشغيلية في Repository تتبع Maatify engineering workflow. +- **Extends:** `None` + +## Required Standards + +هذه هي الـ Standards المباشرة لهذا Profile: + +- [AI Collaboration Workflow](../ai/AI_COLLABORATION_WORKFLOW_AR.md) +- [GitHub Phase Stack Workflow](../GITHUB_PHASE_STACK_WORKFLOW_AR.md) + +لا يضم هذا Profile Package أو Module standards. + +## Conditional Applicability + +تطبق الـ Standards المطلوبة على Scope الذي يفعّل فيه المشروع Profile. تفاصيل الأدوار والـ Phase lifecycle تظل مملوكة للملفين المشار إليهما. + +## Resolved Dependency Behavior + +لا يرث هذا Profile Profile آخر. يكون الـ Resolved Set له هو Required Standards المذكورة أعلاه، مع أي Additional Standards مصرح بها صراحةً في Manifest المشروع. + +عند تفعيل هذا Profile، يجب تثبيت ملفه محليًا ضمن `Pinned Adoption Control Set`؛ وتثبت كذلك ملفات Profiles الموروثة اللازمة للحل، بينما لا تُنسخ Profiles غير المفعلة. + +## Scope Notes + +يجب أن يسجل المشروع Scope صريحًا لكل Activation، مثل `/` أو مسارات الحوكمة التي يشملها العقد. يمكن تفعيله إلى جانب Profiles أخرى في Repository نفسها. + +## Precedence Notes + +هذا الملف composition manifest فقط. تطبق قواعد adoption من [STANDARDS_ADOPTION_STANDARD_AR.md](../STANDARDS_ADOPTION_STANDARD_AR.md)، وتظل قواعد التعاون ودورة Phase مملوكة للـ Standards المطلوبة. diff --git a/docs/php-engineering-standards/standards/testing/TESTING_STANDARD.md b/docs/php-engineering-standards/standards/testing/TESTING_STANDARD.md new file mode 100644 index 0000000..a389e80 --- /dev/null +++ b/docs/php-engineering-standards/standards/testing/TESTING_STANDARD.md @@ -0,0 +1,135 @@ +# TESTING_STANDARD + +**Maatify Testing Architecture and Regression Protection Standard** + +## Standard Metadata + +- **Standard ID:** `std-testing` +- **Standard Version:** `1.1.0` +- **Standard Version Format:** `MAJOR.MINOR.PATCH` + +This document establishes the canonical, repository-wide Testing Standard for the Maatify ecosystem. Its primary purpose is to protect implemented behavior from regressions and unintended damage during future development. + +--- + +## 1. Core Principle + +> Every externally observable behavior, critical workflow, integration boundary, and resolved regression MUST be protected by an appropriate end-to-end or system-level test. A change MUST NOT be considered complete when its correctness depends solely on unit-level verification. + +This is a mandatory engineering rule, not a suggestion. + +--- + +## 2. Normative Language + +The key words **MUST**, **MUST NOT**, **REQUIRED**, **SHALL**, **SHALL NOT**, **SHOULD**, **SHOULD NOT**, **RECOMMENDED**, **MAY**, and **OPTIONAL** in this document are to be interpreted as described in RFC 2119. + +--- + +## 3. Testing Layers + +The testing strategy MUST distinguish between the following layers: + +### 3.1. Unit Tests + +Unit tests verify isolated logic and components. + +Their purpose includes: +- Logic correctness. +- Edge case handling. +- Deterministic isolated behavior. +- Fast developer feedback. + +Unit tests alone MUST NOT be treated as sufficient proof for externally observable workflows where integration or system behavior matters. + +### 3.2. Integration Tests + +Integration tests cover actual collaboration between components or infrastructure boundaries. + +Examples include: +- Service + Repository collaboration. +- Persistence behavior. +- Database interactions. +- Adapters and infrastructure. +- Serialization/deserialization. +- Framework integration. + +While mocks or fakes MAY be useful at some test levels, a mocked dependency chain MUST NOT be described as end-to-end or system-level verification. + +### 3.3. End-to-End (E2E) / System-Level Tests + +System-level and E2E tests are defined by **behavioral boundary**, not by technology. E2E does NOT automatically mean browser testing. + +The test MUST exercise the system through an externally meaningful or public entry point and verify the final observable result across the relevant real execution chain. + +Examples: +- **API/Module:** `HTTP Request → Route → Handler → Service → Repository → Persistence → Response` +- **Standalone Library:** `Public API → Internal Implementation → Required Integration Boundary → Observable Result` +- **CLI Application:** `CLI Command → Application/Service Layer → Infrastructure → Exit Code/Output/State` +- **Admin/Web UI:** `Browser/User Action → Frontend → HTTP → Backend → Persistence/State → Final User-Visible Result` + +Browser automation is REQUIRED only when the browser or UI itself is part of the behavior being protected. + +### 3.4. Consumer Verification Harness + +Every standalone reusable Package, and every Base Module intended to be extractable as a Package, MUST have a reproducible Consumer Verification Harness. + +The Harness is external-consumer evidence, not merely another test suite run with the Package repository as the root project. It MUST: + +- use a Composer root separate from the Package root or Base Module Artifact Root, and resolve and use the artifact as a Composer dependency +- exercise the artifact through its production PSR-4 autoload and documented public API or public contracts +- complete a realistic consumer workflow from input through the public API and applicable integration boundary to an observable result +- run successfully at least twice from clean consumer states; each run MUST be repeatable without relying on prior `vendor/`, generated state, database state, or other leftover environment state + +A Harness MAY be a fixed consumer project, a fixture/template, or a deterministic script that creates a clean consumer project. Regardless of its form, it MUST NOT bypass Composer with direct `require`/`include` of `src/` files, depend on the artifact's `autoload-dev`, test namespace, test bootstrap, internal test fixtures, Host namespace, or Host autoload configuration, or access internal implementation details instead of documented public contracts. For a Base Module, the Harness MUST consume the Module's Artifact Root itself as the dependency; the Host root is not a substitute. + +The proof MUST include Composer installation/resolution, production autoload, public API usage, the realistic workflow, its observable result, and the absence of hidden Host dependencies. Observable results are domain-specific and MAY include a returned public result/DTO, persisted state, a public effect, or a documented exception/failure contract; no single result type is required for every Package. + +Persistence, schema/install assets, transactions, Clock, external services, cleanup, and other integration boundaries MUST be covered when they apply to the artifact's behavior, and MUST NOT be imposed on artifacts that do not need them. When the artifact owns persistence, the Harness MUST prove the relevant real persistence boundary; unit mocks alone are insufficient. When the domain has race-prone invariants and concurrent access is realistic, suitable concurrency verification MUST be included; unit mocks alone are insufficient for that proof. + +The Harness is an additional external-consumer proof layer. It MUST NOT replace applicable Unit, Integration, or System/E2E coverage. System/E2E boundaries remain behavior-based as defined in Section 3.3, so browser automation is required only when browser/UI behavior is part of the contract. A Consumer Verification Harness also does not replace Real Host Validation or define release eligibility. + +--- + +## 4. Regression Protection Rules + +Future development MUST NOT rely only on implementation-level tests. + +### 4.1. Existing Behavior Protection +A refactor or new feature MUST NOT silently break already-supported observable behavior. Existing system/E2E tests SHOULD act as regression contracts. + +### 4.2. New Observable Behavior +New externally observable behavior MUST receive appropriate system/E2E protection before the work is considered complete. + +### 4.3. Critical Workflows +Critical workflows MUST have system-level coverage even when their internal components already have unit tests. + +### 4.4. Integration Boundaries +Where correctness depends on multiple components working together, an appropriate integration test MAY complement the coverage, but it MUST NOT replace required system/E2E protection where the Testing Standard requires it. + +### 4.5. Resolved Bugs/Regressions +A fixed regression MUST be accompanied by a test capable of detecting recurrence. Prefer the narrowest useful regression test, but when the defect affected an externally observable or critical workflow, ensure the relevant system/E2E path is protected as well. + +### 4.6. Internal-Only Refactors +If an internal refactor does not create or change externally observable behavior, and existing E2E/system coverage already protects the behavior, that existing coverage MAY be sufficient. The rule is about behavioral protection, not test-count inflation. You are NOT required to write a new E2E test for every trivial internal change. + +--- + +## 5. Completion and Readiness Semantics + +Implementation completion REQUIRES the appropriate combination of testing layers. + +A task, part, or phase MUST NOT be considered technically complete merely because: +- Unit tests pass. +- Static analysis passes. +- Individual classes are tested. +- Mocks reproduce the expected calls. + +Where the feature depends on a real workflow or integration chain, appropriate system-level verification MUST also pass. + +For artifacts covered by Section 3.4, completion and readiness also require the Consumer Verification Harness evidence defined there. + +--- + +## 6. Adoption Status +يصبح معتمدًا عند دمجه في الفرع الافتراضي للمشروع. diff --git a/schema/README.md b/schema/README.md new file mode 100644 index 0000000..b3e05aa --- /dev/null +++ b/schema/README.md @@ -0,0 +1,7 @@ +# مخطط قاعدة البيانات + +هذه الحزمة تملك سلوك SQL/PDO عامًّا لإدارة الترتيب والمعاملات والترقيم، لكنها لا تملك كيانًا دائمًا أو جدولًا إنتاجيًا خاصًا بها. يزوّد المستهلك جدولَه ومعرّفاته الموثوقة إلى واجهات الحزمة، ولذلك لا توجد migrations أو schema إنتاجية تُثبت عند تثبيت Composer. + +توجد مخططات MySQL المعزولة الخاصة باختبارات المستودع تحت [tests/Fixtures/MySql/](../tests/Fixtures/MySql/)، كما ينشئ Consumer Verification Harness جدوله المعزول مؤقتًا داخل قاعدة الاختبار ثم يحذفه. هذه الملفات ليست جداول Host ولا تعتمد على أي schema خارجي. + +الحد التعاقدي لقاعدة البيانات هو MySQL/MariaDB-compatible SQL عبر PDO المباشر. لا تستخدم الحزمة ORM أو query builder خارجيًا، ولا تنشئ جداول عامة مثل logs أو event_logs، ولا تضيف مفاتيح خارجية أو JOINs إلى جداول Host. diff --git a/tests/Consumer/run.php b/tests/Consumer/run.php new file mode 100644 index 0000000..1802d9e --- /dev/null +++ b/tests/Consumer/run.php @@ -0,0 +1,418 @@ + 'maatify/persistence-consumer-verification', + 'description' => 'External consumer verification for maatify/persistence.', + 'repositories' => [ + [ + 'type' => 'path', + 'url' => $repositoryRoot, + 'options' => ['symlink' => false], + ], + ], + 'require' => [ + 'ext-pdo' => '*', + 'maatify/persistence' => '*', + 'php' => '>=8.2', + ], + 'minimum-stability' => 'dev', + 'prefer-stable' => true, + 'config' => [ + 'allow-plugins' => false, + ], + ]; + $composerJson = json_encode( + $consumerComposer, + JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR, + ) . PHP_EOL; + + if (file_put_contents($consumerRoot . '/composer.json', $composerJson) === false) { + throw new RuntimeException('Unable to write the clean consumer composer.json.'); + } + + runCommand( + [ + composerBinary(), + 'install', + '--no-interaction', + '--prefer-dist', + '--no-progress', + '--no-ansi', + '--no-scripts', + ], + $consumerRoot, + ); + + require $consumerRoot . '/vendor/autoload.php'; + + $installedPath = InstalledVersions::getInstallPath('maatify/persistence'); + if (! is_string($installedPath) || $installedPath === '') { + throw new RuntimeException('Composer did not install maatify/persistence as a dependency.'); + } + + if (is_link($installedPath) || realpath($installedPath) === realpath($repositoryRoot)) { + throw new RuntimeException('The consumer dependency must be installed without a source-tree symlink.'); + } + + if (! class_exists(ScopedOrderingManager::class)) { + throw new RuntimeException('The installed package production autoload is unavailable.'); + } + + $pdo->exec('DROP TABLE IF EXISTS ' . $table); + $pdo->exec( + 'CREATE TABLE ' . $table . ' ( + id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT "Consumer-owned row identity.", + scope_key VARCHAR(64) NOT NULL COMMENT "Consumer-owned ordering scope.", + display_order INT NOT NULL COMMENT "Consumer-owned mutable ordering position.", + deleted_at DATETIME NULL DEFAULT NULL COMMENT "Optional consumer-owned soft-delete timestamp.", + name VARCHAR(128) NOT NULL COMMENT "Consumer-visible row name.", + PRIMARY KEY (id), + KEY idx_consumer_scope_order (scope_key, display_order), + KEY idx_consumer_scope_deleted (scope_key, deleted_at) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT="Temporary consumer verification rows."', + ); + $tableCreated = true; + + $insert = requireStatement( + $pdo->prepare( + 'INSERT INTO ' . $table . ' (scope_key, display_order, name) + VALUES (:scope_key, :display_order, :name)', + ), + 'consumer insert', + ); + + $ids = []; + foreach ([1, 2, 3] as $order) { + $insert->execute([ + 'scope_key' => 'consumer', + 'display_order' => $order, + 'name' => 'item-' . $order, + ]); + $id = $pdo->lastInsertId(); + if ($id === false || ! ctype_digit($id)) { + throw new RuntimeException('Unable to read the consumer row identity.'); + } + $ids[] = (int) $id; + } + + $orderingConfig = new ScopedOrderingConfig( + table: $table, + scopeColumn: 'scope_key', + idColumn: 'id', + orderColumn: 'display_order', + deletedAtColumn: 'deleted_at', + ); + $ordering = new ScopedOrderingManager(); + + expectSame(4, $ordering->getNextPosition($pdo, $orderingConfig, 'consumer'), 'next consumer position'); + expectTrue( + $ordering->rowExistsInScope($pdo, $orderingConfig, 'consumer', $ids[0]), + 'consumer row existence', + ); + + $savepointRunner = new PdoSavepointTransactionRunner($pdo); + $pdo->beginTransaction(); + + try { + executeStatement( + $pdo->prepare( + 'UPDATE ' . $table . ' SET name = :name WHERE id = :id', + ), + ['name' => 'outer-name', 'id' => $ids[0]], + 'outer consumer update', + ); + + $callbackFailure = new RuntimeException('consumer savepoint callback failure.'); + $thrown = null; + + try { + $savepointRunner->run(function () use ($pdo, $table, $ids, $callbackFailure): never { + executeStatement( + $pdo->prepare( + 'UPDATE ' . $table . ' SET name = :name WHERE id = :id', + ), + ['name' => 'rolled-back-name', 'id' => $ids[0]], + 'isolated consumer update', + ); + + throw $callbackFailure; + }); + } catch (Throwable $throwable) { + $thrown = $throwable; + } + + expectSame($callbackFailure, $thrown, 'original savepoint callback Throwable'); + expectTrue($pdo->inTransaction(), 'caller-owned transaction remains active'); + expectSame( + 'outer-name', + readScalar($pdo, 'SELECT name FROM ' . $table . ' WHERE id = ' . (int) $ids[0]), + 'savepoint rollback state', + ); + + $savepointRunner->run( + fn (): bool => $ordering->moveWithinScope($pdo, $orderingConfig, 'consumer', $ids[2], 1), + ); + $pdo->commit(); + } finally { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + } + + expectSame( + 'outer-name', + readScalar($pdo, 'SELECT name FROM ' . $table . ' WHERE id = ' . (int) $ids[0]), + 'committed outer transaction state', + ); + + $paginationConfig = new PaginationConfig( + sortWhitelist: new SortWhitelist([ + 'order' => 'display_order', + 'id' => 'id', + ]), + defaultSortBy: 'order', + defaultSortDirection: SortDirectionEnum::ASC, + tieBreakerSortBy: 'id', + tieBreakerDirection: SortDirectionEnum::ASC, + defaultPerPage: 10, + minPerPage: 1, + maxPerPage: 10, + ); + $paginationQuery = new PdoPaginationQueryDescriptor( + totalSql: 'SELECT COUNT(*) AS total_count FROM ' . $table . ' WHERE scope_key = :total_scope', + totalParams: ['total_scope' => 'consumer'], + filteredCountSql: 'SELECT COUNT(*) AS filtered_count FROM ' . $table . ' WHERE scope_key = :filtered_scope AND deleted_at IS NULL', + filteredCountParams: ['filtered_scope' => 'consumer'], + dataSql: 'SELECT id, name, display_order FROM ' . $table . ' WHERE scope_key = :data_scope AND deleted_at IS NULL', + dataParams: ['data_scope' => 'consumer'], + ); + $result = (new PdoPaginator())->paginate( + pdo: $pdo, + query: $paginationQuery, + request: new PageRequest(page: 1, perPage: 10, sortBy: 'order', sortDirection: 'ASC'), + config: $paginationConfig, + mapper: static fn (array $row): array => $row, + ); + + expectSame(3, $result->total, 'consumer total count'); + expectSame(3, $result->filtered, 'consumer filtered count'); + expectSame(3, count($result->data), 'consumer page size'); + $first = $result->data[0] ?? null; + if (! is_array($first)) { + throw new RuntimeException('Consumer pagination returned an invalid first row.'); + } + $firstId = $first['id'] ?? null; + if (! is_int($firstId) && ! is_string($firstId)) { + throw new RuntimeException('Consumer pagination returned an invalid row identity.'); + } + if (is_string($firstId) && ! ctype_digit($firstId)) { + throw new RuntimeException('Consumer pagination returned a non-integer row identity.'); + } + expectSame($ids[2], (int) $firstId, 'consumer ordering result'); + + echo 'Consumer run ' . $runLabel . " passed.\n"; + } finally { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + if ($tableCreated) { + $pdo->exec('DROP TABLE IF EXISTS ' . $table); + } + removeDirectory($consumerRoot); + } +} + +function createPdo(): PDO +{ + $dsn = requiredEnvironment('PERSISTENCE_TEST_MYSQL_DSN'); + $user = requiredEnvironment('PERSISTENCE_TEST_MYSQL_USER'); + $password = getenv('PERSISTENCE_TEST_MYSQL_PASSWORD'); + + if (! is_string($password)) { + $password = ''; + } + + $pdo = new PDO($dsn, $user, $password, [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]); + + if ($pdo->getAttribute(PDO::ATTR_DRIVER_NAME) !== 'mysql') { + throw new RuntimeException('Consumer verification requires the MySQL PDO driver.'); + } + + return $pdo; +} + +/** + * @return non-empty-string + */ +function requiredEnvironment(string $name): string +{ + $value = getenv($name); + + if (! is_string($value) || $value === '') { + throw new RuntimeException('Missing required environment variable ' . $name . '.'); + } + + return $value; +} + +/** + * @return non-empty-string + */ +function composerBinary(): string +{ + $value = getenv('COMPOSER_BIN'); + + return is_string($value) && $value !== '' ? $value : 'composer'; +} + +/** + * @param list $command + */ +function runCommand(array $command, string $workingDirectory): void +{ + $pipes = []; + $process = proc_open( + $command, + [ + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ], + $pipes, + $workingDirectory, + ); + + if (! is_resource($process)) { + throw new RuntimeException('Unable to start command: ' . implode(' ', $command)); + } + + $stdout = stream_get_contents($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[1]); + fclose($pipes[2]); + $exitCode = proc_close($process); + + if (is_string($stdout) && $stdout !== '') { + echo $stdout; + } + + if ($exitCode !== 0) { + throw new RuntimeException( + 'Command failed with exit code ' . $exitCode . ': ' . implode(' ', $command) + . (is_string($stderr) && $stderr !== '' ? PHP_EOL . $stderr : ''), + ); + } +} + +function requireStatement(PDOStatement|false $statement, string $operation): PDOStatement +{ + if (! $statement instanceof PDOStatement) { + throw new RuntimeException('Unable to prepare ' . $operation . '.'); + } + + return $statement; +} + +/** + * @param array $parameters + */ +function executeStatement(PDOStatement|false $statement, array $parameters, string $operation): void +{ + requireStatement($statement, $operation)->execute($parameters); +} + +function readScalar(PDO $pdo, string $sql): mixed +{ + $statement = $pdo->query($sql); + if (! $statement instanceof PDOStatement) { + throw new RuntimeException('Unable to query consumer state.'); + } + + return $statement->fetchColumn(); +} + +function expectSame(mixed $expected, mixed $actual, string $description): void +{ + if ($expected !== $actual) { + throw new RuntimeException('Unexpected ' . $description . '.'); + } +} + +function expectTrue(bool $actual, string $description): void +{ + if (! $actual) { + throw new RuntimeException('Expected ' . $description . '.'); + } +} + +function removeDirectory(string $directory): void +{ + if (! is_dir($directory)) { + return; + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($directory, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::CHILD_FIRST, + ); + + foreach ($iterator as $item) { + if (! $item instanceof SplFileInfo) { + throw new RuntimeException('Unable to inspect the consumer root.'); + } + + if ($item->isDir()) { + rmdir($item->getPathname()); + } else { + unlink($item->getPathname()); + } + } + + rmdir($directory); +} diff --git a/tests/Fixtures/MySql/create_global_ordering_table.sql b/tests/Fixtures/MySql/create_global_ordering_table.sql index 2639db5..781a170 100644 --- a/tests/Fixtures/MySql/create_global_ordering_table.sql +++ b/tests/Fixtures/MySql/create_global_ordering_table.sql @@ -1,8 +1,10 @@ +-- Consumer-owned fixture table for global ordering. +-- No Host foreign keys or joins; soft-deleted rows are excluded by the package. CREATE TABLE `maa_persistence_test_global_ordering` ( - `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `display_order` INT NOT NULL, - `deleted_at` DATETIME NULL DEFAULT NULL, - `label` VARCHAR(191) NOT NULL, + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', + `display_order` INT NOT NULL COMMENT 'Mutable ordering position.', + `deleted_at` DATETIME NULL DEFAULT NULL COMMENT 'Optional soft-delete timestamp.', + `label` VARCHAR(191) NOT NULL COMMENT 'Fixture row label.', PRIMARY KEY (`id`), KEY `idx_maa_persistence_test_global_ordering_deleted_at` (`deleted_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci diff --git a/tests/Fixtures/MySql/create_pagination_items_table.sql b/tests/Fixtures/MySql/create_pagination_items_table.sql index efa1604..71456cb 100644 --- a/tests/Fixtures/MySql/create_pagination_items_table.sql +++ b/tests/Fixtures/MySql/create_pagination_items_table.sql @@ -1,13 +1,15 @@ +-- Consumer-owned fixture table for pagination. +-- Host identity is supplied as tenant_id; this fixture adds no Host FK. CREATE TABLE `maa_persistence_test_pagination_items` ( - `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, - `tenant_id` INT UNSIGNED NOT NULL, - `category` VARCHAR(32) NOT NULL, - `name` VARCHAR(128) NOT NULL, - `score` INT NOT NULL, - `is_active` TINYINT(1) NOT NULL, - `nullable_code` VARCHAR(32) NULL, - `created_at` DATETIME(6) NOT NULL, - `deleted_at` DATETIME(6) NULL, + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', + `tenant_id` INT UNSIGNED NOT NULL COMMENT 'Host-provided tenant identity; no FK.', + `category` VARCHAR(32) NOT NULL COMMENT 'Fixture filter category.', + `name` VARCHAR(128) NOT NULL COMMENT 'Fixture display name.', + `score` INT NOT NULL COMMENT 'Fixture sortable score.', + `is_active` TINYINT(1) NOT NULL COMMENT 'Fixture visibility flag.', + `nullable_code` VARCHAR(32) NULL COMMENT 'Fixture nullable filter value.', + `created_at` DATETIME(6) NOT NULL COMMENT 'Fixture creation timestamp.', + `deleted_at` DATETIME(6) NULL COMMENT 'Optional soft-delete timestamp.', PRIMARY KEY (`id`), KEY `idx_pagination_base` (`tenant_id`, `deleted_at`, `id`), KEY `idx_pagination_filter` (`tenant_id`, `category`, `is_active`, `nullable_code`, `score`, `id`), diff --git a/tests/Fixtures/MySql/create_scoped_ordering_table.sql b/tests/Fixtures/MySql/create_scoped_ordering_table.sql index 81cdad5..8795eb3 100644 --- a/tests/Fixtures/MySql/create_scoped_ordering_table.sql +++ b/tests/Fixtures/MySql/create_scoped_ordering_table.sql @@ -1,10 +1,12 @@ +-- Consumer-owned fixture table for scoped ordering. +-- NULL scope is an exact scope; it is not a wildcard or fallback. CREATE TABLE `maa_persistence_test_scoped_ordering` ( - `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `scope_key` VARCHAR(191) NULL DEFAULT NULL, - `display_order` INT NOT NULL, - `deleted_at` DATETIME NULL DEFAULT NULL, - `updated_at` DATETIME NULL DEFAULT NULL, - `label` VARCHAR(191) NOT NULL, + `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', + `scope_key` VARCHAR(191) NULL DEFAULT NULL COMMENT 'Exact consumer-owned scope key.', + `display_order` INT NOT NULL COMMENT 'Mutable ordering position.', + `deleted_at` DATETIME NULL DEFAULT NULL COMMENT 'Optional soft-delete timestamp.', + `updated_at` DATETIME NULL DEFAULT NULL COMMENT 'Optional target mutation timestamp.', + `label` VARCHAR(191) NOT NULL COMMENT 'Fixture row label.', PRIMARY KEY (`id`), KEY `idx_maa_persistence_test_scoped_ordering_scope_order` (`scope_key`, `display_order`), KEY `idx_maa_persistence_test_scoped_ordering_deleted_at` (`deleted_at`) diff --git a/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql b/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql index 47fdb0c..a930395 100644 --- a/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql +++ b/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql @@ -1,5 +1,7 @@ +-- Consumer-owned fixture table for transaction/savepoint integration. +-- The table is created and removed by the test suite; no Host tables are used. CREATE TABLE `maa_persistence_test_transaction_savepoint_items` ( - `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, - `payload` VARCHAR(128) NOT NULL, + `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', + `payload` VARCHAR(128) NOT NULL COMMENT 'Fixture transaction payload.', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; From 54fcec045abffe1349774040d14119e2440a2da8 Mon Sep 17 00:00:00 2001 From: Mohamed Abdulalim Date: Thu, 17 Sep 2026 17:14:45 +0300 Subject: [PATCH 2/3] fix: type consumer harness process pipes --- tests/Consumer/run.php | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/tests/Consumer/run.php b/tests/Consumer/run.php index 1802d9e..9e54362 100644 --- a/tests/Consumer/run.php +++ b/tests/Consumer/run.php @@ -28,7 +28,7 @@ echo "Consumer Verification Harness passed: two clean Composer consumer and MySQL runs completed.\n"; /** - * @param non-empty-string $repositoryRoot + * @param string $repositoryRoot * @param string $runLabel */ function runSingleConsumerVerification(string $repositoryRoot, string $runLabel): void @@ -332,10 +332,11 @@ function runCommand(array $command, string $workingDirectory): void throw new RuntimeException('Unable to start command: ' . implode(' ', $command)); } - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - fclose($pipes[1]); - fclose($pipes[2]); + $processPipes = requireProcessPipes($pipes, $process, $command); + $stdout = stream_get_contents($processPipes[1]); + $stderr = stream_get_contents($processPipes[2]); + fclose($processPipes[1]); + fclose($processPipes[2]); $exitCode = proc_close($process); if (is_string($stdout) && $stdout !== '') { @@ -350,6 +351,32 @@ function runCommand(array $command, string $workingDirectory): void } } +/** + * @param mixed $pipes + * @param list $command + * @return array{1: resource, 2: resource} + */ +function requireProcessPipes(mixed $pipes, mixed $process, array $command): array +{ + if (! is_array($pipes) || ! isset($pipes[1], $pipes[2])) { + if (is_resource($process)) { + proc_close($process); + } + throw new RuntimeException('Command pipes were not opened: ' . implode(' ', $command)); + } + + $stdoutPipe = $pipes[1]; + $stderrPipe = $pipes[2]; + if (! is_resource($stdoutPipe) || ! is_resource($stderrPipe)) { + if (is_resource($process)) { + proc_close($process); + } + throw new RuntimeException('Command pipes were not opened: ' . implode(' ', $command)); + } + + return [1 => $stdoutPipe, 2 => $stderrPipe]; +} + function requireStatement(PDOStatement|false $statement, string $operation): PDOStatement { if (! $statement instanceof PDOStatement) { From 87669ab71e5739cf338309a2b3478da0a014e8be Mon Sep 17 00:00:00 2001 From: Mohamed Abdulalim <33574895+megyptm@users.noreply.github.com> Date: Fri, 18 Sep 2026 06:18:48 +0300 Subject: [PATCH 3/3] chore: finalize release-facing compliance wording (#29) --- .github/workflows/ci.yml | 3 --- AGENTS.md | 2 +- CHANGELOG.md | 4 +--- PERSISTENCE_PACKAGE_REFERENCE.md | 10 ++++++---- schema/README.md | 2 +- tests/Fixtures/MySql/create_global_ordering_table.sql | 3 ++- tests/Fixtures/MySql/create_pagination_items_table.sql | 6 ++++-- tests/Fixtures/MySql/create_scoped_ordering_table.sql | 6 ++++-- .../MySql/create_transaction_savepoint_items_table.sql | 6 ++++-- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be03374..184b8e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,6 @@ name: CI on: pull_request: - branches: - - main - - codex/transaction-savepoint-orchestration-draft push: branches: - main diff --git a/AGENTS.md b/AGENTS.md index d1df92e..02b75dc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,7 +8,7 @@ ## قواعد خاصة بالمشروع -- هذه الحزمة مكتبة Composer مستقلة، framework-agnostic وhost-agnostic، وتستخدم PDO المباشر مع MySQL/MariaDB-compatible SQL. +- هذه الحزمة مكتبة Composer مستقلة، framework-agnostic وhost-agnostic، وتستخدم PDO المباشر مع SQL متوافق مع ملف MySQL/MariaDB. التحقق التشغيلي في هذا المستودع يتم على MySQL الحقيقي فقط، وMariaDB ليست مدخلة تحقق مستقلة في مصفوفة CI الحالية. - يجب الحفاظ على عقد v1.4.0 العام، بما في ذلك ملكية المعاملات، ودعم المعاملة الخارجية، ودلالات savepoint المعتمدة؛ لا يُجرى تغيير breaking public API. - اختبارات قاعدة البيانات تتطلب MySQL حقيقيًا؛ لا يجوز استخدام SQLite أو mocks لإثبات سلوك persistence الحقيقي. - لا يُتتبّع composer.lock، ولا يُضاف حقل Composer باسم version، ولا تُنشأ Tag أو GitHub Release ضمن أعمال هذا المستودع ما لم يصدر تصريح صريح بذلك. diff --git a/CHANGELOG.md b/CHANGELOG.md index 3435245..cafa528 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [1.4.0] - Stable Release Preparation (planned 2026-09-17) - -> **Release state:** Stable Release Preparation. The `v1.4.0` tag and release are not published; publication awaits owner approval. +## [1.4.0] - 2026-09-18 ### Added * Transaction savepoint orchestration capability (`SavepointTransactionRunnerInterface`, `PdoSavepointTransactionRunner`) for safe, operation-local rollback boundaries within caller-owned PDO transactions. diff --git a/PERSISTENCE_PACKAGE_REFERENCE.md b/PERSISTENCE_PACKAGE_REFERENCE.md index 746f118..9ba632d 100644 --- a/PERSISTENCE_PACKAGE_REFERENCE.md +++ b/PERSISTENCE_PACKAGE_REFERENCE.md @@ -19,9 +19,11 @@ The package owns the reusable PDO ordering, transaction, savepoint, and pagination behavior, but it does not own a persistent business entity or a production table. Consumers provide their own trusted table and column identifiers, SQL, scopes, and mapping. The package does not create migrations, -foreign keys, or joins to Host tables. MySQL/MariaDB-compatible SQL through -direct PDO is the supported persistence boundary; the package-level schema -notes are in [schema/README.md](schema/README.md). +foreign keys, or joins to Host tables. The persistence profile is +MySQL/MariaDB-compatible SQL through direct PDO. Repository integration and +Consumer verification run against real MySQL, with MySQL 8.4.10 as the current +CI baseline; MariaDB is not independently verified by the current CI matrix. +The package-level schema notes are in [schema/README.md](schema/README.md). ## Public API Inventory @@ -411,7 +413,7 @@ Renaming the marker MAY be reconsidered only as part of a separately approved, m * `PERSISTENCE_TEST_MYSQL_USER` * `PERSISTENCE_TEST_MYSQL_PASSWORD` * **Test Database Isolation**: Assumes isolated test tables and requires local package privileges (trigger/table cleanup). Tests include trigger failure injection. -* **Current CI MySQL Baseline**: 8.4.10. +* **Current CI MySQL Baseline**: MySQL 8.4.10. MariaDB is not independently verified by the current CI matrix. * **Consumer Verification Harness**: `composer test:consumer` installs the package into a separate non-symlinked Composer root and verifies a public ordering, savepoint, and pagination workflow against real MySQL twice from diff --git a/schema/README.md b/schema/README.md index b3e05aa..061d977 100644 --- a/schema/README.md +++ b/schema/README.md @@ -4,4 +4,4 @@ توجد مخططات MySQL المعزولة الخاصة باختبارات المستودع تحت [tests/Fixtures/MySql/](../tests/Fixtures/MySql/)، كما ينشئ Consumer Verification Harness جدوله المعزول مؤقتًا داخل قاعدة الاختبار ثم يحذفه. هذه الملفات ليست جداول Host ولا تعتمد على أي schema خارجي. -الحد التعاقدي لقاعدة البيانات هو MySQL/MariaDB-compatible SQL عبر PDO المباشر. لا تستخدم الحزمة ORM أو query builder خارجيًا، ولا تنشئ جداول عامة مثل logs أو event_logs، ولا تضيف مفاتيح خارجية أو JOINs إلى جداول Host. +الحد التعاقدي لقاعدة البيانات هو SQL متوافق مع ملف MySQL/MariaDB عبر PDO المباشر. التحقق الفعلي لهذه الحزمة واختبارات Consumer يتم على MySQL، وخط CI الحالي يستخدم MySQL 8.4.10؛ لم تُتحقق MariaDB بصورة مستقلة ضمن مصفوفة CI الحالية. لا تستخدم الحزمة ORM أو query builder خارجيًا، ولا تنشئ جداول عامة مثل logs أو event_logs، ولا تضيف مفاتيح خارجية أو JOINs إلى جداول Host. diff --git a/tests/Fixtures/MySql/create_global_ordering_table.sql b/tests/Fixtures/MySql/create_global_ordering_table.sql index 781a170..f714bfc 100644 --- a/tests/Fixtures/MySql/create_global_ordering_table.sql +++ b/tests/Fixtures/MySql/create_global_ordering_table.sql @@ -1,4 +1,5 @@ --- Consumer-owned fixture table for global ordering. +-- Test-only, consumer-owned fixture; the integration suite creates and drops it. +-- Global ordering uses display_order; no additional UNIQUE constraint is declared. -- No Host foreign keys or joins; soft-deleted rows are excluded by the package. CREATE TABLE `maa_persistence_test_global_ordering` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', diff --git a/tests/Fixtures/MySql/create_pagination_items_table.sql b/tests/Fixtures/MySql/create_pagination_items_table.sql index 71456cb..5d6f6eb 100644 --- a/tests/Fixtures/MySql/create_pagination_items_table.sql +++ b/tests/Fixtures/MySql/create_pagination_items_table.sql @@ -1,5 +1,7 @@ --- Consumer-owned fixture table for pagination. --- Host identity is supplied as tenant_id; this fixture adds no Host FK. +-- Test-only, consumer-owned fixture; the integration suite creates and drops it. +-- Pagination filters deleted_at and sorts through whitelisted fields with id as +-- the deterministic tie-breaker; no additional UNIQUE constraint is declared. +-- Host identity is supplied as tenant_id; this fixture adds no Host FK or JOIN. CREATE TABLE `maa_persistence_test_pagination_items` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', `tenant_id` INT UNSIGNED NOT NULL COMMENT 'Host-provided tenant identity; no FK.', diff --git a/tests/Fixtures/MySql/create_scoped_ordering_table.sql b/tests/Fixtures/MySql/create_scoped_ordering_table.sql index 8795eb3..4293d1b 100644 --- a/tests/Fixtures/MySql/create_scoped_ordering_table.sql +++ b/tests/Fixtures/MySql/create_scoped_ordering_table.sql @@ -1,5 +1,7 @@ --- Consumer-owned fixture table for scoped ordering. --- NULL scope is an exact scope; it is not a wildcard or fallback. +-- Test-only, consumer-owned fixture; the integration suite creates and drops it. +-- Scoped ordering uses display_order within the exact scope_key; no additional +-- UNIQUE constraint is declared, and NULL scope is exact rather than a wildcard. +-- No Host foreign keys or joins; soft-deleted rows are excluded by the package. CREATE TABLE `maa_persistence_test_scoped_ordering` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', `scope_key` VARCHAR(191) NULL DEFAULT NULL COMMENT 'Exact consumer-owned scope key.', diff --git a/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql b/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql index a930395..8358d2f 100644 --- a/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql +++ b/tests/Fixtures/MySql/create_transaction_savepoint_items_table.sql @@ -1,5 +1,7 @@ --- Consumer-owned fixture table for transaction/savepoint integration. --- The table is created and removed by the test suite; no Host tables are used. +-- Test-only, consumer-owned fixture; the integration suite creates and drops it. +-- Transaction/savepoint tests use only the primary-key identity; no additional +-- UNIQUE constraint is declared, and no ordering or soft-delete policy applies. +-- No Host foreign keys or joins; no Host tables are used. CREATE TABLE `maa_persistence_test_transaction_savepoint_items` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Fixture row identity.', `payload` VARCHAR(128) NOT NULL COMMENT 'Fixture transaction payload.',