feat(quality): the quality assessment is @self metadata, not object data - #3348
Merged
Conversation
A per-object quality score is an assessment OF the object's data, not a fact about the thing the object describes. It had nowhere to live except the object body, which forced every schema wanting a score to declare `qualityScore` and `qualityStatus` as ordinary properties. Three things followed, and all three are wrong: - The properties appear on every form the schema drives. A case handler filing a case in dossiq was shown a "Quality score" number field to fill in, for a value the platform overwrites on save. - Removing the declaration silently DELETES the values, because the store strips what the schema does not declare. So the mistake could not be undone without data loss. - Two schemas scoring the same way had to agree on property names by convention, with nothing to enforce it. `_quality` is now a metadata column of the same kind as `_validation` and `_retention`, surfaced in the `@self` envelope as `quality` with `score`, `status` and `scoredAt`. The change is additive on purpose. The listener still writes the body properties, but ONLY where the schema actually declares them: dropping that outright would freeze the stored value of every schema that has one, and a score that silently stops updating reads exactly like a score that is simply good. A schema that has migrated declares neither, so nothing is written to its objects and the body stays clean. The migration sweeps every per-schema object table, adding the column where it is missing and skipping it where present, so re-running is a no-op. It identifies an object table by the `_uuid` column rather than by the name prefix alone; verified against a live database, where every `oc_openregister_table_%` carries `_uuid` and `_validation` and none yet carries `_quality`. Verified: 1886 unit tests in tests/Unit/Db and tests/Unit/Listener pass (1881 before, plus the 5 added here), with the same 3 pre-existing vendor warnings and 5 skips as the pristine tree. PHPCS, PHPStan clean on every changed file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Quality Report — ConductionNL/openregister @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-specs | ✅ | ||||
| test-l10n | ✅ | ||||
| test-l10n-parity | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 174/174 | |||
| npm | ✅ | ✅ 543/543 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| PHPUnit | ✅ | ||||
| Newman | ✅ | ||||
| Playwright | ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development | ||||
| Hydra gates | ✅ |
Quality workflow — 2026-09-03 06:06 UTC
Download the full PDF report from the workflow artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A per-object quality score is an assessment of the object's data, not a fact about the thing the object describes. It had nowhere to live except the object body, which forced every schema wanting a score to declare
qualityScoreandqualityStatusas ordinary properties. Three things followed, and all three are wrong:What
_qualitybecomes a metadata column of the same kind as_validationand_retention, surfaced in the@selfenvelope asquality:The change is additive on purpose. The listener still writes the body properties, but only where the schema actually declares them. Dropping that outright would freeze the stored value of every schema that has one, and a score that silently stops updating reads exactly like a score that is simply good. A schema that has migrated declares neither property, so nothing is written to its objects and the body stays clean.
That gives every app a migration path it can take on its own schedule: read
@self.quality, then drop the declarations.The migration
It sweeps every per-schema object table, adding the column where missing and skipping it where present, so re-running is a no-op. It identifies an object table by the
_uuidcolumn rather than by the name prefix alone, so a table that merely shares the prefix is never altered.I verified that signature against a live database rather than only against the source: every
oc_openregister_table_%carries_uuidand_validation, and none yet carries_quality.Verification
tests/Unit/Dbandtests/Unit/Listener. The pristine tree runs 1881; the 5 added here are the difference, and the 3 pre-existing vendor warnings and 5 skips are unchanged@selfwrite, the schema that declares nothing, the schema that still declares both, astatusFieldnaming a property the schema never declared, and a schema with no annotationlibscope) and PHPStan clean on every changed fileUnusedBaselineEntryonObjectEntity, which reproduces identically on the pristine tree. It is an artifact of analysing single files, not something this branch introducesReviewer note
This touches the storage layer of the foundation repo, so the blast radius is every app. The two things worth your eyes are the migration's table-identification guard and the decision to keep writing declared body properties rather than cutting over hard.
🤖 Generated with Claude Code