Assessor_2.0/docs/REPORT_STRATEGY.md

713 lines
38 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.