34 KiB
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 | ASSESSOR application look |
| Technical scope (B) | Deviations, diagnostics and score-neutral classes |
| Interaction | Static, print- and PDF-ready, no JavaScript |
| 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.
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/reporting/report-projection.ts (moved from src/domain on 2026-09-30)
(REPORT_PROJECTION_VERSION = '1.1.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
Superseding user decision 2026-09-29 (Phase 7): The Management Report is generated offline and without an LLM from the current, selected client's existing report projection. It is a factual overview, not a scanner finding list, mixed-method score or speculative risk assessment. The earlier Report A content contract below (overall-score donut, domain spine, priority findings, remediation status and source overview) is retained as historical context but does not govern the current Management export.
Current Report A shows project name, report date, the captured domain and DC count when present, counts of assessed and deviating results, a heatmap of deviations divided by assessed results for each catalog Security Domain, and a second stacked chart of passed and deviating results with the Pass Rate and underlying counts. A domain with no assessed results has no percentage or heat level. The colors and percentages describe result frequency only: they do not express severity, business impact, compromise, protection or progress.
The GPO domain chart counts assigned result rows. When the separate policy evaluation exists, its failing comparisons and affected settings are stated separately and never equated to result rows. The export names its statement limits: source observations may come from different times; affected business services, exploitation and current remediation state are not derivable from these facts. It does not extrapolate backup age or add invented risk scenarios, owners, measures or deadlines. Technical results remain in Report B. The document is standalone HTML with inline styles and no external resources.
User decision 2026-09-30 (Report Engine v0.2): Directly below the three key
figures, Report A shows a Kernaussagen block with three deterministic statements.
Each is a fixed German sentence into which only projection values are inserted:
- Gesamtbild: assessed and deviating results with their share.
- Schwerpunkt: the domain or domains with the most deviations and with the highest deviation share. Ties name every tied domain, and the sentence carries the note that share and frequency say nothing about severity or business risk.
- Aussagegrenze: not run, not applicable, failed and otherwise unassessed checks, which are neither passed nor deviating and enter no rate.
A statement without a factual basis is omitted. The statements are
language-neutral data in the projection (statements, built by
src/reporting/report-narrative.ts). The wording lives in
src/reporting/report-statement-text.ts, which both renderers share. The
Technical Report proves every statement with the same sentence and the result IDs
behind each number (Belege der Kernaussagen). Report A contains no IDs.
Historical Report A design (superseded 2026-09-29)
Implemented in src/reporting/management-overview-report.ts
(MANAGEMENT_OVERVIEW_RENDERER_VERSION = '1.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.
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. Light is the document default
because a report is printed on white; dark renders from the same semantic roles
through prefers-color-scheme.
The bundled Inter is referenced by family name 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/reporting/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.
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,DataandType codefor 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.
Report Engine boundary
Decision: 2026-09-30, explicitly approved by the user. Implementation plan: Phase 7, Report Engine als eigenstaendiger Nur-Lese-Baustein.
The Report Engine is a self-contained, read-only building block inside ASSESSOR. It produces the reports offline, without an LLM, and never changes ASSESSOR logic or data.
- Location. The projection, correlation, input assembler,
client-report-projectionand both renderers were moved unchanged tosrc/reporting/on 2026-09-30. The shared security-domain catalog, scoring and review hydration stay ASSESSOR components and are only imported, so that a report number always equals the Client Info and Work number. An architecture test enforces the boundary. - Read-only access. The engine reads through a read-only repository port and a dedicated read-only database pool. It detects a repository revision change during assembly and repeats the read instead of mixing states.
- Server rendering. Since v0.1 the server renders both files once per run and
archives them. Client Info downloads exactly the archived file through
POST /api/v1/projects/:id/report-runs. - Frozen state. Every report run is archived server-side in its own folder
and never modified afterwards. The folder holds
projection.json, both HTML files and a manifest with file hashes, engine versions, repository revision, scope and time. The archive lives outside the repository and outside synced folders (ASSESSOR_REPORT_ARCHIVE_DIR) and is deleted together with its client.projection.jsonand the manifest are internal. They are never delivered with Report A, which keeps the separate-files confidentiality boundary. - Boundaries.
- Only the shared security-domain catalog.
- Severity only per source, never summed across scanners.
- Review state only as unverified self-report, and never in Report A.
- Scenarios and cross-finding relationships only from the context engine (Phase 13E), never from report-local rules.
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, 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.
- Static output: no JavaScript, printable to PDF without layout loss.
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
criticalby 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
includewith 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-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 toundeclaredwith its own diagnostic rather than guessing. Declaring the basis insideToolProfileDefinitionis the follow-up step. - 2026-09-18: Profile obligation implemented.
ToolPriorityBasisDefinitionis 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. CISLevelis 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 orurl(). Deviation from theassessor-uishell 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-30: Report Engine boundary decided by the user. The report modules move
unchanged to
src/reporting/and access is read-only. Every run is archived immutably server-side, outside the repository and synced folders. Domain, severity, review-state and scenario boundaries are confirmed, with scenarios only from the Phase 13E context engine. Documentation only; no implementation yet. - 2026-09-30: Report modules moved unchanged to
src/reporting/, with their tests intests/reporting/.tests/reporting/reporting-boundary.test.tsenforces the importer allow-list and the absence of writing repository calls. Output and numbers are unchanged. - 2026-09-30: Report Engine v0.1 (product 2.10.0). A read-only port, a PostgreSQL reader with read-only sessions and a revision check before and after the read (repeat, otherwise refuse) ensure a consistent read. Every run is archived write-once on the server. The Client Info buttons now download the server-rendered, archived file, and the browser no longer renders reports. Report content is unchanged.
- 2026-09-30: Report Engine v0.2. The user chose the statements Gesamtbild, Schwerpunkt and Aussagegrenze, placed below the key figures, with evidence in the Technical Report and the archive. Projection 1.2.0 adds ID lists per domain and per coverage group plus the statements. The narrative module is 1.0.0, the Management renderer 2.1.0 and the Technical renderer 1.1.0, whose result index now shows the result ID.