713 lines
38 KiB
Markdown
713 lines
38 KiB
Markdown
# Assessment output strategy
|
||
|
||
Decision: 2026-09-18, explicitly approved by the user. The 2026-09-23 user request
|
||
starts the A/B HTML deliverable through Client Info (Phase 7 UI integration,
|
||
cross-cutting report projection). Artifact C and D remain separate future work.
|
||
|
||
ASSESSOR produces **three** artifacts from one assessment:
|
||
|
||
| Artifact | Audience | Nature |
|
||
| --- | --- | --- |
|
||
| A — Management Overview (HTML) | customer decision makers | frozen snapshot |
|
||
| B — Technical Report (HTML) | engineers reproducing a finding | frozen snapshot, complete |
|
||
| C — Arbeitsgrundlage (XLSX + HTML) | the people doing the work | living document, curated |
|
||
| D — Delta Report (HTML, management + technical cut) | both, after a rescan | frozen snapshot of the change |
|
||
|
||
The dividing principle: **a report states the finding and its proof; the
|
||
Arbeitsgrundlage states the measure and who owns it.**
|
||
|
||
Remediation progress is proven by rescans, never by self-reported status. See
|
||
*Progress is proven by rescan* below.
|
||
|
||
## Approved delivery decisions
|
||
|
||
| Decision | Choice |
|
||
| --- | --- |
|
||
| Delivery | Separate files per artifact |
|
||
| Design | Layout direction of the earlier ASSESSOR exports, drawn in the ASSESSOR look (superseded 2026-09-24, see below) |
|
||
| Technical scope (B) | Deviations, diagnostics and score-neutral classes |
|
||
| Interaction | Print- and PDF-ready; inline script only for search/filter (superseded 2026-09-24, see below) |
|
||
| Language | German, all artifacts |
|
||
| Arbeitsgrundlage format | XLSX to work in, HTML as the frozen status view |
|
||
| Arbeitsgrundlage scope | Curated selection, plus the complete list on a second sheet |
|
||
| Progress evidence | Rescan only; planning fields stay but are marked unverified |
|
||
| Delta delivery | Own artifact, management and technical cut |
|
||
|
||
Separate files keep the confidentiality boundary real: the Management file can be
|
||
forwarded without carrying registry keys, SIDs, evidence paths or parser
|
||
versions in its source. A single file with a hidden section would still contain
|
||
them.
|
||
|
||
### Export layout and interaction — explicit user decision, 2026-09-24
|
||
|
||
The user asked for both reports to follow the earlier ASSESSOR exports again.
|
||
This supersedes the static no-JavaScript decision and the dark rendering path:
|
||
|
||
- Layout: KPI cards, a severity distribution donut with legend and large total,
|
||
the Overall Score donut with per-source contributions, bar lists instead of
|
||
count tables, and finding lists with expandable rows (Technical Report) or a
|
||
filterable Priority list (Management Overview).
|
||
- Look: ASSESSOR typography (embedded Inter), flat white cards with thin
|
||
borders, shared severity colours and the yellow marking colour for active
|
||
filter chips. No rounded shadow cards, gradients, purple accents or system
|
||
font from the old exports.
|
||
- Light only: customers read both files, so there is no `prefers-color-scheme`
|
||
dark variant.
|
||
- Interaction: one small inline script adds search and filter chips and opens
|
||
every expandable row for printing. It only toggles `hidden`, `open` and
|
||
`aria-pressed` on server-rendered markup; without it everything stays
|
||
visible. No external script, CDN, font download or inline event handler.
|
||
- Unchanged: the Management Overview keeps the grouped Priority list and
|
||
carries no per-record table or technical values; GPO deviations still carry no
|
||
invented severity; all binding wording and score semantics stay.
|
||
|
||
Shared presentation lives in `src/exports/report-theme.ts`.
|
||
|
||
Readability refinement, same day, on user feedback: a reader must see what a
|
||
finding is and how to fix it without wading through empty or raw values.
|
||
|
||
- Technical Report findings read as Beschreibung, Befund, Ist-/Sollwert where
|
||
retained, Warum ist das relevant?, Lösung and Referenzen. Empty source fields
|
||
and fields repeating already shown text are left out; the remaining original
|
||
fields, identities and raw baseline variants sit in a collapsed
|
||
`Technische Details` block. Omitting an empty value never invents one.
|
||
- Source prose keeps its simple formatting: text is escaped first and only
|
||
attribute-free `p/br/b/strong/i/em/u/ul/ol/li` tags are re-emitted.
|
||
- GPO Findings show one row per policy setting with Deviation, rolled up over its
|
||
baseline comparisons: expected values per baseline beside the configured
|
||
source instructions with the retained deviation marking, plus a fix sentence
|
||
derived only from the expected value and the Conflicts/Duplicates flags. The
|
||
Policy Register lists every other verdict grouped by verdict; long
|
||
score-neutral groups start collapsed and stay out of print.
|
||
- Severity and status are supporting information: a small dot and muted label,
|
||
no filled badges or FAIL pills. Unknown severity renders nothing.
|
||
- The Management Overview names tools by their profile name, shows GPO
|
||
deviations once in the equal-weight GPO block rather than per comparison in
|
||
Priority Findings, and counts the Deviations KPI as scanner deviations plus GPO
|
||
policy settings with Deviation.
|
||
|
||
## Report language
|
||
|
||
Both reports are written in German: headings, prose, labels, table headers,
|
||
legends and every explanatory sentence.
|
||
|
||
This does not change the Client Info dashboard, which remains English-only by its
|
||
own decision. The reports are separate customer-facing artifacts; the two rules
|
||
stand side by side and neither overrides the other.
|
||
|
||
German is the carrier language. **Established English technical terminology stays
|
||
English** and is not translated, not hyphenated into a German compound and not
|
||
replaced by an invented German equivalent. This is the general rule, not a list
|
||
of exceptions. It covers at least:
|
||
|
||
- the agreed GPO verdicts `Deviation`, `Passed`, `Not configured`,
|
||
`No baseline rule`, `Not comparable`, `Conflicts`, `Duplicates`
|
||
- the security domain names from `src/features/dashboard/security-domains.ts`
|
||
- assessment vocabulary such as Finding, Baseline, Score, Scope, Severity,
|
||
Pass Rate, Review, Owner, Due Date, Remediation, Evidence
|
||
- platform vocabulary such as Group Policy, Registry, Domain Controller,
|
||
Privilege, Attack Path, Hardening
|
||
|
||
Reason: these are the terms the readers already use, and most of them appear
|
||
verbatim in the application's Work filters and in the Client Info dashboard. A
|
||
reader must be able to match a line in the report to the view it came from, and a
|
||
translated second vocabulary would weaken the documented agreements.
|
||
|
||
Where a term is not self-explanatory to a management reader, it is introduced once
|
||
with a short German explanation and then used in its canonical English form.
|
||
German prose carries the sentence; the term inside it stays English.
|
||
|
||
Original source values, registry keys, value names, principals, evidence paths and
|
||
native identifiers are never translated or localized. Numbers and dates follow
|
||
German formatting.
|
||
|
||
The shared projection stays language-neutral and carries data, not display
|
||
strings. All German wording lives in the renderers.
|
||
|
||
## Shared report projection
|
||
|
||
Implemented in `src/domain/report-projection.ts`
|
||
(`REPORT_PROJECTION_VERSION = '1.2.0'`), covered by
|
||
`tests/domain/report-projection.test.ts`.
|
||
|
||
All artifacts read **one** projection built in the platform-neutral domain layer.
|
||
The projection is the single source of truth; the renderers only choose depth,
|
||
never content. Two consequences are binding:
|
||
|
||
- A number that appears in both reports is the same number. The Management
|
||
Overview never rounds, re-derives or re-filters a value that the Technical
|
||
Report states differently.
|
||
- Renderers contain no source-specific parsing, no scoring arithmetic and no
|
||
database access. They receive the finished projection.
|
||
|
||
The projection is built on export only. It is not part of the workspace load
|
||
path and must not derive presentation fields for records no report section
|
||
consumes.
|
||
|
||
## Report A — Management Overview
|
||
|
||
Implemented in `src/exports/management-overview-report.ts`
|
||
(`MANAGEMENT_OVERVIEW_RENDERER_VERSION = '3.0.0'`), covered by
|
||
`tests/exports/management-overview-report.test.ts`.
|
||
|
||
Answers: how do we stand, what is most urgent, what is this based on, what do we
|
||
not know. Its reading order follows the agreed Client Info grammar.
|
||
|
||
### Brief standing — explicit user decision, 2026-09-28
|
||
|
||
The Management Overview is a brief standing of the tenant for senior decision
|
||
makers and no longer shows single findings. This supersedes sections 4 to 7
|
||
below (Priority Findings, Remediation status, the coverage tables and Source
|
||
overview) as well as the 2026-09-24 filterable Priority list, convergence and
|
||
bundle sections. The report now reads:
|
||
|
||
1. Assessment identity (unchanged).
|
||
2. Overall Posture: one summary card with the Overall Score, the Deviations
|
||
total and Deviations per source side by side; below it Security Domains at
|
||
full width, one meter line per domain (pass rate and deviations of
|
||
assessed); then one coverage sentence (assessed / not run / not applicable /
|
||
execution errors) and the binding score wording, including the GPO scope
|
||
limit when it applies. There is no separate GPO section; GPO deviations are
|
||
counted in the totals, per source and in the GPO & Baseline domain.
|
||
3. Empfohlene Maßnahmen: only when the timeslot has a succeeded, non-stale AI
|
||
Overview carrying a `managementBrief` (AI prompt 1.2.0). It shows up to five
|
||
German priorities (timeframe, owner role, rationale) and the five roadmap
|
||
phases, visibly marked as AI-supported advisory content and not technical
|
||
proof. A missing, failed, stale or unreachable AI Overview omits the section;
|
||
it never blocks the export. The Client Info AI Overview stays English.
|
||
|
||
The Technical Report remains the place for every finding.
|
||
|
||
No severity (user correction, same day): not every tool provides a severity, so
|
||
the Management Overview shows no severity KPI, severity distribution or
|
||
criticality wording. Every deviation counts equally, whatever its tool reports.
|
||
|
||
Filler text removed (user request, same day): the coverage sentence, the long
|
||
score explanation, the inverted-risk and GPO scope notes and the AI intro are
|
||
gone. One line keeps the binding score wording ("Mixed-Method-Index;
|
||
GPO-Anteil = Konformität der konfigurierten, vergleichbaren Einstellungen im
|
||
Scope"), and the AI section heading carries a short "KI-gestützt" label with its
|
||
date, so the advisory content stays marked.
|
||
|
||
Layout correction (user feedback, same day): the separate GPO & Baseline section
|
||
is removed, and the half-empty KPI cards and the tall domain spine are replaced
|
||
by the summary card and one-line domain meters described above.
|
||
|
||
**Named deviation from the `assessor-ui` skill:** a delivered document uses no
|
||
application shell — no sidebar, topbar, command band or context strip — and none
|
||
of the four page archetypes, because it is read and printed outside the
|
||
application. Typography roles, donut geometry, tile and segment grammar, status
|
||
colour rules and the panel inset apply unchanged. Since 2026-09-24 the report is
|
||
light only (customer-facing) and uses the card layout described under *Export
|
||
layout and interaction*.
|
||
|
||
The bundled Inter is embedded as a data URL with a system fallback. No font,
|
||
style, script or image is loaded when the file is opened.
|
||
|
||
### 1. Assessment identity
|
||
Customer, environment (domain, forest, domain controller count from the
|
||
environment inventory), assessment period, report date, ASSESSOR product version.
|
||
|
||
### 2. Overall posture
|
||
The single score as a donut using the shared donut geometry, with its method
|
||
label. Binding wording from `SCORING_MODEL.md`:
|
||
|
||
- The GPO contribution is *conformance of configured, comparable in-scope
|
||
settings*. Binding German wording: „Konformität der konfigurierten,
|
||
vergleichbaren Einstellungen im Scope". It is never labelled baseline
|
||
compliance, baseline coverage or proof that recommended settings are
|
||
implemented — in German neither „Baseline-Compliance", „Baseline-Abdeckung"
|
||
nor any phrasing implying the baseline is fully rolled out.
|
||
- PingCastle enters as `100 − native risk`; the raw risk stays secondary context.
|
||
- A mixed-method index is named as such. Security Domain values are pass rates
|
||
and are not a decomposition of the index.
|
||
|
||
### 3. Security Domains
|
||
The eight domains from `src/features/dashboard/security-domains.ts` as a
|
||
connected pass-rate spine beside the overall score. Not a table.
|
||
|
||
### 4. Priority Findings
|
||
Grouped by security domain. **There is no global cross-tool ranking.** Inside a
|
||
domain, findings are ordered by the declared priority basis of their own source,
|
||
and that basis is named at the point of display.
|
||
|
||
Per entry: title, domain, the source's own rank value with its basis, one
|
||
sentence of impact, plus owner and status when a review exists.
|
||
|
||
GPO deviations form their own equal-weight block with their count, the affected
|
||
policy settings and the scope limit. They are never assigned an invented
|
||
criticality.
|
||
|
||
No registry keys, no SIDs, no file paths, no raw values.
|
||
|
||
See *Priority without a common severity* below for why.
|
||
|
||
### 5. Remediation status
|
||
Open, in progress, accepted, overdue, and findings without an owner — derived
|
||
from the stored reviews including accepted-risk data. If no reviews are
|
||
maintained, the section is omitted rather than rendered empty.
|
||
|
||
### 6. Coverage and gaps
|
||
What was assessed, what was not, unassessed controls, and every scope limit that
|
||
bounds a statement. A GPO import covering a subset of the domain is reported as
|
||
scope-limited and never presented as a domain-wide or effective-device claim.
|
||
This section is what makes the report defensible.
|
||
|
||
### 7. Source overview
|
||
Per tool: run or file date, score contribution, and the method that produced it.
|
||
|
||
### Excluded from Report A
|
||
Per-record tables, raw values, evidence paths, diagnostics, parser, analyzer and
|
||
manifest versions.
|
||
|
||
## Report B — Technical Report
|
||
|
||
The initial static renderer is implemented in `src/exports/technical-report.ts`.
|
||
It retains the current internal result projection, original Work fields when a
|
||
canonical occurrence matches, and the retained per-backup GPO instructions.
|
||
Missing source facts are labelled as unavailable; the renderer never invents
|
||
actual/expected values or an endpoint-effective state. A dedicated completeness
|
||
audit of diagnostics, reimport metadata and all source formats remains open and
|
||
must not be mistaken for a final acceptance of every section below.
|
||
|
||
One finding list, severity only on findings — explicit user decision, 2026-09-28:
|
||
scanner deviations and GPO policy settings with Deviation form one `Findings`
|
||
list grouped by Security Domain, with one search and filter bar (Severity for
|
||
scanner rows, Quelle including Group Policy, Conflicts/Duplicates). GPO settings
|
||
stay rolled up per policy setting and carry no severity; they sort after the
|
||
severity-ranked rows of their domain. This supersedes the separate Scan Findings
|
||
and GPO Findings sections and the GPO grouping by policy section. Severity
|
||
appears only on the finding rows, their detail and the list filter: the overview
|
||
shows a Deviations total with a count per source instead of a severity donut,
|
||
and the result inventory and result index have no Severity card or column.
|
||
|
||
Focused sections — explicit user decision, 2026-09-28: the Technical Report now
|
||
reads Überblick and Findings. Result-Inventar,
|
||
Konvergenz-Nachweis, Scope-Grenzen and Anhang (diagnostics, scope/provenance and
|
||
the complete result index) are removed; this supersedes sections 1, 2, 5 and 6
|
||
below. Explanatory notes and intro text are removed on user request (header
|
||
snapshot/endpoint note, GPO card note, Findings intro); the report states no
|
||
effective endpoint state and shows no score-neutral GPO verdicts, so no claim
|
||
needs the former caveats. Missing-data markers inside a finding stay. Überblick gains an Umgebung card and
|
||
a Betriebssysteme card (no separate heading, user correction the same day) with
|
||
the domain/forest facts plus the Client Info inventory counts (domains, domain
|
||
controllers, user accounts with enabled/disabled, computer objects) and the
|
||
operating-system inventory grouped as Servers, Clients and Other / unclassified.
|
||
They come from the same helpers as Client Info (projection field
|
||
`technicalEnvironment`, projection 1.2.0); an unknown count is left out and an
|
||
operating system without a row-bound count shows an em dash, never zero.
|
||
|
||
GPO counts — user correction, 2026-09-28: the Überblick GPO card shows only
|
||
Deviation, Passed and Review required plus Conflicts and Duplicates as bars;
|
||
the score-neutral Not configured, No baseline rule and Not comparable bars are
|
||
removed, and its label counts only the assessed settings shown. Both reports
|
||
read GPO policy settings from the current evaluation run only, exactly like Work
|
||
and Client Info; before, a superseded stored run was counted as well and every
|
||
setting appeared twice. A GPO-only timeslot is read from its single GPO sheet.
|
||
The GPO Policy Register at the end of the report is removed on user request as
|
||
well (supersedes section 4 below); settings with Deviation stay in Findings.
|
||
|
||
Answers: what exactly is configured, what should it be, where does that stand,
|
||
how does ASSESSOR know, what do I do.
|
||
|
||
### 1. Scope and provenance
|
||
Imported artifacts, processing, analyzer and manifest versions, reimport status,
|
||
aggregation and evaluation run identifiers. Enough to reproduce the result.
|
||
|
||
### 2. Result inventory
|
||
Totals per status, severity, domain and tool, including the score-neutral
|
||
classes. Passed results appear here as a count.
|
||
|
||
### 3. Findings in detail
|
||
Grouped by security domain, ordered by severity inside each group. Per finding:
|
||
|
||
- technical identity and scope
|
||
- actual against expected value, with the field-specific deviation marking used
|
||
by the Finding Reader: `Operation`, `Data` and `Type code` for registry policy
|
||
differences, several fields only where each is independently proven
|
||
- principal sets compared per member: only configured principals absent from
|
||
every retained baseline variant are marked; a principal also present in the
|
||
expected baseline stays neutral
|
||
- GPO source attribution as vertically stacked sections per exact backup
|
||
identity, each with evidence reference, source-local sequence and every
|
||
original instruction immediately visible
|
||
- conflict and duplicate flags, kept separate from the policy verdict
|
||
- baseline variants where more than one exists
|
||
- the remediation step from the review
|
||
|
||
### 4. GPO policy register
|
||
All seven verdicts in full: `Deviation`, `Passed`, `Not configured`,
|
||
`No baseline rule`, `Not comparable`, `Conflicts`, `Duplicates`. The
|
||
score-neutral verdicts are labelled as score-neutral at the point of display, so
|
||
that a reader cannot mistake `Not configured` for a remediation obligation.
|
||
|
||
### 5. Diagnostics
|
||
Unresolved identities, parser gaps, scope limits, declared-against-counted
|
||
mismatches and incomplete backups. Each observation appears once with its
|
||
authoritative resolver reason and is not restated by snapshot aggregation.
|
||
|
||
### 6. Appendix
|
||
Complete result index.
|
||
|
||
## Artifact C — Arbeitsgrundlage
|
||
|
||
Decision: 2026-09-18, explicitly approved by the user.
|
||
|
||
Answers: what do we do, who owns it, by when, where does it stand.
|
||
|
||
The measured volume makes this its own artifact: the stored data holds **1,806
|
||
actual deviations** (CIS-CAT 969, Maester 350, PingCastle 277, Purple Knight 210)
|
||
plus the GPO deviations. Rendering each of those with full technical depth inside
|
||
Report B would produce a document nobody works with.
|
||
|
||
Size is not the decisive reason, though. A report is a frozen snapshot that
|
||
proves what was found on a date and is archived unchanged. An Arbeitsgrundlage is
|
||
a living document that the customer edits for weeks: owner, due date, status,
|
||
comment. Forcing both into one file makes both worse.
|
||
|
||
### Data model
|
||
|
||
The Arbeitsgrundlage is the stored review model in `src/domain/review.ts`:
|
||
`status`, `priority`, `owner`, `due`, `prerequisites`, `access`, `nextStep`,
|
||
`evidence`, `comment`, the markers `quickwin`, `blocked`, `external`, `question`
|
||
and `notRelevant`, plus `riskAcceptance`.
|
||
|
||
`include` is the curation switch. The consultant selects what reaches the
|
||
customer as a work item. Shipping 1,806 unfiltered items produces no action at
|
||
all.
|
||
|
||
### Structure
|
||
|
||
- **Sheet 1 — Maßnahmen.** Only the curated selection, with a stated selection
|
||
criterion. One row per work item.
|
||
- **Sheet 2 — Vollständige Abweichungen.** All deviations for reference, so the
|
||
customer can pull further items in without the working list overflowing.
|
||
|
||
The HTML variant renders the same content as a frozen status view for status
|
||
meetings and filing. It is generated from the same projection, never maintained
|
||
separately.
|
||
|
||
### No duplicated technical depth
|
||
|
||
A work item carries its stable finding identifier, the measure, prerequisites,
|
||
required access and the owner — not the evidence, not the source attribution, not
|
||
the baseline variants. Those stay in Report B and are reached through the
|
||
identifier.
|
||
|
||
One fact, one place. Repeating the technical detail would leave two diverging
|
||
versions after the first correction.
|
||
|
||
## Progress is proven by rescan
|
||
|
||
Decision: 2026-09-18, explicitly approved by the user: *"Den Fortschritt
|
||
dokumentiere ich durch Rescans — für mich zählt nur der technische Beweis."*
|
||
|
||
Remediation progress is established by comparing scan runs, never by a status
|
||
somebody ticked. This follows `TIMESLOT_COMPARISON_PLAN.md`, which already
|
||
replaced the conclusion *absent equals remediated*.
|
||
|
||
### Binding rules
|
||
|
||
- No artifact presents a self-reported status as a resolved finding. A work item
|
||
marked done in the Arbeitsgrundlage stays an open deviation in every report
|
||
until a rescan proves otherwise.
|
||
- A delta uses the lifecycle vocabulary of the timeslot contract — demonstrably
|
||
remediated, still open, unresolved, not comparable — never a binary
|
||
done/open. *Unresolved* is a legitimate and frequent outcome and is shown as
|
||
such.
|
||
- Absence of a finding is not proof of remediation. Remediation is claimed only
|
||
where the profile-bound negative-proof contract is satisfied for exactly that
|
||
rule and object.
|
||
- Result presence and deviation lifecycle stay separate. A rule can still be
|
||
reported while its concrete deviation is fixed.
|
||
- No effective-endpoint claim is derived from a backup-configuration comparison.
|
||
|
||
### Why the caveat is not theoretical
|
||
|
||
The stored data shows how easily absence would be misread: Maester carries **845
|
||
`not_run`** and 10 `execution_error`, Purple Knight 34 `not_applicable` and 10
|
||
`not_run`. A check that did not run would otherwise turn into a success message —
|
||
the most dangerous false statement a progress report can make, because it errs in
|
||
the comfortable direction.
|
||
|
||
### Artifact D — Delta Report
|
||
|
||
An own artifact per rescan, in the same two cuts as the reports. The initial
|
||
report stays frozen and is never rewritten; the change is a separate document
|
||
with its own reporting date.
|
||
|
||
**The comparison is against a chosen reference run, and that choice is made in
|
||
ASSESSOR — not at export time.** The export renders a comparison that already
|
||
exists; it contains no run-selection logic, no fallback to "the previous run" and
|
||
no implicit pairing of its own. Consequences:
|
||
|
||
- The chosen reference run is part of the stored comparison, together with its
|
||
contract version, engine versions and input fingerprint. The export reads it
|
||
and never re-derives it.
|
||
- The document names both compared runs explicitly — reference and current, each
|
||
with its identity and date — so it stays self-describing once it is out of the
|
||
application.
|
||
- Without a stored comparison there is no Delta Report. The export is
|
||
unavailable rather than guessing a pairing.
|
||
|
||
This keeps comparison a domain concern and presentation a separate one: the Delta
|
||
Report is a renderer, not a second comparison engine.
|
||
|
||
- **Management cut:** score movement, what is demonstrably remediated, what
|
||
persists, what is newly found, and how much of the comparison is unresolved or
|
||
not comparable. The unresolved share is stated, not hidden.
|
||
- **Technical cut:** per finding the lifecycle verdict with its evidence — which
|
||
run, which identity match, which contract qualified it — plus the
|
||
disqualifying diagnostics where a comparison was not admissible.
|
||
|
||
### Planning fields in the Arbeitsgrundlage
|
||
|
||
`status`, `due`, `owner` and the markers stay in the XLSX as the customer's own
|
||
steering aid. They are labelled as unverified self-report at the point of display.
|
||
ASSESSOR never promotes them into a report as a result.
|
||
|
||
The export therefore stays one-way by design, not by limitation: progress does not
|
||
need a return channel because it comes from the next scan.
|
||
|
||
## Priority without a common severity
|
||
|
||
Decision: 2026-09-18, explicitly approved by the user.
|
||
|
||
Severity is not a property every scanner delivers. Measured against the stored
|
||
data:
|
||
|
||
| Tool | Results | Severity coverage | Native ranking signal |
|
||
| --- | --- | --- | --- |
|
||
| CIS-CAT | 1,233 | none, all `unknown` | none |
|
||
| PingCastle | 277 | derived from Points | Points 0–50+ |
|
||
| Maester | 1,590 | 99.4 % | native severity |
|
||
| Purple Knight | 1,309 | 100 %, 187 `critical` | native severity |
|
||
| GPO / baseline | — | none | none |
|
||
|
||
A severity-ranked global list would therefore drop CIS-CAT and GPO out of the
|
||
Priority Findings entirely, let Purple Knight dominate merely because it is the
|
||
only source that emits `critical` natively, and keep PingCastle permanently below
|
||
`critical` because `pingCastleSeverityFromPoints` caps at `high` by construction.
|
||
That ordering would describe the report formats, not the customer's risk.
|
||
|
||
### Binding rules
|
||
|
||
- Priority Findings are grouped by security domain. The eight domains are
|
||
tool-neutral and already exist.
|
||
- Within a domain, findings are ordered by the declared priority basis of their
|
||
own source. The basis is visible to the reader.
|
||
- No ranking is ever produced across sources with incomparable bases. A single
|
||
ordered list that mixes them is not permitted.
|
||
- GPO deviations are equal-weight. They get their own block with count, affected
|
||
policy settings and scope limit, and never an inferred criticality.
|
||
- A source without any defensible ranking basis lists its findings unranked and
|
||
says so. Unranked is an acceptable answer; an invented rank is not.
|
||
|
||
### Profile obligation
|
||
|
||
Implemented as `ToolPriorityBasisDefinition` in
|
||
`src/domain/tool-profile-definition.ts`, required on every `ToolProfileDefinition`
|
||
and enforced by `tests/profiles/declarative-profiles.test.ts`.
|
||
|
||
Analogous to the existing `securityScoring` obligation, every tool profile
|
||
declares a **priority basis**: the exact mapped properties, scale, direction and
|
||
semantics of the value used to order its findings — or an explicit reason why no
|
||
usable basis exists. Never infer a priority from an arbitrary field named
|
||
severity, level, score or rank.
|
||
|
||
A declaration may also list `excludedProperties`: fields that resemble a basis
|
||
but are not one, each with its reason. This is what stops a later change from
|
||
quietly promoting them.
|
||
|
||
| Profile | Declared basis |
|
||
| --- | --- |
|
||
| Purple Knight | `severity` — native criticality, the only source reaching `critical` without derivation |
|
||
| Maester | `severity` — native per test |
|
||
| PingCastle | `numeric` on Points, `0-50+`, higher-is-worse |
|
||
| CIS-CAT | `unavailable` — benchmarks state no per-recommendation criticality |
|
||
| Generic | `unavailable` — unrecognized fields establish no scale or direction |
|
||
|
||
PingCastle is declared on Points rather than severity on purpose: its canonical
|
||
severity is *derived* from Points by `pingcastle-severity-from-points` and is
|
||
capped at `high` by construction. Points keeps the granularity the capped
|
||
severity loses.
|
||
|
||
`reportPriorityBasisFrom` turns an `unavailable` declaration into an explicit
|
||
`equal-weight` basis carrying the profile's own reason, so a report states why a
|
||
source is unranked instead of implying the declaration is missing.
|
||
|
||
A derived, normalized cross-tool ASSESSOR priority is **not** approved. It would
|
||
require its own versioned rule and an explicit decision of its own.
|
||
|
||
### Guarded mis-mapping risk
|
||
|
||
`src/profiles/cis-cat/cis-cat-definition.ts` declares
|
||
`severityHeaders: /^(?:severity|level)$/i`. CIS `Level 1` / `Level 2` is a
|
||
hardening profile tier, not a criticality. It falls through to `unknown`, which
|
||
is harmless, and it is now recorded as an excluded property with its reason and
|
||
covered by a test. It must not be "corrected" into a severity, because that would
|
||
manufacture criticalities the benchmark never stated.
|
||
|
||
## Guardrails for both reports
|
||
|
||
- Score-neutral classes never appear in Priority Findings and never enter the
|
||
score. They remain fully inspectable in Report B.
|
||
- A GPO verdict is taken only from the authoritative rolled-up policy verdict and
|
||
the explicit conflict and duplicate flags. Never from comparison prose,
|
||
historical results, baseline text, guidance or evidence.
|
||
- Unknown or unavailable facts render as an em dash, never as an inferred zero.
|
||
- Both files are self-contained: inline styles and script, no CDN, no external
|
||
fonts, scripts or images, no network access when opened. A report leaves the building
|
||
and must not load anything.
|
||
- The bundled Inter variable font is embedded or a local system stack is used;
|
||
no font is downloaded at view time.
|
||
- Shared typography roles, donut geometry, marking semantics and panel inset
|
||
apply as in the application. Status colour stays in accent lines, markers,
|
||
arcs and score nodes, never as a full status fill.
|
||
- Printable to PDF without layout loss. Inline script is limited to search and
|
||
filtering over already rendered content (2026-09-24); it never fetches or
|
||
writes markup.
|
||
|
||
## Relationship to the existing export
|
||
|
||
### Current-view export — explicit user extension, 2026-09-18
|
||
|
||
The Work toolbar's CSV/MD/HTML buttons now export the current filtered and sorted
|
||
view, including Results, with exactly two content columns: `Soll-Zustand` and
|
||
`Abweichungen`. This supersedes their old marked-only selection. The user can
|
||
still restrict the view with `My Workspace`; that restriction combines with the
|
||
other active filters. A view export is a frozen, scoped inspection snapshot,
|
||
not the curated Arbeitsgrundlage C, a replacement for reports A/B, or a delta.
|
||
|
||
`src/exports/work-view-export.ts` supplies one click-time presentation projection
|
||
for these three formats, consuming existing Work records and the shared Results
|
||
resolver without ranking, scoring, re-evaluation or database queries. The shared
|
||
`report-projection.ts` contract for artifacts A–D remains unchanged. Native
|
||
remediation, baseline variants, exact source attribution and verification gaps
|
||
stay visible. Review completion never becomes a technical resolution. Long CSV
|
||
cells are preserved in labelled continuation rows (same finding ID), keeping two
|
||
columns and avoiding Excel's cell-size truncation. HTML is self-contained,
|
||
script-free, with locally bundled Inter embedded and responsive wrapping.
|
||
|
||
The following paragraph records the earlier strategy baseline; its description
|
||
of the toolbar's marked-only behaviour has been superseded by this extension.
|
||
|
||
`src/exports/dashboard-export.ts` and `ActionlistControls` already export the
|
||
review model as CSV, Markdown and a minimal HTML page. That HTML knows nothing of
|
||
the score, the security domains, GPO verdicts or provenance and uses Segoe UI
|
||
with fixed colours.
|
||
|
||
The existing action-list export is the seed of artifact C, not of the reports.
|
||
The reports are new; the action-list HTML is replaced by the artifact C renderer,
|
||
and the CSV path stays useful for ticket-system import.
|
||
|
||
## Open decisions
|
||
|
||
- How many findings each domain block shows before it is truncated, and how a tie
|
||
inside one source's ranking basis is broken.
|
||
- Whether the Microsoft baseline packages carry any per-setting classification
|
||
that could later give GPO deviations a defensible basis. Until proven, GPO
|
||
stays equal-weight.
|
||
- The selection criterion wording for the curated sheet, and whether it is fixed
|
||
or written per engagement.
|
||
- Which profiles can satisfy a negative-proof contract at all. Profiles that
|
||
cannot will never produce a *demonstrably remediated* verdict, and the Delta
|
||
Report must say so per source rather than leave the reader guessing.
|
||
- File naming convention across all artifacts, including how a delta names its
|
||
two compared runs.
|
||
|
||
## Dependency
|
||
|
||
Artifact D depends on the timeslot comparison actually producing stored results.
|
||
`assessor_timeslot_evidence_comparisons` exists with its contract version, engine
|
||
versions and input fingerprint, but currently holds no rows. Until the comparison
|
||
is implemented per `TIMESLOT_COMPARISON_PLAN.md`, artifacts A, B and C are
|
||
deliverable and D is not.
|
||
|
||
## Change log
|
||
|
||
- 2026-09-18: Strategy established. Delivery, design, technical scope and
|
||
interaction decided by the user; content inventory per report fixed.
|
||
- 2026-09-18: Report language decided by the user — German for both reports. The
|
||
agreed GPO verdict vocabulary and the security domain names stay canonical
|
||
English inside the German text; source values are never localized. The Client
|
||
Info English-only rule is unaffected.
|
||
- 2026-09-18: User correction — established English technical terminology stays
|
||
English as a general rule, not as an enumerated exception. German carries the
|
||
prose; technical terms are never translated or turned into German compounds.
|
||
- 2026-09-18: Priority model decided by the user after the user raised that not
|
||
every tool provides severity. Verified against stored data: CIS-CAT and GPO
|
||
have no severity at all, PingCastle cannot reach `critical` by construction.
|
||
Priority Findings are grouped by security domain with a per-source, declared
|
||
and visible ranking basis; no cross-tool ranking; GPO equal-weight in its own
|
||
block. Profiles must declare a priority basis. A normalized cross-tool
|
||
priority is explicitly not approved.
|
||
- 2026-09-18: Third artifact added on the user's proposal. The per-finding
|
||
working basis becomes its own deliverable — XLSX to work in plus an HTML status
|
||
view, curated through `include` with the complete deviation list on a second
|
||
sheet. Decisive reason is the differing lifecycle, not only the measured volume
|
||
of 1,806 deviations. Work items reference findings by identifier and never
|
||
repeat the technical depth of Report B.
|
||
- 2026-09-18: Progress model fixed by the user — progress is documented by
|
||
rescans, only technical proof counts. A fourth artifact is added: the Delta
|
||
Report, in a management and a technical cut, using the timeslot lifecycle
|
||
vocabulary. Self-reported status never becomes a reported result; planning
|
||
fields remain in the Arbeitsgrundlage marked as unverified. The earlier open
|
||
question about re-importing a maintained worklist is closed: the export is
|
||
one-way by design.
|
||
- 2026-09-18: Reference run decided by the user — a delta compares against a
|
||
chosen reference run, and the choice is made in ASSESSOR. The export renders a
|
||
stored comparison and carries no run-selection logic, no previous-run fallback
|
||
and no implicit pairing. Both runs are named in the document.
|
||
- 2026-09-28: User decision — the Management Overview becomes a brief tenant
|
||
standing without single findings (renderer 3.0.0): posture, one-line coverage,
|
||
GPO summary and, from a current AI Overview, the German `managementBrief`
|
||
priorities and roadmap. Priority Findings, remediation, convergence, bundles
|
||
and source tables are removed from Report A. Same-day correction: no severity
|
||
KPI, distribution or criticality wording, because not every tool has one.
|
||
Layout correction: no separate GPO section; summary card plus full-width
|
||
one-line Security Domain meters.
|
||
- 2026-09-28: User decision for the Technical Report — one Findings list for
|
||
scanner and GPO deviations, and severity only on the finding rows.
|
||
- 2026-09-28: User decision — the Technical Report drops Result-Inventar,
|
||
Konvergenz-Nachweis, Scope-Grenzen and Anhang; Überblick gains Umgebung and
|
||
Betriebssysteme cards with the Client Info inventory counts and operating systems (projection 1.2.0).
|
||
- 2026-09-28: Fix — report GPO counts use the current evaluation run only (were
|
||
doubled by a superseded run); the Technical Report GPO card drops the
|
||
score-neutral bars and adds Conflicts and Duplicates.
|
||
- 2026-09-28: User decision — the GPO Policy Register is removed from the
|
||
Technical Report.
|
||
- 2026-09-28: User decision — explanatory filler text is removed from the
|
||
Technical Report and trimmed in the Management Overview to the binding score
|
||
line and a short AI label.
|
||
- 2026-09-18: Shared projection implemented as `src/domain/report-projection.ts`.
|
||
The security-domain assignment is injected by the caller so the domain layer
|
||
never points at the feature layer. Profiles do not yet declare a priority
|
||
basis, so the projection accepts one per source and falls back to `undeclared`
|
||
with its own diagnostic rather than guessing. Declaring the basis inside
|
||
`ToolProfileDefinition` is the follow-up step.
|
||
- 2026-09-18: Profile obligation implemented. `ToolPriorityBasisDefinition` is
|
||
required on every registered profile and enforced by a contract test. Purple
|
||
Knight and Maester declare native severity, PingCastle declares Points because
|
||
its severity is derived and capped, CIS-CAT and Generic declare unavailable
|
||
with a reason. CIS `Level` is recorded as an excluded property so it cannot be
|
||
promoted into a criticality later.
|
||
- 2026-09-18: Management Overview renderer implemented as
|
||
`src/exports/management-overview-report.ts`. Static, self-contained German
|
||
HTML with no script, inline handler, external URL or `url()`. Deviation from
|
||
the `assessor-ui` shell and page archetypes named above; all token, typography,
|
||
donut and status rules kept. An out-of-range score is clamped and a missing one
|
||
draws no arc at all.
|
||
- 2026-09-24: User decision — both reports move back toward the layout of the
|
||
earlier ASSESSOR exports (KPI cards, severity donut, bar lists, filterable and
|
||
expandable finding lists) in the ASSESSOR look, light only, with a small
|
||
inline search/filter script. Supersedes the static no-JavaScript and dark
|
||
rendering decisions. The Management Overview keeps the Priority list only and
|
||
now reads posture, Priority Findings, remediation, coverage, convergence,
|
||
bundles, sources. Renderers 2.0.0 share `src/exports/report-theme.ts`.
|
||
- 2026-09-24: Readability refinement on user feedback (renderers 2.1.0): findings
|
||
read as description, result and solution; empty and duplicate source values
|
||
are omitted and raw details are collapsed; GPO comparisons roll up to one
|
||
finding per policy setting; severity and status become quiet supporting
|
||
information.
|