Skip to content

refactor(organization-sync): split the related contact and organisation entity sync, drop unused organisation service parameters - #1405

Merged
rubenvdlinde merged 7 commits into
developmentfrom
refactor/sig-org-sync-related-contacts
Nov 3, 2026
Merged

rubenvdlinde merged 7 commits into
developmentfrom
refactor/sig-org-sync-related-contacts

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

REVIEW (organisation and contact ownership): held for a reviewer. Lane SQ3, SIG unit interfacing in stackiq.

Three refactors, each behind a golden recorded on the old code:

1. Related contact person sync (OrganizationSyncService::processRelatedContactPersons)

Drops its unused organisation object parameter (235 LOC / 3 params to 55 LOC / 2) and hands the work to findRelatedContacts, contactsFromOrganisationList, fetchListedContact, processRelatedContact and completeRelatedContact, each with at most two parameters (the sync run array, stats held by reference, the pattern this class already uses). Golden OrganizationSyncRelatedContactsGoldenTest, 13 cases; mutants 14 of 14 killed (organisation field never set or set wrong, retry keeping the old field, refetch ignored, stats copied instead of shared, and more).

2. Ensuring the organisation entity (ensureOrganisationEntity)

193 LOC / 3 params to 41 LOC / 2. It takes the organisatie object and one run array (stats by reference, and sendEmails passed explicitly at every call site instead of a default) and hands the work to fullOrganisationObject, refreshOrganisationEntity, adoptOrganisationEntityBySlug, createOrganisationEntity, mailOrganisation and makeEntityOwner. The public ensureOrganisationEntityPublic keeps its signature. Golden OrganizationSyncEntityGoldenTest, 16 cases (in sync, (de)activated with and without mail, adopted by slug, created, creation and save failures); mutants 17 of 18 killed. The survivor was the old sendEmails default, which is why every caller now passes it explicitly. The OrganisationMapper stub gains findBySlug, as on OpenRegister.

3. Organisation create and update in OpenRegister (StackiqService)

createOrganisationInOpenRegisterInternal (217 LOC) and updateOrganisationInOpenRegister drop an OrganisationService parameter neither reads; the public create wrapper still fetches it first, so a missing OpenRegister fails at the same point. Golden StackiqServiceOrganisationSyncGoldenTest, 10 cases through syncOrganizationWithOpenRegister and createOrganisationInOpenRegister; mutants 2 of 2 killed.

Finding for the reviewer, not changed here: creating an organisation can never succeed against current OpenRegister. The signed-in path calls OrganisationMapper::createWithUuid, which OpenRegister does not have, and the anonymous path saves the entity and then reads getUID() on the absent user. Both escape as Error, past the callers' catch (\Exception). The golden records this as it is today. A fix (save the entity on both paths, return after the anonymous save) needs a decision on owner and users, so it belongs in its own PR.

Numbers (PHP, lizard): with the batch PR and the koppelingen PR params >=3 goes from 18.74% to 14.97% (limit 15%); size >60 35.13% to 32.53%, McCabe >25 3.50% to 2.72%.

Debt fixed: class @spec tag on OrganizationSyncService (phpcs warning).

Verification: goldens plain re-run green on old and new; mutants as above; development merged in; touched tests (196 organisation and contact tests, 128 StackiqService and Organisation tests) green; full unit suite under pcov --fail-on-risky on this branch combined with the koppelingen PR: 1591 tests, exit 0 (before the last development merge); on the final tree with the batch PR and development merged: 1631 tests, exit 0, lint 0 errors, gates 37 of 37 applicable 0 FAIL; phpcs, phpstan, psalm, phpmd clean on the touched files.

This PR was prepared with AI assistance (Claude Code).

…to find, fetch and process steps

processRelatedContactPersons drops its unused organisation object parameter and
hands the work to findRelatedContacts, contactsFromOrganisationList,
fetchListedContact, processRelatedContact and completeRelatedContact, each with
at most two parameters (the sync run array, stats held by reference). Lookups,
saves, log lines and stats are unchanged (golden of the previous commit).

Assisted-by: ClaudeCode:claude-opus-5-5
…of an organisatie object

The OrganisationMapper stub gains findBySlug, as on OpenRegister's mapper.

Assisted-by: ClaudeCode:claude-opus-5-5
…nto refresh, adopt-by-slug and create steps

ensureOrganisationEntity takes the organisatie object and one run array (stats
held by reference, and an explicit sendEmails at every call site) and hands
the work to fullOrganisationObject, refreshOrganisationEntity,
adoptOrganisationEntityBySlug, createOrganisationEntity, mailOrganisation and
makeEntityOwner. The public wrapper keeps its signature. Lookups, saves,
mails, log lines and stats are unchanged (golden of the previous commit).

Assisted-by: ClaudeCode:claude-opus-5-5
… it behaves today

Creating an organisation escapes with an Error on both paths: the signed-in
path calls OrganisationMapper::createWithUuid, which OpenRegister does not
have, and the anonymous path saves and then reads the absent user.

Assisted-by: ClaudeCode:claude-opus-5-5
…m the OpenRegister create and update steps

Neither createOrganisationInOpenRegisterInternal nor updateOrganisationInOpenRegister
reads the OrganisationService it was handed. The public create wrapper still
fetches it first, so a missing OpenRegister fails at the same point. The golden
masks mock and anonymous class names, which depend on test order; it was
re-recorded on the code before this commit.

Assisted-by: ClaudeCode:claude-opus-5-5
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 25e103d

Check PHP Vue Security License Tests
lint ✅
phpcs ✅
phpmd ✅
psalm ✅
phpstan ✅
phpmetrics ✅
eslint ✅
stylelint ✅
build ✅
check-manifest ✅
check-vue-demi ✅
test-l10n ✅
format ❌
check-schema-l10n ❌
check-l10n-js ✅
composer ❌ ✅ 127/127
npm ❌ ✅ 807/807
app:check-code ⏭️
info.xml ✅
REUSE ❌
lockfile sync ✅
PHPUnit ❌ 1565/1571 · 24 skipped
Newman ⏭️
Playwright ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development.
Hydra gates ❌

Quality workflow — 2026-11-03 17:03 UTC

Download the full PDF report from the workflow artifacts.

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.

1 participant