feat(spec): implement spec (#157)#158
Conversation
Builder was meant to emit every new PHP file with EUPL-1.2 headers (see images/builder/CLAUDE.md line 324). On this branch 18 files shipped without. The orchestrator's quality recheck (`spdx-headers` stage via run-quality.sh) fails hard on any lib/**.php missing the SPDX-License-Identifier, which escalated this issue back to needs-input on every retry cycle. Hand-adding the headers here unblocks the recheck. A follow-up change will strengthen the builder prompt so the first-pass output always includes the headers.
PHPCS PEAR.Commenting.FileComment treats the first /** block as the file comment and requires @author and @license tags. The split two-docblock pattern (SPDX /** block + file /** block) caused all 26 lib/*.php files to fail with "Missing @author/license tag in file comment". Converting the SPDX block opener from /** to /* makes it a non-docblock comment; PHPCS then treats the second /** block (which already has @author and @license) as the file comment — both gates green. SPDX-License-Identifier strings are preserved in all files (spdx-headers gate unaffected). Co-fixed-by: Juan Claude van Damme <hydra-reviewer@conduction.nl>
Addresses the WARNING + SUGGESTION findings on PR #111: - Register MotionService, VotingService, OriPublicationService, MotionController, VotingController explicitly in Application.php. Matches the existing per-service registration pattern (MinutesController, DecisionController, OverdueActionItemsJob). Auto-wiring worked but was inconsistent with the file's own style — reviewer flagged it; now fixed per tasks 1.4 and 2.4. - tasks.md 1.5 and 2.5 marked [ ] (incomplete) with reason. Tests exist but skip unconditionally in setUp() due to #90 (ObjectService stub/real-signature mismatch). The previous [x] claim was dishonest coverage — zero assertions ever ran. Will flip back to [x] once #90 lands and tests can unskip.
…ting feat: motion and voting lifecycle — p2-motion-and-voting (#72)
…ively (#157) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…157) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Quality Report — ConductionNL/decidesk @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 417/417 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ⏭️ |
Coverage: 0% (0/115 statements)
Quality workflow — 2026-05-08 21:20 UTC
Download the full PDF report from the workflow artifacts.
# Conflicts: # lib/AppInfo/Application.php
Code Review — Juan Claude van DammeResult: PASS (3 fixed, 0 unfixed, 0 blocking) What the PR doesAdds Fixes applied
Gate results
Out-of-scope inherited debt (informational — do NOT treat as blockers)
Consider opening cleanup PRs for the above. Reviewed by Juan Claude van Damme — Hydra Quality Stage 🤖 Changes Juan Claude van Damme applied
View full diff · 33 files changed, 22335 insertions(+), 46 deletions(-) |
| @@ -1,5 +1,4 @@ | |||
| <?php | |||
There was a problem hiding this comment.
[fixed: merge conflict resolved] Kept all DI registrations from both branches — HEAD's 11 services/controllers + origin/development's 5 services/controllers. All imports merged alphabetically.
| @@ -187,6 +220,22 @@ static function ($c): AnalyticsController { | |||
| return new AnalyticsController( | |||
There was a problem hiding this comment.
[fixed: DI constructor completeness] Added missing userSession and groupManager named parameters to AnalyticsController registration. AnalyticsController::__construct requires IUserSession + IGroupManager; these were omitted during conflict resolution and caught by Psalm/PHPStan.
| * @return ObjectEntity&MockObject | ||
| */ | ||
| private function buildMockEntity(string $lifecycle, string $domain = 'operations', ?string $chair = null): ObjectEntity&MockObject | ||
| private function buildMockEntity(string $lifecycle, string $domain='operations', ?string $chair=null): ObjectEntity&MockObject |
There was a problem hiding this comment.
[fixed: ADR-015 named parameters + PHPCS spacing] 17 violations: phpcbf auto-fixed 8 (equals-sign alignment, default-value spacing, blank-line); manually fixed 9 named-parameter violations — markTestSkipped('...') → markTestSkipped(message: '...'), buildMockEntity($x) → buildMockEntity(lifecycle: $x).
Quality Report — ConductionNL/decidesk @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| composer | ✅ | ✅ 100/100 | |||
| npm | ✅ | ✅ 417/417 | |||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ⏭️ |
Coverage: 0% (0/115 statements)
Quality workflow — 2026-05-08 21:32 UTC
Download the full PDF report from the workflow artifacts.
Security Review — Clyde BarcodeResult: PASS (10 fixed, 0 unfixed blocking) Fixes Applied[WARNING] Semantic-auth mismatch (gate-9) — 10 controller methods had
All fixes self-verified: Semgrep clean on touched files, unit tests 153/153 pass. Checks
Out-of-scope inherited debt (informational, non-blocking)
🤖 Changes Clyde Barcode applied
View full diff · 3 files changed, 1 insertion(+), 21 deletions(-) |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — annotation contradicted admin body check; Nextcloud router would skip admin enforcement while body still gated. Removed docblock annotation to match body semantics. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — generateDraft() body enforces admin via isAdmin(); annotation was lying to the router layer. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — transition() body enforces admin; annotation removed. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — generateALVDraft() body enforces admin; annotation removed. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — distributeALVMinutes() body enforces admin; annotation removed. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — extractActionItems() body enforces admin; annotation removed. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — saveExtractedActionItems() body enforces admin; annotation removed. |
|
📍 [fixed: removed @NoAdminRequired] Rule: ADR-016/gate-9 — submitForApproval() body enforces admin; annotation removed. |
|
📍 [fixed: #[NoAdminRequired] → #[AuthorizedAdminSetting] + removed @NoAdminRequired docblock] Rule: ADR-016/gate-9 — create() calls requireAdmin() in body; swapped to AuthorizedAdminSetting mirroring sibling load() method. |
|
📍 [fixed: removed stale @NoAdminRequired docblock] Rule: ADR-016/gate-9 — load() PHP 8 attribute was already #[AuthorizedAdminSetting]; stale docblock annotation was the mismatch source. |
Closes #157
Summary
Auto-generated draft PR for OpenSpec change
spec.The Hydra builder ran the spec but could not run
gh pr createitself(Phase D+E credential strip — Claude has no
GH_TOKENby design).The entrypoint detected commits on the feature branch with no PR and
created this draft so the reviewer + security + applier can proceed.
Spec Reference
/spec//spec/proposal.md/spec/design.md/spec/tasks.mdCommits on this branch
Files changed
lib/Lifecycle/MeetingTransitionGuard.phplib/Service/MeetingService.phpopenspec/changes/spec/design.mdopenspec/changes/spec/proposal.mdopenspec/changes/spec/tasks.mdtests/Unit/Lifecycle/MeetingTransitionGuardTest.phptests/Unit/Service/MeetingServiceTest.phpPR auto-created by Hydra builder entrypoint (
hydra_ensure_pr_exists)because Claude's session closed without running
gh pr create.Reviewer + applier follow as normal.