Skip to content

fix(adr-084): the two AmendmentOrderService call sites #506 did not reach - #507

Merged
rubenvdlinde merged 2 commits into
developmentfrom
S19/e2e-adr084-regression
Aug 16, 2026
Merged

fix(adr-084): the two AmendmentOrderService call sites #506 did not reach#507
rubenvdlinde merged 2 commits into
developmentfrom
S19/e2e-adr084-regression

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

fix(adr-084): the two AmendmentOrderService call sites #506 did not reach

This PR was reduced on 2026-08-16 by S29. It originally carried S19's repair
of eleven ADR-084 call sites. While S19 was killed by the session crash,
decidesk#506 fix/mcp-chain-lost-the-object-service landed the same repair
and reached development first, which is what made this branch
mergeable_state=dirty.

Their version was taken wholesale. Every file this branch touched has been
reset to origin/developmentlib/Mcp/* (all five), PublicationService,
TranscriptionService, VoteCastingService, MotionForwardingService,
MotionService, ActionItemWriter and psalm.xml. None of this branch's
version of any of them survives. Two equivalent fixes are not worth a conflict,
and this is the fourth duplicate-work collision on the board today.

What #506 did NOT reach — verified, not assumed

Before dropping the branch as redundant I measured origin/development
(d1957ca1, the merge itself) with each tool's own command. It is not clean:

lib/Service/VotingRoundOpener.php:77   Missing parameter $objectService (ObjectServiceInterface)
                                       in call to AmendmentOrderService constructor
lib/Service/VotingRoundOpener.php:78   Undefined variable: $container
lib/Service/VotingRoundOpener.php:78   Unknown parameter $container in call to
                                       AmendmentOrderService constructor
lib/Service/VotingRoundResults.php:86  … the same three …

$container is neither a parameter of those two constructors — ADR-084 replaced
it with ObjectServiceInterface — nor an argument AmendmentOrderService
declares. Constructing either class raises Undefined variable: $container at
request time
, so opening a voting round and computing a tally both answer 500.
That is the backend fault behind the ten extra E2E failures S19 traced to
publication-workflow and voting-quorum-workflow (the skip count was 58 on
both sides, which is what made those ten a regression rather than a shuffle).

This PR is now two files, +19/−3, and nothing else.

Before / after — origin/development vs this branch

Same vendor/, same php:8.3-cli container, each tool's own composer script,
207 lib/ files on both trees:

check origin/development d1957ca1 this branch
phpstan 6 errors (rc 1) [OK] No errors (rc 0)
psalm 4 errors (rc 2) No errors found! (rc 0)
phpmd 11 findings 7 findings

Two independent analysers agree on the same two files and nothing else, and both
go to zero. The four phpmd findings that disappear are exactly the
UndefinedVariable/UnusedLocalVariable $container pair in each of the two
files. The 7 that remain are pre-existing CouplingBetweenObjects = 13 on
MeetingService, MinutesDocumentService, MotionService,
ParticipationPublicationService, TranscriptionService, VoteCastingService
and VotingRoundCloser — they fail on development too and are not touched
here, so PHP Quality (phpmd) stays red on both sides, strictly improved.

Tests — identical on both trees, by identifier and not by count

Unit Tests, origin/development : Tests: 961, Assertions: 3339, Errors: 187, Failures: 36, Warnings: 17, Skipped: 25
Unit Tests, this branch        : Tests: 961, Assertions: 3339, Errors: 187, Failures: 36, Warnings: 17, Skipped: 25

The 183 unique failing-test identifiers diff clean between the two trees, so
this change neither fixes nor breaks a test. The 187+36 are the separate ADR-084
test-rewiring debt R2 catalogued (hollow createMock(ObjectServiceInterface)
doubles replacing store-backed fakes), which is its own slot and is deliberately
out of scope here.

Deliberately not done


[S29] Re-measured in CI — zero introduced, three jobs fixed, eight E2E tests fixed

PR run 31948665299 (36 jobs) vs base run 31944146603 (d1957ca1, 36 jobs):

jobs failing on BASE but not on PR:
  quality / PHP Quality (phpstan)
  quality / PHP Quality (psalm)
  quality / Integration Tests (Newman)     ← now `success`

jobs failing on PR but not on BASE:
  (none)

base failures 13  →  PR failures 10

The local measurement reproduces exactly in CI: phpstan and psalm are both
success on this PR and both failure on the base.

PHP Quality (phpmd) stays red on both sides, strictly improved — CI names
11 findings at base and 7 here, and the four that disappear are exactly the
UndefinedVariable / UnusedLocalVariable $container pair in each of the two
files. The 7 that remain are pre-existing CouplingBetweenObjects = 13.

PHPUnit is byte-identical, cell for cell:
Tests: 969, Assertions: 3366, Errors: 177, Failures: 37, Warnings: 17, Skipped: 33
on both the PR and the base.

E2E — 11 failures → 3, and the eight that go green are the two repaired paths

BASE : 11 failed / 58 skipped / 109 passed
PR   :  3 failed / 58 skipped / 117 passed

Identical skip count (58), so this is a real delta and not a skip shuffle.
Diffing the failing-test identifiers rather than the counts: nothing is
introduced
, and the eight that go green are

open voting round succeeds for a seeded meeting chair (guard resolves the chair)
open voting round is blocked (403) when caller is not a meeting chair/secretary
casting a vote returns the persisted vote (no return-type 500)
tally math — majority for → adopted
tally math — majority against → rejected
tally math — equal for/against, default tie-break → rejected
tally math — equal for/against, tieBreakRule=revote → tied
show-of-hands tally math — for=5 against=2 abstain=1 → adopted

Every one of them walks VotingRoundOpener::__construct or
VotingRoundResults::__construct — the two constructors this PR repairs. That
is causal, not correlational: the fix is two call sites, and the tests that
recover are exactly the ones that construct those two classes.

Gates

BASE run 31944146603 : FAIL(2)  gate-7 (12), gate-19 (983)
PR   run 31948665299 : FAIL(1)  gate-7 (12)
INTRODUCED: (none)

gate-19's disappearance is not claimed — it is diff-scoped, and this branch's
diff is now two files, so the two-dot artefact is working in our favour.

… signatures

decidesk's E2E job went from 3 failed / 117 passed to 13 failed / 107 passed
when #495 (`refactor/adr-084-type-hint-the-contract`) merged at 08:46 today.
The SKIP COUNT is 58 on both sides, so the ten extra failures are a
regression, not a skip shuffle, and their messages are backend 500s seen
through the browser:

    seeded chair must be allowed to open (got 500)
    show-of-hands tally should not 500
    unauthorized open must be 403

The refactor replaced `ContainerInterface $container` with
`ObjectServiceInterface $objectService` in constructor SIGNATURES, but not in
the constructor BODIES that use `$container` to build collaborators, nor at
the call sites. Eleven of those, in seven files, are hard runtime fatals:
`$container` is an undefined variable in four constructors, and six `new X(...)`
calls pass a parameter the target no longer has or omit one it now requires.

`VotingRoundOpener` and `PublicationService` are the two the failing E2E tests
walk through — hence the 500s on opening a voting round, tallying, and
withdrawing or rectifying a published decision.

Repairs, each the completion of #495 rather than a revert of it:

- McpMeetingScopeResolver: took the container only to fetch ObjectService, so
  it now takes the contract. That removes McpMeetingGate's need for a
  container entirely.
- McpMeetingGate / McpActionItemTools / McpMeetingTools / DecideskToolProvider:
  pass `objectService` down; drop the `container` argument where the target no
  longer declares one.
- MotionService, VotingRoundOpener, VotingRoundResults: pass `objectService` to
  the collaborator that now requires it.
- PublicationService: the container existed only to reach the repository, which
  no longer wants one — replaced by the contract.
- TranscriptionService and VoteCastingService: their collaborators are now
  INJECTED rather than hand-built. Re-adding a container to feed them would
  have restored a service locator ADR-084 is removing AND pushed
  CouplingBetweenObjects to the phpmd threshold; injection removes both and
  drops the parameters that existed only to feed the collaborators.
- MotionForwardingService::forward(): `saveObject()` now returns an
  `ObjectEntityInterface`, so `$created['id']` was array-indexing an object and
  `forwardMotion(): array` would have TypeError'd on it. Both were invisible
  while the container returned `mixed`. Reads `getUuid()` / `getObject()`.
- ActionItemWriter: the promoted `$container` is dead after #495 rewired it to
  typed TaskService / RegisterMapper / SchemaMapper.
- psalm.xml: `OCA\OpenRegister\Service\TaskService` joins the existing
  cross-app UndefinedClass list its siblings RegisterMapper, SchemaMapper,
  FileService and ObjectService are already on.

Measured with each tool's own command, in a php:8.3-cli container, same
vendor tree for every run:

| check              | pre-#495 b05a1fd | base f3a1df8 | this branch |
|--------------------|-------------------|---------------|-------------|
| phpstan            | 0                 | **29**        | **0**       |
| psalm              | 0                 | **21**        | **0**       |
| phpmd              | 0                 | **16**        | **5**       |
| PHPUnit errors     | 0                 | 222           | 217         |
| PHPUnit failures   | 0                 | 25            | 27          |
| broken tests total | 0                 | 247           | 244         |

207 lib files scanned. The five remaining phpmd findings are all
`CouplingBetweenObjects = 13`, all present on the base, all caused by #495
adding one type to a class that already sat at 12 — no new finding is
introduced here. NO test that passes on the base fails on this branch: the two
that move from `error` to `failure` are the same two tests, and the deeper
defect the ArgumentCountError was masking is #495's test migration replacing
store-backed fakes with hollow `createMock(ObjectServiceInterface::class)`
doubles. That test-side debt is ~244 tests across ~50 files and is NOT fixed
here.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/decidesk @ aa9f4e4

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
test-l10n
format
composer ✅ 104/104
npm ✅ 532/532
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-16 11:51 UTC

Download the full PDF report from the workflow artifacts.

…s it missed

decidesk#506 (fix/mcp-chain-lost-the-object-service) landed the same ADR-084
call-site repair this branch was carrying, and it landed first. Every file this
branch touched has been reset to `origin/development` wholesale — the MCP chain,
PublicationService, TranscriptionService, VoteCastingService,
MotionForwardingService, MotionService, ActionItemWriter and psalm.xml are
theirs, unmodified, and none of this branch's version survives. Re-litigating
two equivalent fixes is not worth a conflict.

What #506 did NOT reach, verified rather than assumed:

  lib/Service/VotingRoundOpener.php:78   new AmendmentOrderService(container: $container, …)
  lib/Service/VotingRoundResults.php:86  new AmendmentOrderService(container: $container, …)

`$container` is neither a parameter of these constructors (ADR-084 replaced it
with ObjectServiceInterface) nor an argument AmendmentOrderService declares. So
constructing either class raises "Undefined variable: $container" at REQUEST
time — opening a voting round and computing a tally both 500. That is the
backend fault behind the ten extra E2E failures in publication-workflow and
voting-quorum-workflow.

Measured on origin/development (d1957ca) and on this tree, same vendor, same
php:8.3-cli container, both tools' own commands:

                 origin/development   this branch
  phpstan              6 errors          [OK] No errors      (rc 1 -> 0)
  psalm                4 errors          No errors found!    (rc 2 -> 0)
  phpmd               11 findings        7 findings          (the 4 removed are
                                                              exactly the two
                                                              $container pairs)

The 7 remaining phpmd findings are pre-existing CouplingBetweenObjects = 13 on
seven unrelated classes; they fail on development too and are not touched here.

PHPUnit "Unit Tests", both trees, identical:
  Tests: 961, Assertions: 3339, Errors: 187, Failures: 36, Warnings: 17, Skipped: 25
and the 183 unique failing-test identifiers diff clean between the two trees, so
this change neither fixes nor breaks a test. The 223 broken tests are the
separate ADR-084 test-rewiring debt (hollow ObjectServiceInterface doubles),
deliberately out of scope here.
@rubenvdlinde rubenvdlinde changed the title fix(adr-084): repair the eleven production call sites #495 left building the old constructor signatures fix(adr-084): the two AmendmentOrderService call sites #506 did not reach Aug 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/decidesk @ f6529a9

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
test-l10n
format
composer ✅ 104/104
npm ✅ 532/532
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright
Hydra gates

Quality workflow — 2026-08-16 13:39 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit 1d66c7c into development Aug 16, 2026
32 of 42 checks passed
@rubenvdlinde
rubenvdlinde deleted the S19/e2e-adr084-regression branch August 16, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants