toBeTrue(); return (string) file_get_contents($path); } function spec439ConstitutionUnrelatedBody(string $contents): string { $withoutSyncImpact = preg_replace( '/\A\R\R/s', '', $contents, ); $withoutBranchAmendment = preg_replace( '/### Spec-First Workflow\R.*?(?=\R## Quality Gates)/s', "### Spec-First Workflow\n[BRANCH-TOPOLOGY-AMENDMENT]\n", $withoutSyncImpact, ); $withoutAmendmentMetadata = preg_replace( '/^\*\*Version\*\*:.*$/m', '**Version**: [AMENDMENT-METADATA]', $withoutBranchAmendment, ); if (! is_string($withoutAmendmentMetadata)) { throw new RuntimeException('Unable to normalize Constitution amendment boundaries.'); } return $withoutAmendmentMetadata; } it('defines the three canonical branch roles and fail-closed scope routing', function (): void { $contents = spec439ConstitutionContents(); expect($contents) ->toContain( '`dev` is the repository-wide integration and promotion branch', '`platform-dev` is the integration branch for TenantPilot platform work', '`website-dev` is the integration branch for website work', 'Ordinary platform work MUST branch from, target, and diff against `platform-dev`', 'ordinary website work MUST branch from, target, and diff against `website-dev`', 'Cross-stream integration, promotion, and repository-governance work MUST be explicitly classified', 'Such work MAY target `dev`; the existence of `dev` alone MUST NOT imply that target.', 'Ambiguous or missing branch-family/ref resolution MUST fail closed.', '`origin/dev`, the wrong branch family, `HEAD~1`, or an arbitrary prior commit', ) ->not->toContain('- New work branches from `dev` using `feat/-`'); expect(substr_count($contents, '### Spec-First Workflow'))->toBe(1); }); it('keeps the major amendment metadata and Sync Impact report coherent', function (): void { $contents = spec439ConstitutionContents(); expect($contents) ->toContain( '- Version change: 2.16.0 -> 3.0.0', 'MAJOR because a normative universal branch rule is redefined', '- Added sections: None', '- Removed sections: None', '✅ `Agents.md`: directly conflicting universal `dev` instructions were', '✅ Specs 437 and 438: historical/completed or deferred context remains', '**Version**: 3.0.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-07-11', ) ->not->toContain('⏳ `Agents.md`'); expect(substr_count($contents, 'Sync Impact Report'))->toBe(1) ->and(substr_count($contents, '**Version**:'))->toBe(1); }); it('locks all Constitution content outside the authorized amendment boundaries', function (): void { $normalized = spec439ConstitutionUnrelatedBody(spec439ConstitutionContents()); expect(hash('sha256', $normalized)) ->toBe('9ea4019798f1854e7b513a8fe0bce2529a19207d0b16e81a08582e6b661b8e74'); }); it('keeps authoritative repository branch instructions synchronized', function (): void { $instructions = (string) file_get_contents(repo_path('Agents.md')); expect($instructions) ->toContain( '`dev`: repository-weite Integration und Promotion', '`platform-dev`: Integration für TenantPilot-Plattformarbeit', '`website-dev`: Integration für Website-Arbeit', 'Normale Plattformarbeit startet von und zielt auf `platform-dev`', 'Website-Arbeit startet von und zielt auf `website-dev`', 'Cross-Stream-, Promotion- und Repository-Governance-Arbeit muss ausdrücklich', '`dev` darf dabei ein', 'bewusstes Integrations-/Promotion-Ziel sein, aber kein stiller Fallback.', 'Für normale Plattformarbeit ist das `origin/platform-dev`', 'Website-Arbeit `origin/website-dev`', '`origin/dev` ist nur für ausdrücklich als', ) ->not->toContain( '- Default / Integrations-Branch: `dev`', 'Neue Arbeit läuft über Feature-Branches von `dev`', 'PR/MR: `feat/...` → `dev`', "git merge origin/dev\n", ); });