Skip to content

feat(portfolio): score the applications you use on value, fit and risk, and see where the scores contradict the TIME class - #1200

Merged
rubenvdlinde merged 9 commits into
developmentfrom
feat/value-assessment
Sep 30, 2026
Merged

rubenvdlinde merged 9 commits into
developmentfrom
feat/value-assessment

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Change: lifecycle-application-value-assessment (archived here as 2026-09-30-lifecycle-application-value-assessment; its spec is now openspec/specs/application-value-assessment/spec.md). It builds on the usage pages from #1194.

Row moved to built: stackiq:life-value-assessment (tender row, Helmond REQ41; rated yes now).

What a user can now do: an information manager scores each application the organisation uses on business value, technical fit and risk (1 to 5) with the date, on the usage's page. On save stackiq fills in the suggested TIME class (Invest, Migrate, Tolerate or Eliminate from value and fit); the recorded TIME class stays the decision and sits beside the suggestion in a new Value assessment section. Below it, Risk signals shows whether the version in use is past its end of support or withdrawn and how many known vulnerabilities are linked to the application. The portfolio report plots business value against technical fit with annualised cost as circle size, shows the suggested class and the scores per row, offers the switch "Recorded class differs from scores", and its CSV export carries the new columns.

How: lib/Settings/register.d/value-assessment.json adds businessValue, technicalFit, riskScore, scoredOn and suggestedTimeClassification to usage (1.5.3), the suggestion as a materialised x-openregister-calculations expression. PortfolioReportService adds the scores, the suggestion and timeMismatch to each row and the CSV, falling back to the same rule (PortfolioReportDerivation::suggestTimeClassification) for a usage saved before the calculation existed. UsageRiskSignals (body widget on the usage page) and ValueFitPlot (SVG, on the report) are custom because each joins data no built-in widget combines. The demo usages are scored into all four classes, one of them contradicting its recorded class.

Design changes at build, recorded in the archived design: the plot is a small SVG component instead of CnChartWidget (per-point colour, ring and tooltip), and the scores got their own data section on the usage page.

Scenarios and the tests that prove them:

  • An information manager scores an application (REQ-AVA-001): tests/Unit/Settings/ValueAssessmentFragmentTest.php (6 tests: fields and ranges, the declared calculation, the four classes, the report rule equals the expression, the schema version, the seeds). The expression also ran through OpenRegister's real CalculationAnnotationValidator and CalculationEvaluator (OR a5832f2498): 0 validator errors, a planted typo reported as calculation-prop-unknown, 36 value/fit combinations with 0 mismatches. Playwright tests/e2e/workflows/portfolio-value.spec.ts.
  • Signals that back a high risk score (REQ-AVA-002): tests/vitest/valueAssessment.spec.js (riskSignals, the usage page wiring).
  • Finding the classes to revisit (REQ-AVA-003): tests/Unit/Service/PortfolioReportServiceTest.php (row fields and mismatch, CSV columns), tests/vitest/valueAssessment.spec.js (plot points sized by cost, not-scored count, mismatch filter), Playwright tests/e2e/workflows/portfolio-value.spec.ts.
    The PHPUnit and vitest tests were committed red before the implementation (commits dad8c75 and 05bdb10). The Playwright spec lists (2 tests); it was not run here, because no local instance has a seeded stackiq register.

New text is in English and Dutch. Docs: docs/features/portfolio-value-assessment.md; its screenshot waits for a seeded instance.

Live check: after the register re-imports, open an application under Applications in use, edit it, set business value 5 and technical fit 2 and save: Value assessment shows Suggested TIME classification Migrate beside the recorded class. Open Reports, Portfolio rationalization, pick the organisation: the chart shows the usage as a circle; the switch Recorded class differs from scores lists it when its recorded class is not Migrate.

Checks (branch head, which contains development at 100db8c): one full run (check.sh) gave composer check:strict red only on phpmd, one NEW finding (PortfolioReportService complexity 53 over 50) plus a missing pdepend cache directory in my lane tooling; npm lint 2 NEW errors and prettier on 5 new files. Fixed in 90beb13 and 6fd45fd (the score fields moved into PortfolioReportDerivation), then rerun: composer check:strict with lint, phpcs, psalm (no errors), phpstan (no errors) green and phpmd 0 on the two touched classes after the last commit; npm lint exit 0 (0 errors, 222 warnings inherited), format exit 0; PHPUnit (phpunit-unit.xml) 953 tests, 20 errors, all 20 inherited and identical by name to development (MigrateRegisterSlugTest x12, MigrateSchemaApplicationIdTest x7, PortfolioReportControllerTest::testCsvFormatReturnsDownloadResponse); the two touched PHPUnit files rerun green after the refactor (18 and 6 tests); stylelint, test:l10n, check:schema-l10n, check:l10n-js, check:manifest, check:vue-demi exit 0; jest exit 0; vitest 359 of 359; Hydra gates at ConductionNL/.github main, full scope with --require-full-coverage: 84 of 84 applicable gates passed.

Inherited: the 20 PHPUnit errors above; 222 eslint warnings.

@rubenvdlinde
rubenvdlinde merged commit f262512 into development Sep 30, 2026
36 of 37 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 3c202b4

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 ✅ ✅ 130/130
npm ✅ ✅ 807/807
app:check-code ⏭️
info.xml ✅
REUSE ❌
lockfile sync ✅
PHPUnit ❌
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 on any branch from the Actions tab, or locally with npx playwright test.
Hydra gates ✅

Quality workflow — 2026-09-30 03:54 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