Skip to content

fix(archimate): link GEMMA standards, back-fill command, and split the SBOM import - #1411

Merged
rubenvdlinde merged 5 commits into
developmentfrom
fix/gemma-standard-links
Nov 3, 2026
Merged

rubenvdlinde merged 5 commits into
developmentfrom
fix/gemma-standard-links

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Batch PR for stackiq (SQ5). It holds two changes, each with its own section, so a red can be traced back to the change behind it. The first change is meant to change data.

1. GEMMA standards are linked to reference components and standard versions (data-changing fix)

The bug. processRelationshipImmediate and processStandardVersionRelationship recorded a link only when $standardId === true. A string identifier is never === true, so no GEMMA reference component ever got its recommendedStandards, mandatoryStandards, standards or linkedStandardVersions, and no standard version got its standard. fixStandaardVersieUuids had the same pattern ($uuid === true). It also updated a standaard column that has been called standard since the catalog rename. The classic import never matched either, because its sections are plural (elements, relationships). All of these patterns came in with the mechanical PHPCS commit eb72884 (if ($a && $b) became $a !== false && $b === true).

The fix.

  • The linking moves out of ArchiMateImportService into Service\ArchiMate\GemmaStandardLinker, which reads the objects through GemmaObjectReader. That removes 462 lines from the 4,830-line service.
  • A linked object is referenced by its id when the id is a uuid (the GEMMA "Object ID"), and by its slug otherwise. OpenRegister applies inversedBy only to uuid values, so the old identifier-without-prefix value would not have resolved even with the condition fixed.
  • fixStandaardVersieUuids checks for non-empty strings and writes the standard column.

What this changes in data. Every import from now on writes the links. On lib/Settings/GEMMA_release.xml that is:

  • 148 reference components linked;
  • 275 mandatory and 411 recommended standard links;
  • 1,668 linked standard versions;
  • 321 of 321 standard versions get their standard.

All 686 standard references are uuids. Before this change every one of these counts was 0.

Back-fill for earlier imports. occ stackiq:gemma:link-standards [--dry-run] [--register vng-gemma] [--element-schema element] [--relation-schema relation]:

  • It reads the imported elements and relationships, derives the same links, and patches only the link properties that differ from what is stored.
  • A second run writes nothing, so it is idempotent.
  • It prints N GEMMA objects read, N need links, N written, N failed, and lists the ids with -v. It exits 1 when a write fails.
  • It reads and writes without RBAC and organisation scoping, the same way the import saves these objects. It does not change any access rule.

The paged reader it uses, Command\ObjectPages, is now shared with ReferencesAuditCommand, whose own copy is removed.

Tests (written to fail first).

  • ArchiMateGemmaStandardLinksTest runs both import entry points over a new fixture. On the old code it had 5 failures.
  • GemmaStandardLinkerTest has 11 cases. GemmaStandardLinksCommandTest covers writes, idempotency, link order, dry run, a failed write and an unreadable register. ObjectPagesTest covers paging, payloads and scoping.
  • The existing ArchiMateImportGoldenTest was re-recorded. I checked the diff: apart from the GEMMA log lines, the only change is the post-save UPDATE ... SET standard = ?, which now runs in 15 cases.

Mutants (capped, with a no-op control that survived):

  • linker 18 of 18 killed;
  • reader 15 of 15;
  • command 12 of 12;
  • pager 6 of 6;
  • import service 4 of 4.

One planned linker mutant (no deduplication of the linked versions) showed that the array_unique was redundant: each version has exactly one standard, and the standards are already deduplicated. So I removed the array_unique instead of keeping dead code.

2. SbomImportService::importForModuleVersie split

  • The method goes from 82 lines to 41. Every call keeps its order. Starting the progress, completing it, the log line and the summary move into helpers.
  • importForModuleVersie, resolveParentModuleUuid and getStatus each repeated the same lookup, which is now one findModuleVersion(). That removes a 7-line clone repeated three times.
  • phpmd ExcessiveClassComplexity stays under its threshold.

Golden. SbomImportGoldenTest covers nine imports (both formats, VEX, empty, unsupported, missing version, 50 and 60 components) plus the status. It was recorded on the old code and passes on old and new.

Mutants. 10 of 10 killed, and the control survived.

Numbers (PHP, lizard, against development)

development this PR
params >= 3 16.95% 16.81%
size > 60 33.98% 33.45%
McCabe > 10 18.28% 17.64%

No unit gained parameters. Every new helper takes at most 2 parameters.

Verified locally

  • Diff-scoped checks on every touched lib file: php -l, phpcs, phpstan, psalm and phpmd are clean.
  • The touched tests pass under pcov with --fail-on-risky (exit 0).
  • development (ea0dcc2) is merged in, without a rebase.
  • The full unit suite ran once through heavy.sh (phpunit-unit.xml, pcov, --fail-on-risky): exit 0, 1609 tests, 0 failures, 0 risky, 59 skipped (inherited).
  • The hydra gates run (--scope-to-diff --base origin/development) is queued. Its result follows in a comment.

Assisted-by: ClaudeCode:claude-opus-5-5

…ions

The import recorded a GEMMA link only when `$standardId === true`, which a
string identifier never is, so no reference component ever got its
recommended, mandatory or combined standards and no standard version got its
standard. The post-save fix had the same `$uuid === true` pattern and updated
the `standaard` column, which is `standard` since the catalog rename. The
classic import also never matched, because its sections are plural.

The linking moves out of ArchiMateImportService into GemmaStandardLinker (with
GemmaObjectReader), which references a linked object by its uuid id, or by its
slug when it has none. `occ stackiq:gemma:link-standards` back-fills the links
for earlier imports: it patches only link properties that differ, so a second
run writes nothing, and `--dry-run` reports without writing. ObjectPages is the
paged reader both occ commands now share.

Assisted-by: ClaudeCode:claude-opus-5-5
…leVersie lookup

importForModuleVersie (82 lines) keeps the order of every call; starting and
completing the progress, the log line and the summary move into helpers. The
moduleVersie lookup that importForModuleVersie, resolveParentModuleUuid and
getStatus each repeated is one findModuleVersion().

Golden: every object service, progress and logger call over nine imports
(both formats, VEX, empty, unsupported, missing version, 50 and 60
components), recorded on the old code.

Assisted-by: ClaudeCode:claude-opus-5-5
@rubenvdlinde

Copy link
Copy Markdown
Contributor Author

Hydra gates --scope-to-diff --base origin/development (through heavy.sh): 37 of 37 applicable gates ran. The single FAIL was gate 16, a missing @SPEC on GemmaStandardLinksCommand::configure(), fixed in 8th commit; gate 16's checker re-run on the new head reports count=0. Full unit suite on the merged tree: exit 0, 1609 tests (the fix is a docblock only).

@rubenvdlinde
rubenvdlinde marked this pull request as ready for review November 3, 2026 19:18
@rubenvdlinde
rubenvdlinde merged commit 0b614a1 into development Nov 3, 2026
10 of 11 checks passed
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